aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Murray <timmurray@google.com>2014-04-28 13:30:20 -0700
committerTim Murray <timmurray@google.com>2014-04-28 13:30:20 -0700
commit61f99ffc0d77f1c1d5306d070b90fba0c2c05fbe (patch)
treeb2d959fe9d1c91575d77bb4470bf5162fc664fbb
parent19098dcde2b7597ad620b1d7bfe180dd69308648 (diff)
parentbf6a66cd290403bd051f6e4266c96786e666993e (diff)
downloadclang_35a-61f99ffc0d77f1c1d5306d070b90fba0c2c05fbe.tar.gz
Merge remote-tracking branch 'upstream/master' into rebase
-rw-r--r--.arcconfig2
-rw-r--r--bindings/python/clang/cindex.py69
-rw-r--r--bindings/python/tests/cindex/test_access_specifiers.py34
-rw-r--r--bindings/xml/comment-xml-schema.rng6
-rw-r--r--docs/CMakeLists.txt9
-rw-r--r--docs/ClangFormatStyleOptions.rst38
-rw-r--r--docs/LanguageExtensions.rst20
-rw-r--r--docs/Modules.rst9
-rw-r--r--docs/UsersManual.rst160
-rwxr-xr-x[-rw-r--r--]docs/tools/dump_format_style.py5
-rw-r--r--include/clang-c/CXString.h2
-rw-r--r--include/clang-c/Documentation.h554
-rw-r--r--include/clang-c/Index.h603
-rw-r--r--include/clang/AST/ASTUnresolvedSet.h3
-rw-r--r--include/clang/AST/ASTVector.h15
-rw-r--r--include/clang/AST/Comment.h28
-rw-r--r--include/clang/AST/CommentHTMLTags.td80
-rw-r--r--include/clang/AST/DataRecursiveASTVisitor.h8
-rw-r--r--include/clang/AST/Decl.h5
-rw-r--r--include/clang/AST/DeclCXX.h2
-rw-r--r--include/clang/AST/Expr.h16
-rw-r--r--include/clang/AST/ExprCXX.h3
-rw-r--r--include/clang/AST/OpenMPClause.h85
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h7
-rw-r--r--include/clang/ASTMatchers/Dynamic/Diagnostics.h3
-rw-r--r--include/clang/ASTMatchers/Dynamic/Parser.h51
-rw-r--r--include/clang/ASTMatchers/Dynamic/Registry.h7
-rw-r--r--include/clang/ASTMatchers/Dynamic/VariantValue.h7
-rw-r--r--include/clang/Analysis/Analyses/PostOrderCFGView.h8
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafetyCommon.h388
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafetyOps.def46
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafetyTIL.h1313
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafetyTraverse.h762
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafetyUtil.h292
-rw-r--r--include/clang/Analysis/CFG.h14
-rw-r--r--include/clang/Basic/Attr.td3
-rw-r--r--include/clang/Basic/AttrDocs.td8
-rw-r--r--include/clang/Basic/Builtins.def23
-rw-r--r--include/clang/Basic/BuiltinsARM.def3
-rw-r--r--include/clang/Basic/BuiltinsARM64.def2
-rw-r--r--include/clang/Basic/BuiltinsX86.def2
-rw-r--r--include/clang/Basic/Diagnostic.h33
-rw-r--r--include/clang/Basic/Diagnostic.td1
-rw-r--r--include/clang/Basic/DiagnosticCommentKinds.td4
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td5
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td6
-rw-r--r--include/clang/Basic/DiagnosticGroups.td30
-rw-r--r--include/clang/Basic/DiagnosticIDs.h3
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td28
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td43
-rw-r--r--include/clang/Basic/DiagnosticSerializationKinds.td14
-rw-r--r--include/clang/Basic/LangOptions.def2
-rw-r--r--include/clang/Basic/Module.h36
-rw-r--r--include/clang/Basic/OnDiskHashTable.h419
-rw-r--r--include/clang/Basic/OpenMPKinds.def2
-rw-r--r--include/clang/Basic/SourceManager.h19
-rw-r--r--include/clang/Basic/TargetInfo.h2
-rw-r--r--include/clang/Basic/TokenKinds.def6
-rw-r--r--include/clang/CodeGen/CGFunctionInfo.h4
-rw-r--r--include/clang/Driver/CLCompatOptions.td6
-rw-r--r--include/clang/Driver/Options.td27
-rw-r--r--include/clang/Edit/Commit.h5
-rw-r--r--include/clang/Edit/EditedSource.h9
-rw-r--r--include/clang/Format/Format.h24
-rw-r--r--include/clang/Frontend/ASTUnit.h27
-rw-r--r--include/clang/Frontend/CodeGenOptions.h8
-rw-r--r--include/clang/Frontend/CompilerInstance.h12
-rw-r--r--include/clang/Frontend/CompilerInvocation.h8
-rw-r--r--include/clang/Frontend/FrontendActions.h18
-rw-r--r--include/clang/Frontend/VerifyDiagnosticConsumer.h4
-rw-r--r--include/clang/Index/CommentToXML.h6
-rw-r--r--include/clang/Lex/HeaderSearch.h6
-rw-r--r--include/clang/Lex/MacroInfo.h8
-rw-r--r--include/clang/Lex/ModuleLoader.h36
-rw-r--r--include/clang/Lex/ModuleMap.h24
-rw-r--r--include/clang/Lex/Preprocessor.h1
-rw-r--r--include/clang/Parse/Parser.h28
-rw-r--r--include/clang/Sema/DeclSpec.h4
-rw-r--r--include/clang/Sema/Overload.h17
-rw-r--r--include/clang/Sema/Sema.h140
-rw-r--r--include/clang/Sema/TypoCorrection.h4
-rw-r--r--include/clang/Serialization/ASTBitCodes.h9
-rw-r--r--include/clang/Serialization/ASTReader.h50
-rw-r--r--include/clang/Serialization/ASTWriter.h4
-rw-r--r--include/clang/Serialization/GlobalModuleIndex.h3
-rw-r--r--include/clang/Serialization/Module.h13
-rw-r--r--include/clang/Tooling/Tooling.h32
-rw-r--r--lib/ARCMigrate/ObjCMT.cpp32
-rw-r--r--lib/AST/ASTContext.cpp26
-rw-r--r--lib/AST/ASTDiagnostic.cpp14
-rw-r--r--lib/AST/ASTDumper.cpp1
-rw-r--r--lib/AST/CommentSema.cpp33
-rw-r--r--lib/AST/Decl.cpp42
-rw-r--r--lib/AST/DeclBase.cpp17
-rw-r--r--lib/AST/DeclObjC.cpp22
-rw-r--r--lib/AST/DeclTemplate.cpp8
-rw-r--r--lib/AST/Expr.cpp39
-rw-r--r--lib/AST/ExprConstant.cpp4
-rw-r--r--lib/AST/ItaniumMangle.cpp54
-rw-r--r--lib/AST/MicrosoftMangle.cpp130
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp394
-rw-r--r--lib/AST/Stmt.cpp24
-rw-r--r--lib/AST/StmtPrinter.cpp15
-rw-r--r--lib/AST/StmtProfile.cpp4
-rw-r--r--lib/AST/VTableBuilder.cpp80
-rw-r--r--lib/ASTMatchers/Dynamic/Diagnostics.cpp4
-rw-r--r--lib/ASTMatchers/Dynamic/Parser.cpp87
-rw-r--r--lib/ASTMatchers/Dynamic/Registry.cpp13
-rw-r--r--lib/Analysis/AnalysisDeclContext.cpp6
-rw-r--r--lib/Analysis/CFG.cpp223
-rw-r--r--lib/Analysis/CMakeLists.txt1
-rw-r--r--lib/Analysis/CallGraph.cpp4
-rw-r--r--lib/Analysis/Consumed.cpp73
-rw-r--r--lib/Analysis/ReachableCode.cpp5
-rw-r--r--lib/Analysis/ThreadSafety.cpp78
-rw-r--r--lib/Analysis/ThreadSafetyCommon.cpp808
-rw-r--r--lib/Basic/DiagnosticIDs.cpp5
-rw-r--r--lib/Basic/Module.cpp26
-rw-r--r--lib/Basic/OpenMPKinds.cpp2
-rw-r--r--lib/Basic/SourceManager.cpp16
-rw-r--r--lib/Basic/Targets.cpp574
-rw-r--r--lib/CodeGen/BackendUtil.cpp4
-rw-r--r--lib/CodeGen/CGBlocks.cpp9
-rw-r--r--lib/CodeGen/CGBuiltin.cpp29
-rw-r--r--lib/CodeGen/CGCall.cpp12
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp163
-rw-r--r--lib/CodeGen/CGDebugInfo.h16
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp107
-rw-r--r--lib/CodeGen/CGExpr.cpp34
-rw-r--r--lib/CodeGen/CGExprConstant.cpp9
-rw-r--r--lib/CodeGen/CGExprScalar.cpp6
-rw-r--r--lib/CodeGen/CGObjC.cpp7
-rw-r--r--lib/CodeGen/CGRTTI.cpp3
-rw-r--r--lib/CodeGen/CGRecordLayout.h2
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp35
-rw-r--r--lib/CodeGen/CGStmt.cpp7
-rw-r--r--lib/CodeGen/CGVTables.cpp2
-rw-r--r--lib/CodeGen/CMakeLists.txt1
-rw-r--r--lib/CodeGen/CodeGenAction.cpp49
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp30
-rw-r--r--lib/CodeGen/CodeGenFunction.h8
-rw-r--r--lib/CodeGen/CodeGenModule.cpp157
-rw-r--r--lib/CodeGen/CodeGenModule.h19
-rw-r--r--lib/CodeGen/CodeGenPGO.cpp567
-rw-r--r--lib/CodeGen/CodeGenPGO.h27
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp80
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp27
-rw-r--r--lib/CodeGen/TargetInfo.cpp135
-rw-r--r--lib/Driver/Driver.cpp16
-rw-r--r--lib/Driver/Job.cpp3
-rw-r--r--lib/Driver/ToolChain.cpp13
-rw-r--r--lib/Driver/ToolChains.cpp13
-rw-r--r--lib/Driver/Tools.cpp94
-rw-r--r--lib/Driver/WindowsToolChain.cpp36
-rw-r--r--lib/Edit/Commit.cpp12
-rw-r--r--lib/Format/BreakableToken.cpp12
-rw-r--r--lib/Format/BreakableToken.h2
-rw-r--r--lib/Format/ContinuationIndenter.cpp70
-rw-r--r--lib/Format/ContinuationIndenter.h22
-rw-r--r--lib/Format/Format.cpp137
-rw-r--r--lib/Format/FormatToken.cpp5
-rw-r--r--lib/Format/FormatToken.h25
-rw-r--r--lib/Format/TokenAnnotator.cpp83
-rw-r--r--lib/Format/UnwrappedLineParser.cpp117
-rw-r--r--lib/Format/UnwrappedLineParser.h12
-rw-r--r--lib/Format/WhitespaceManager.cpp149
-rw-r--r--lib/Format/WhitespaceManager.h26
-rw-r--r--lib/Frontend/ASTUnit.cpp71
-rw-r--r--lib/Frontend/CacheTokens.cpp26
-rw-r--r--lib/Frontend/CompilerInstance.cpp225
-rw-r--r--lib/Frontend/CompilerInvocation.cpp47
-rw-r--r--lib/Frontend/FrontendAction.cpp60
-rw-r--r--lib/Frontend/FrontendActions.cpp24
-rw-r--r--lib/Frontend/InitPreprocessor.cpp4
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp6
-rw-r--r--lib/Frontend/VerifyDiagnosticConsumer.cpp14
-rw-r--r--lib/Headers/CMakeLists.txt2
-rw-r--r--lib/Headers/Intrin.h35
-rw-r--r--lib/Headers/Makefile8
-rw-r--r--lib/Headers/ia32intrin.h10
-rw-r--r--lib/Headers/module.modulemap (renamed from lib/Headers/module.map)0
-rw-r--r--lib/Index/CommentToXML.cpp58
-rw-r--r--lib/Index/SimpleFormatContext.h2
-rw-r--r--lib/Lex/HeaderSearch.cpp35
-rw-r--r--lib/Lex/Lexer.cpp33
-rw-r--r--lib/Lex/LiteralSupport.cpp6
-rw-r--r--lib/Lex/MacroInfo.cpp3
-rw-r--r--lib/Lex/ModuleMap.cpp266
-rw-r--r--lib/Lex/PPLexerChange.cpp4
-rw-r--r--lib/Lex/PPMacroExpansion.cpp6
-rw-r--r--lib/Lex/PTHLexer.cpp25
-rw-r--r--lib/Parse/ParseDecl.cpp21
-rw-r--r--lib/Parse/ParseDeclCXX.cpp61
-rw-r--r--lib/Parse/ParseExpr.cpp1
-rw-r--r--lib/Parse/ParseExprCXX.cpp49
-rw-r--r--lib/Parse/ParseInit.cpp58
-rw-r--r--lib/Parse/ParseOpenMP.cpp41
-rw-r--r--lib/Parse/ParsePragma.cpp197
-rw-r--r--lib/Parse/ParseStmt.cpp28
-rw-r--r--lib/Parse/ParseTemplate.cpp1
-rw-r--r--lib/Parse/ParseTentative.cpp1
-rw-r--r--lib/Parse/Parser.cpp3
-rw-r--r--lib/Rewrite/Core/RewriteRope.cpp5
-rw-r--r--lib/Rewrite/Frontend/RewriteModernObjC.cpp2
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp54
-rw-r--r--lib/Sema/DelayedDiagnostic.cpp5
-rw-r--r--lib/Sema/Sema.cpp23
-rw-r--r--lib/Sema/SemaAttr.cpp106
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp83
-rw-r--r--lib/Sema/SemaCast.cpp14
-rw-r--r--lib/Sema/SemaChecking.cpp518
-rw-r--r--lib/Sema/SemaCodeComplete.cpp9
-rw-r--r--lib/Sema/SemaDecl.cpp194
-rw-r--r--lib/Sema/SemaDeclAttr.cpp56
-rw-r--r--lib/Sema/SemaDeclCXX.cpp60
-rw-r--r--lib/Sema/SemaDeclObjC.cpp7
-rw-r--r--lib/Sema/SemaExpr.cpp51
-rw-r--r--lib/Sema/SemaExprCXX.cpp10
-rw-r--r--lib/Sema/SemaExprMember.cpp8
-rw-r--r--lib/Sema/SemaExprObjC.cpp35
-rw-r--r--lib/Sema/SemaInit.cpp8
-rw-r--r--lib/Sema/SemaLambda.cpp3
-rw-r--r--lib/Sema/SemaLookup.cpp131
-rw-r--r--lib/Sema/SemaObjCProperty.cpp10
-rw-r--r--lib/Sema/SemaOpenMP.cpp145
-rw-r--r--lib/Sema/SemaOverload.cpp103
-rw-r--r--lib/Sema/SemaPseudoObject.cpp6
-rw-r--r--lib/Sema/SemaStmt.cpp3
-rw-r--r--lib/Sema/SemaTemplate.cpp174
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp40
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp2
-rw-r--r--lib/Sema/TreeTransform.h51
-rw-r--r--lib/Serialization/ASTCommon.h1
-rw-r--r--lib/Serialization/ASTReader.cpp437
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp380
-rw-r--r--lib/Serialization/ASTReaderInternals.h25
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp15
-rw-r--r--lib/Serialization/ASTWriter.cpp212
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp7
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp25
-rw-r--r--lib/Serialization/GlobalModuleIndex.cpp53
-rw-r--r--lib/Serialization/ModuleManager.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp114
-rw-r--r--lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp33
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/Checkers/SelectorExtras.h68
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp12
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp12
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp4
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp12
-rw-r--r--lib/Tooling/Tooling.cpp26
-rw-r--r--test/Analysis/NSContainers.m8
-rw-r--r--test/Analysis/dtor.cpp11
-rw-r--r--test/CMakeLists.txt2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp8
-rw-r--r--test/CXX/drs/dr2xx.cpp2
-rw-r--r--test/CXX/drs/dr5xx.cpp181
-rw-r--r--test/CXX/expr/expr.const/p2-0x.cpp4
-rw-r--r--test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp28
-rw-r--r--test/CodeGen/aarch64-inline-asm.c1
-rw-r--r--test/CodeGen/aarch64-neon-2velem.c2
-rw-r--r--test/CodeGen/aarch64-neon-3v.c2
-rw-r--r--test/CodeGen/aarch64-neon-across.c2
-rw-r--r--test/CodeGen/aarch64-neon-extract.c2
-rw-r--r--test/CodeGen/aarch64-neon-fcvt-intrinsics.c2
-rw-r--r--test/CodeGen/aarch64-neon-fma.c2
-rw-r--r--test/CodeGen/aarch64-neon-intrinsics.c110
-rw-r--r--test/CodeGen/aarch64-neon-ld-sideeffect.c2
-rw-r--r--test/CodeGen/aarch64-neon-ldst-one.c20
-rw-r--r--test/CodeGen/aarch64-neon-misc.c2
-rw-r--r--test/CodeGen/aarch64-neon-perm.c2
-rw-r--r--test/CodeGen/aarch64-neon-scalar-copy.c2
-rw-r--r--test/CodeGen/aarch64-neon-scalar-x-indexed-elem.c2
-rw-r--r--test/CodeGen/aarch64-neon-shifts.c2
-rw-r--r--test/CodeGen/aarch64-neon-tbl.c2
-rw-r--r--test/CodeGen/aarch64-neon-vcombine.c2
-rw-r--r--test/CodeGen/aarch64-neon-vget-hilo.c2
-rw-r--r--test/CodeGen/aarch64-poly128.c2
-rw-r--r--test/CodeGen/aarch64-poly64.c10
-rw-r--r--test/CodeGen/aarch64-type-sizes.c1
-rw-r--r--test/CodeGen/aarch64-varargs.c1
-rw-r--r--test/CodeGen/arm-aapcs-vfp.c2
-rw-r--r--test/CodeGen/arm-homogenous.c4
-rw-r--r--test/CodeGen/arm64-aapcs-arguments.c42
-rw-r--r--test/CodeGen/arm64-arguments.c8
-rw-r--r--test/CodeGen/arm64-lanes.c2
-rw-r--r--test/CodeGen/arm64-scalar-test.c14
-rw-r--r--test/CodeGen/arm64-vrnd.c2
-rw-r--r--test/CodeGen/arm64-vrsqrt.c2
-rw-r--r--test/CodeGen/arm64_crypto.c2
-rw-r--r--test/CodeGen/arm64_neon_high_half.c2
-rw-r--r--test/CodeGen/arm64_vCMP.c2
-rw-r--r--test/CodeGen/arm64_vLdStNum_lane.c2
-rw-r--r--test/CodeGen/arm64_vMaxMin.c4
-rw-r--r--test/CodeGen/arm64_vadd.c2
-rw-r--r--test/CodeGen/arm64_vca.c2
-rw-r--r--test/CodeGen/arm64_vcopy.c2
-rw-r--r--test/CodeGen/arm64_vcreate.c2
-rw-r--r--test/CodeGen/arm64_vcvtfp.c2
-rw-r--r--test/CodeGen/arm64_vdup.c2
-rw-r--r--test/CodeGen/arm64_vdupq_n_f64.c4
-rw-r--r--test/CodeGen/arm64_vecCmpBr.c2
-rw-r--r--test/CodeGen/arm64_vext.c2
-rw-r--r--test/CodeGen/arm64_vfma.c2
-rw-r--r--test/CodeGen/arm64_vget.c2
-rw-r--r--test/CodeGen/arm64_vneg.c2
-rw-r--r--test/CodeGen/arm64_vqmov.c2
-rw-r--r--test/CodeGen/arm64_vrecps.c2
-rw-r--r--test/CodeGen/arm64_vset_lane.c2
-rw-r--r--test/CodeGen/arm64_vshift.c2
-rw-r--r--test/CodeGen/arm64_vsli.c4
-rw-r--r--test/CodeGen/arm64_vsri.c4
-rw-r--r--test/CodeGen/arm64_vtst.c2
-rw-r--r--test/CodeGen/avx2-builtins.c8
-rw-r--r--test/CodeGen/builtins-arm-microsoft.c10
-rw-r--r--test/CodeGen/builtins-arm.c2
-rw-r--r--test/CodeGen/builtins-x86.c3
-rw-r--r--test/CodeGen/disable-tail-calls.c16
-rw-r--r--test/CodeGen/function-attributes.c11
-rw-r--r--test/CodeGen/function-sections.c28
-rw-r--r--test/CodeGen/mips-type-sizes-int128.c13
-rw-r--r--test/CodeGen/mips-type-sizes.c92
-rw-r--r--test/CodeGen/mmx-inline-asm-error.c6
-rw-r--r--test/CodeGen/neon-crypto.c33
-rw-r--r--test/CodeGen/predefined-expr.c1
-rw-r--r--test/CodeGen/sections.c75
-rw-r--r--test/CodeGen/split-stacks.c18
-rw-r--r--test/CodeGen/varargs.c10
-rw-r--r--test/CodeGenCUDA/launch-bounds.cu30
-rw-r--r--test/CodeGenCXX/aarch64-cxxabi.cpp4
-rw-r--r--test/CodeGenCXX/aarch64-neon.cpp2
-rw-r--r--test/CodeGenCXX/arm.cpp12
-rw-r--r--test/CodeGenCXX/class-layout.cpp9
-rw-r--r--test/CodeGenCXX/debug-info-alias.cpp28
-rw-r--r--test/CodeGenCXX/debug-info-anon-union-vars.cpp28
-rw-r--r--test/CodeGenCXX/debug-info-global.cpp19
-rw-r--r--test/CodeGenCXX/debug-info-namespace.cpp6
-rw-r--r--test/CodeGenCXX/debug-info-template-partial-specialization.cpp31
-rw-r--r--test/CodeGenCXX/debug-info.cpp16
-rw-r--r--test/CodeGenCXX/enable_if.cpp20
-rw-r--r--test/CodeGenCXX/explicit-instantiation.cpp76
-rw-r--r--test/CodeGenCXX/extern-c.cpp7
-rw-r--r--test/CodeGenCXX/funcsig.cpp29
-rw-r--r--test/CodeGenCXX/globalinit-loc.cpp23
-rw-r--r--test/CodeGenCXX/mangle-ms-cxx11.cpp11
-rw-r--r--test/CodeGenCXX/mangle-ms-templates-memptrs-2.cpp26
-rw-r--r--test/CodeGenCXX/mangle-neon-vectors.cpp4
-rw-r--r--test/CodeGenCXX/mangle.cpp40
-rw-r--r--test/CodeGenCXX/microsoft-abi-nontrivial-memptr-thunks.cpp11
-rw-r--r--test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp18
-rw-r--r--test/CodeGenCXX/microsoft-abi-static-initializers.cpp13
-rw-r--r--test/CodeGenCXX/microsoft-abi-vbtables.cpp10
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-no-thunks.cpp302
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-pure-virtual.cpp35
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-return-adjustment.cpp297
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-this-adjustment.cpp140
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-vdtors.cpp94
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp609
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp182
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp67
-rw-r--r--test/CodeGenCXX/mips-size_t-ptrdiff_t.cpp49
-rw-r--r--test/CodeGenCXX/poly-unsigned.cpp4
-rw-r--r--test/CodeGenCXX/pragma-init_seg.cpp16
-rw-r--r--test/CodeGenCXX/rtti-fundamental.cpp5
-rw-r--r--test/CodeGenObjC/encode-test-6.m11
-rw-r--r--test/CodeGenOpenCL/address-space-constant-initializers.cl20
-rw-r--r--test/CodeGenOpenCL/kernel-arg-info.cl8
-rw-r--r--test/Driver/Inputs/basic_android_tree/aarch64-linux-android/bin/.keep0
-rw-r--r--test/Driver/Inputs/basic_android_tree/aarch64-linux-android/include/c++/4.8/.keep0
-rw-r--r--test/Driver/Inputs/basic_android_tree/aarch64-linux-android/lib/.keep0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtbegin.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtbeginS.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtbeginT.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtend.o0
-rw-r--r--test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtendS.o0
-rw-r--r--test/Driver/Inputs/basic_netbsd_tree/usr/lib/64/crti.o0
-rw-r--r--test/Driver/Inputs/basic_netbsd_tree/usr/lib/eabi/crti.o0
-rw-r--r--test/Driver/Inputs/basic_netbsd_tree/usr/lib/i386/crti.o0
-rw-r--r--test/Driver/Inputs/basic_netbsd_tree/usr/lib/o32/crti.o0
-rw-r--r--test/Driver/Inputs/basic_netbsd_tree/usr/lib/oabi/crti.o0
-rw-r--r--test/Driver/Inputs/basic_netbsd_tree/usr/lib/sparc/crti.o0
-rw-r--r--test/Driver/Inputs/file.ll0
-rw-r--r--test/Driver/aarch64-cpus.c44
-rw-r--r--test/Driver/aarch64-features.c1
-rw-r--r--test/Driver/aarch64-mfpu.c11
-rw-r--r--test/Driver/aarch64-mgeneral_regs_only.c2
-rw-r--r--test/Driver/android-standalone.cpp15
-rw-r--r--test/Driver/arm-cortex-cpus.c94
-rw-r--r--test/Driver/arm64-as.s5
-rw-r--r--test/Driver/cl-fallback.c11
-rw-r--r--test/Driver/cl-link.c4
-rw-r--r--test/Driver/cl-options.c20
-rw-r--r--test/Driver/clang_f_opts.c11
-rw-r--r--test/Driver/constructors.c9
-rw-r--r--test/Driver/crash-report.c2
-rw-r--r--test/Driver/linux-ld.c23
-rw-r--r--test/Driver/netbsd.c70
-rw-r--r--test/Driver/netbsd.cpp46
-rw-r--r--test/Driver/windows-arm-minimal-arch.c5
-rw-r--r--test/FixIt/fixit-cxx0x.cpp3
-rw-r--r--test/FixIt/fixit.cpp4
-rw-r--r--test/Frontend/optimization-remark.c19
-rw-r--r--test/Headers/cocoa.m (renamed from test/SemaObjC/cocoa.m)2
-rw-r--r--test/Headers/cxx11.cpp4
-rw-r--r--test/Index/Inputs/CommentXML/valid-function-02.xml11
-rw-r--r--test/Index/Inputs/base_module_needs_vfs.h1
-rw-r--r--test/Index/Inputs/module.map6
-rw-r--r--test/Index/Inputs/module_needs_vfs.h4
-rw-r--r--test/Index/Inputs/vfsoverlay.yaml18
-rw-r--r--test/Index/annotate-module.m2
-rw-r--r--test/Index/comment-cplus-template-decls.cpp15
-rw-r--r--test/Index/comment-to-html-xml-conversion.cpp44
-rw-r--r--test/Index/complete-macros.c23
-rw-r--r--test/Index/complete-macros.h6
-rw-r--r--test/Index/index-module-with-vfs.m26
-rw-r--r--test/Index/load-classes.cpp30
-rw-r--r--test/Index/pch-depending-on-deleted-module.c6
-rw-r--r--test/Index/print-type.c16
-rw-r--r--test/Index/print-type.cpp14
-rw-r--r--test/Index/print-type.m2
-rw-r--r--test/Index/recursive-cxx-member-calls.cpp18
-rw-r--r--test/Layout/ms-x86-alias-avoidance-padding.cpp291
-rw-r--r--test/Layout/ms-x86-bitfields-vbases.cpp40
-rw-r--r--test/Layout/ms-x86-lazy-empty-nonvirtual-base.cpp43
-rw-r--r--test/Layout/ms-x86-pack-and-align.cpp167
-rw-r--r--test/Layout/ms-x86-vtordisp.cpp95
-rw-r--r--test/Lexer/cxx1y_digit_separators.cpp14
-rw-r--r--test/Lexer/has_feature_exceptions.cpp8
-rw-r--r--test/Lexer/keywords_test.c29
-rw-r--r--test/Misc/warning-flags.c3
-rw-r--r--test/Modules/Inputs/cxx-decls-imported.h15
-rw-r--r--test/Modules/Inputs/cxx-irgen-left.h4
-rw-r--r--test/Modules/Inputs/cxx-irgen-top.h6
-rw-r--r--test/Modules/Inputs/exclude-header/module.map3
-rw-r--r--test/Modules/Inputs/exclude-header/x/a.h1
-rw-r--r--test/Modules/Inputs/exclude-header/x/bad.h1
-rw-r--r--test/Modules/Inputs/exclude-header/y/b.h1
-rw-r--r--test/Modules/Inputs/modules-with-same-name/DependsOnA/DependsOnA.h1
-rw-r--r--test/Modules/Inputs/modules-with-same-name/DependsOnA/module.modulemap4
-rw-r--r--test/Modules/Inputs/modules-with-same-name/path1/A/a.h1
-rw-r--r--test/Modules/Inputs/modules-with-same-name/path1/A/module.modulemap5
-rw-r--r--test/Modules/Inputs/modules-with-same-name/path2/A/a.h1
-rw-r--r--test/Modules/Inputs/modules-with-same-name/path2/A/module.modulemap5
-rw-r--r--test/Modules/Inputs/submodules/module.map15
-rw-r--r--test/Modules/Inputs/templates-left.h18
-rw-r--r--test/Modules/Inputs/templates-right.h8
-rw-r--r--test/Modules/Inputs/templates-top.h6
-rw-r--r--test/Modules/Inputs/undefined-type-fixit/module.map9
-rw-r--r--test/Modules/Inputs/undefined-type-fixit/public1.h6
-rw-r--r--test/Modules/Inputs/undefined-type-fixit/public2.h6
-rw-r--r--test/Modules/Inputs/undefined-type-fixit/public2sub.h6
-rw-r--r--test/Modules/cxx-decls.cpp3
-rw-r--r--test/Modules/cxx-irgen.cpp10
-rw-r--r--test/Modules/cxx-templates.cpp12
-rw-r--r--test/Modules/dependency-gen-pch.m2
-rw-r--r--test/Modules/diamond-pch.c2
-rw-r--r--test/Modules/exclude-header.c11
-rw-r--r--test/Modules/macro-undef-through-pch.m4
-rw-r--r--test/Modules/missing-header.m13
-rw-r--r--test/Modules/missing-submodule.m7
-rw-r--r--test/Modules/module_file_info.m3
-rw-r--r--test/Modules/modules-with-same-name.m35
-rw-r--r--test/Modules/prune.m20
-rw-r--r--test/Modules/redecls/main.m2
-rw-r--r--test/Modules/resolution-change.m24
-rw-r--r--test/Modules/strict-decluse.cpp9
-rw-r--r--test/Modules/submodules.cpp5
-rw-r--r--test/Modules/system_version.m6
-rw-r--r--test/Modules/templates.mm17
-rw-r--r--test/Modules/undefined-type-fixit1.cpp12
-rw-r--r--test/Modules/validate-system-headers.m18
-rw-r--r--test/OpenMP/simd_ast_print.cpp29
-rw-r--r--test/OpenMP/simd_linear_messages.cpp205
-rw-r--r--test/OpenMP/simd_misc_messages.c74
-rw-r--r--test/PCH/modified-module-dependency.m4
-rw-r--r--test/PCH/single-token-macro.c5
-rw-r--r--test/Parser/MicrosoftExtensions.c6
-rw-r--r--test/Parser/altivec.c4
-rw-r--r--test/Parser/arm-windows-calling-convention-handling.c10
-rw-r--r--test/Parser/attributes.c3
-rw-r--r--test/Parser/check-objc2-syntax-1.m2
-rw-r--r--test/Parser/cxx-altivec.cpp4
-rw-r--r--test/Parser/cxx0x-attributes.cpp7
-rw-r--r--test/Parser/cxx0x-lambda-expressions.cpp10
-rw-r--r--test/Parser/opencl-astype.cl2
-rw-r--r--test/Parser/recovery.cpp67
-rw-r--r--test/Preprocessor/aarch64-target-features.c1
-rw-r--r--test/Preprocessor/init.c2
-rw-r--r--test/Preprocessor/macro-multiline.c7
-rw-r--r--test/Preprocessor/macro-multiline.c.ignoreme8
-rw-r--r--test/Preprocessor/macro_redefined.c19
-rw-r--r--test/Preprocessor/woa-defaults.c33
-rw-r--r--test/Profile/Inputs/c-attributes.proftext (renamed from test/Profile/Inputs/c-attributes.profdata)2
-rw-r--r--test/Profile/Inputs/c-captured.proftext25
-rw-r--r--test/Profile/Inputs/c-counter-overflows.proftext (renamed from test/Profile/Inputs/c-counter-overflows.profdata)2
-rw-r--r--test/Profile/Inputs/c-general.proftext (renamed from test/Profile/Inputs/c-general.profdata)29
-rw-r--r--test/Profile/Inputs/c-outdated-data.proftext (renamed from test/Profile/Inputs/c-outdated-data.profdata)4
-rw-r--r--test/Profile/Inputs/c-unprofiled-blocks.proftext32
-rw-r--r--test/Profile/Inputs/cxx-class.proftext (renamed from test/Profile/Inputs/cxx-class.profdata)14
-rw-r--r--test/Profile/Inputs/cxx-lambda.proftext20
-rw-r--r--test/Profile/Inputs/cxx-templates.proftext17
-rw-r--r--test/Profile/Inputs/cxx-throws.proftext (renamed from test/Profile/Inputs/cxx-throws.profdata)4
-rw-r--r--test/Profile/Inputs/objc-general.proftext (renamed from test/Profile/Inputs/objc-general.profdata)6
-rw-r--r--test/Profile/c-attributes.c3
-rw-r--r--test/Profile/c-captured.c59
-rw-r--r--test/Profile/c-counter-overflows.c3
-rw-r--r--test/Profile/c-general.c26
-rw-r--r--test/Profile/c-linkage-available_externally.c2
-rw-r--r--test/Profile/c-linkage.c8
-rw-r--r--test/Profile/c-outdated-data.c14
-rw-r--r--test/Profile/c-unprofiled-blocks.c69
-rw-r--r--test/Profile/cxx-class.cpp3
-rw-r--r--test/Profile/cxx-implicit.cpp17
-rw-r--r--test/Profile/cxx-lambda.cpp58
-rw-r--r--test/Profile/cxx-linkage.cpp8
-rw-r--r--test/Profile/cxx-templates.cpp42
-rw-r--r--test/Profile/cxx-throws.cpp5
-rw-r--r--test/Profile/objc-general.m4
-rw-r--r--test/Sema/aarch64-neon-ranges.c1
-rw-r--r--test/Sema/aarch64-neon-vector-types.c2
-rw-r--r--test/Sema/arm64-inline-asm.c3
-rw-r--r--test/Sema/arm64-neon-args.c2
-rw-r--r--test/Sema/attr-aligned.c11
-rw-r--r--test/Sema/attr-capabilities.c11
-rw-r--r--test/Sema/bool-compare.c162
-rw-r--r--test/Sema/builtin-clear_cache.c1
-rw-r--r--test/Sema/builtins-aarch64.c2
-rw-r--r--test/Sema/builtins-gnu-mode.c8
-rw-r--r--test/Sema/conversion.c12
-rw-r--r--test/Sema/ext_vector_casts.c24
-rw-r--r--test/Sema/inline-asm-validate.c3
-rw-r--r--test/Sema/ms_bitfield_layout.c26
-rw-r--r--test/Sema/pragma-section.c42
-rw-r--r--test/Sema/return-noreturn.c12
-rw-r--r--test/Sema/transparent-union.c2
-rw-r--r--test/Sema/typedef-retain.c4
-rw-r--r--test/Sema/types.c8
-rw-r--r--test/Sema/vector-assign.c40
-rw-r--r--test/Sema/vector-cast.c16
-rw-r--r--test/Sema/vector-init.c2
-rw-r--r--test/Sema/vector-ops.c6
-rw-r--r--test/Sema/warn-documentation.cpp13
-rw-r--r--test/Sema/warn-overlap.c64
-rw-r--r--test/SemaCUDA/lit.local.cfg4
-rw-r--r--test/SemaCXX/addr-of-overloaded-function-casting.cpp13
-rw-r--r--test/SemaCXX/bool-compare.cpp207
-rw-r--r--test/SemaCXX/cxx1y-deduced-return-type.cpp7
-rw-r--r--test/SemaCXX/cxx98-compat.cpp36
-rw-r--r--test/SemaCXX/decl-microsoft-call-conv.cpp2
-rw-r--r--test/SemaCXX/decltype.cpp21
-rw-r--r--test/SemaCXX/expressions.cpp10
-rw-r--r--test/SemaCXX/funcdname.cpp32
-rw-r--r--test/SemaCXX/nested-name-spec.cpp5
-rw-r--r--test/SemaCXX/type-traits.cpp5
-rw-r--r--test/SemaCXX/typo-correction-pt2.cpp22
-rw-r--r--test/SemaCXX/using-decl-1.cpp34
-rw-r--r--test/SemaCXX/vector-casts.cpp22
-rw-r--r--test/SemaCXX/vector.cpp10
-rw-r--r--test/SemaCXX/warn-absolute-value-header.cpp64
-rw-r--r--test/SemaCXX/warn-absolute-value.cpp823
-rw-r--r--test/SemaCXX/warn-absolute-value2.cpp13
-rw-r--r--test/SemaCXX/warn-float-conversion.cpp38
-rw-r--r--test/SemaCXX/warn-unreachable.cpp82
-rw-r--r--test/SemaCXX/warn-unused-variables.cpp11
-rw-r--r--test/SemaCXX/writable-strings-deprecated.cpp13
-rw-r--r--test/SemaObjC/attr-designated-init.m133
-rw-r--r--test/SemaObjC/class-property-access.m43
-rw-r--r--test/SemaObjC/encode-typeof-test.m26
-rw-r--r--test/SemaObjC/objcbridge-attribute-arc.m32
-rw-r--r--test/SemaObjC/objcbridge-attribute.m26
-rw-r--r--test/SemaObjCXX/lit.local.cfg4
-rw-r--r--test/SemaObjCXX/objcbridge-attribute-arc.mm32
-rw-r--r--test/SemaObjCXX/objcbridge-attribute.mm26
-rw-r--r--test/SemaOpenCL/array-parameters.cl6
-rw-r--r--test/SemaOpenCL/invalid-kernel.cl2
-rw-r--r--test/SemaOpenCL/lit.local.cfg4
-rw-r--r--test/SemaOpenCL/vector_conv_invalid.cl6
-rw-r--r--test/SemaTemplate/explicit-specialization-member.cpp18
-rw-r--r--test/VFS/Inputs/Foo.framework/Headers/Foo.h0
-rw-r--r--test/VFS/Inputs/Foo.framework/Modules/module.modulemap3
-rw-r--r--test/VFS/Inputs/Foo.h0
-rw-r--r--test/VFS/Inputs/actual_module2.map5
-rw-r--r--test/VFS/Inputs/vfsoverlay.yaml3
-rw-r--r--test/VFS/Inputs/vfsoverlay2.yaml12
-rw-r--r--test/VFS/module-import.m17
-rw-r--r--test/VFS/umbrella-mismatch.m8
-rw-r--r--tools/c-arcmt-test/Makefile5
-rw-r--r--tools/c-index-test/c-index-test.c31
-rw-r--r--tools/clang-check/ClangCheck.cpp4
-rw-r--r--tools/clang-format/clang-format.py7
-rwxr-xr-xtools/clang-format/git-clang-format3
-rw-r--r--tools/diagtool/DiagnosticNames.cpp4
-rw-r--r--tools/driver/CMakeLists.txt1
-rw-r--r--tools/driver/Makefile2
-rw-r--r--tools/driver/cc1as_main.cpp6
-rw-r--r--tools/libclang/BuildSystem.cpp8
-rw-r--r--tools/libclang/CIndex.cpp33
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp31
-rw-r--r--tools/libclang/CIndexDiagnostic.cpp1
-rw-r--r--tools/libclang/CXComment.cpp14
-rw-r--r--tools/libclang/CXComment.h1
-rw-r--r--tools/libclang/CXLoadedDiagnostic.cpp3
-rw-r--r--tools/libclang/CXStoredDiagnostic.cpp3
-rw-r--r--tools/libclang/Indexing.cpp5
-rw-r--r--tools/libclang/libclang.exports1
-rwxr-xr-xtools/scan-build/set-xcode-analyzer2
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h10
-rw-r--r--unittests/ASTMatchers/Dynamic/ParserTest.cpp31
-rw-r--r--unittests/ASTMatchers/Dynamic/RegistryTest.cpp16
-rw-r--r--unittests/ASTMatchers/Dynamic/VariantValueTest.cpp25
-rw-r--r--unittests/Basic/SourceManagerTest.cpp21
-rw-r--r--unittests/Format/FormatTest.cpp353
-rw-r--r--unittests/Format/FormatTestJS.cpp4
-rw-r--r--unittests/Format/FormatTestProto.cpp21
-rw-r--r--unittests/Lex/CMakeLists.txt1
-rw-r--r--unittests/Lex/LexerTest.cpp21
-rw-r--r--unittests/Lex/Makefile4
-rw-r--r--unittests/Lex/PPCallbacksTest.cpp21
-rw-r--r--unittests/Lex/PPConditionalDirectiveRecordTest.cpp21
-rw-r--r--unittests/Tooling/RefactoringTest.cpp4
-rw-r--r--unittests/Tooling/RewriterTestContext.h6
-rw-r--r--unittests/Tooling/ToolingTest.cpp25
-rw-r--r--unittests/libclang/LibclangTest.cpp37
-rw-r--r--utils/TableGen/ClangCommentHTMLTagsEmitter.cpp41
-rw-r--r--www/analyzer/open_projects.html23
-rw-r--r--www/analyzer/potential_checkers.html28
-rw-r--r--www/comparison.html11
-rw-r--r--www/cxx_dr_status.html42
-rw-r--r--www/features.html61
-rw-r--r--www/get_started.html5
-rw-r--r--www/related.html2
635 files changed, 19305 insertions, 5851 deletions
diff --git a/.arcconfig b/.arcconfig
index 7f45342a43..7540b46523 100644
--- a/.arcconfig
+++ b/.arcconfig
@@ -1,4 +1,4 @@
{
"project_id" : "clang",
- "conduit_uri" : "http://llvm-reviews.chandlerc.com/"
+ "conduit_uri" : "http://reviews.llvm.org/"
}
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
index 5078825f14..21c3f9a8f3 100644
--- a/bindings/python/clang/cindex.py
+++ b/bindings/python/clang/cindex.py
@@ -361,13 +361,13 @@ class Diagnostic(object):
@property
def category_number(self):
- """The category number for this diagnostic."""
+ """The category number for this diagnostic or 0 if unavailable."""
return conf.lib.clang_getDiagnosticCategory(self)
@property
def category_name(self):
"""The string name of the category for this diagnostic."""
- return conf.lib.clang_getDiagnosticCategoryName(self.category_number)
+ return conf.lib.clang_getDiagnosticCategoryText(self)
@property
def option(self):
@@ -1205,6 +1205,17 @@ class Cursor(Structure):
return self._extent
@property
+ def access_specifier(self):
+ """
+ Retrieves the access specifier (if any) of the entity pointed at by the
+ cursor.
+ """
+ if not hasattr(self, '_access_specifier'):
+ self._access_specifier = conf.lib.clang_getCXXAccessSpecifier(self)
+
+ return AccessSpecifier.from_id(self._access_specifier)
+
+ @property
def type(self):
"""
Retrieve the Type (if any) of the entity pointed at by the cursor.
@@ -1426,6 +1437,54 @@ class Cursor(Structure):
res._tu = args[0]._tu
return res
+### C++ access specifiers ###
+
+class AccessSpecifier(object):
+ """
+ Describes the access of a C++ class member
+ """
+
+ # The unique kind objects, index by id.
+ _kinds = []
+ _name_map = None
+
+ def __init__(self, value):
+ if value >= len(AccessSpecifier._kinds):
+ AccessSpecifier._kinds += [None] * (value - len(AccessSpecifier._kinds) + 1)
+ if AccessSpecifier._kinds[value] is not None:
+ raise ValueError,'AccessSpecifier already loaded'
+ self.value = value
+ AccessSpecifier._kinds[value] = self
+ AccessSpecifier._name_map = None
+
+ def from_param(self):
+ return self.value
+
+ @property
+ def name(self):
+ """Get the enumeration name of this access specifier."""
+ if self._name_map is None:
+ self._name_map = {}
+ for key,value in AccessSpecifier.__dict__.items():
+ if isinstance(value,AccessSpecifier):
+ self._name_map[value] = key
+ return self._name_map[self]
+
+ @staticmethod
+ def from_id(id):
+ if id >= len(AccessSpecifier._kinds) or not AccessSpecifier._kinds[id]:
+ raise ValueError,'Unknown access specifier %d' % id
+ return AccessSpecifier._kinds[id]
+
+ def __repr__(self):
+ return 'AccessSpecifier.%s' % (self.name,)
+
+AccessSpecifier.INVALID = AccessSpecifier(0)
+AccessSpecifier.PUBLIC = AccessSpecifier(1)
+AccessSpecifier.PROTECTED = AccessSpecifier(2)
+AccessSpecifier.PRIVATE = AccessSpecifier(3)
+AccessSpecifier.NONE = AccessSpecifier(4)
+
### Type Kinds ###
class TypeKind(object):
@@ -1934,7 +1993,7 @@ class CompletionString(ClangObject):
return "<Availability: %s>" % self
def __len__(self):
- self.num_chunks
+ return self.num_chunks
@CachedProperty
def num_chunks(self):
@@ -2922,8 +2981,8 @@ functionList = [
[Diagnostic],
c_uint),
- ("clang_getDiagnosticCategoryName",
- [c_uint],
+ ("clang_getDiagnosticCategoryText",
+ [Diagnostic],
_CXString,
_CXString.from_result),
diff --git a/bindings/python/tests/cindex/test_access_specifiers.py b/bindings/python/tests/cindex/test_access_specifiers.py
new file mode 100644
index 0000000000..cfa04dc865
--- /dev/null
+++ b/bindings/python/tests/cindex/test_access_specifiers.py
@@ -0,0 +1,34 @@
+
+from clang.cindex import AccessSpecifier
+from clang.cindex import Cursor
+from clang.cindex import TranslationUnit
+
+from .util import get_cursor
+from .util import get_tu
+
+def test_access_specifiers():
+ """Ensure that C++ access specifiers are available on cursors"""
+
+ tu = get_tu("""
+class test_class {
+public:
+ void public_member_function();
+protected:
+ void protected_member_function();
+private:
+ void private_member_function();
+};
+""", lang = 'cpp')
+
+ test_class = get_cursor(tu, "test_class")
+ assert test_class.access_specifier == AccessSpecifier.INVALID;
+
+ public = get_cursor(tu.cursor, "public_member_function")
+ assert public.access_specifier == AccessSpecifier.PUBLIC
+
+ protected = get_cursor(tu.cursor, "protected_member_function")
+ assert protected.access_specifier == AccessSpecifier.PROTECTED
+
+ private = get_cursor(tu.cursor, "private_member_function")
+ assert private.access_specifier == AccessSpecifier.PRIVATE
+
diff --git a/bindings/xml/comment-xml-schema.rng b/bindings/xml/comment-xml-schema.rng
index a8913a360b..29a91bf674 100644
--- a/bindings/xml/comment-xml-schema.rng
+++ b/bindings/xml/comment-xml-schema.rng
@@ -580,6 +580,12 @@
</data>
</element>
<element name="rawHTML">
+ <optional>
+ <!-- If not specified, the default value is 'false'. -->
+ <attribute name="isSafeToPassThrough">
+ <data type="boolean" />
+ </attribute>
+ </optional>
<!-- Non-empty text content. -->
<data type="string">
<param name="pattern">.*\S.*</param>
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
index 635ea1fe7c..20a1396c48 100644
--- a/docs/CMakeLists.txt
+++ b/docs/CMakeLists.txt
@@ -80,3 +80,12 @@ if (LLVM_ENABLE_DOXYGEN)
endif()
endif()
endif()
+
+if (LLVM_ENABLE_SPHINX)
+ if (SPHINX_FOUND)
+ include(AddSphinxTarget)
+ if (${SPHINX_OUTPUT_HTML})
+ add_sphinx_target(html clang)
+ endif()
+ endif()
+endif()
diff --git a/docs/ClangFormatStyleOptions.rst b/docs/ClangFormatStyleOptions.rst
index db77372724..27d5e7426a 100644
--- a/docs/ClangFormatStyleOptions.rst
+++ b/docs/ClangFormatStyleOptions.rst
@@ -106,9 +106,19 @@ the configuration (without a prefix: ``Auto``).
Allow putting all parameters of a function declaration onto
the next line even if ``BinPackParameters`` is ``false``.
-**AllowShortFunctionsOnASingleLine** (``bool``)
- If ``true``, ``int f() { return 0; }`` can be put on a single
- line.
+**AllowShortFunctionsOnASingleLine** (``ShortFunctionStyle``)
+ Dependent on the value, ``int f() { return 0; }`` can be put
+ on a single line.
+
+ Possible values:
+
+ * ``SFS_None`` (in configuration: ``None``)
+ Never merge functions into a single line.
+ * ``SFS_Inline`` (in configuration: ``Inline``)
+ Only merge functions defined inside a class.
+ * ``SFS_All`` (in configuration: ``All``)
+ Merge all functions fitting on a single line.
+
**AllowShortIfStatementsOnASingleLine** (``bool``)
If ``true``, ``if (a) return;`` can be put on a single
@@ -213,12 +223,16 @@ the configuration (without a prefix: ``Auto``).
not use this in config files, etc. Use at your own risk.
**ForEachMacros** (``std::vector<std::string>``)
- A list of macros that should be interpreted as foreach loops instead of as
- function calls.
+ A vector of macros that should be interpreted as foreach loops
+ instead of as function calls.
+
+ These are expected to be macros of the form:
+ \code
+ FOREACH(<variable-declaration>, ...)
+ <loop-body>
+ \endcode
- For example, ``ForEachMacros: [BOOST_FOREACH, Q_FOREACH]`` tells
- clang-format to treat ``BOOST_FOREACH`` and ``Q_FOREACH`` as loop control
- statements.
+ For example: BOOST_FOREACH.
**IndentCaseLabels** (``bool``)
Indent case labels one level from the switch statement.
@@ -233,6 +247,9 @@ the configuration (without a prefix: ``Auto``).
**IndentWidth** (``unsigned``)
The number of columns to use for indentation.
+**KeepEmptyLinesAtTheStartOfBlocks** (``bool``)
+ If true, empty lines at the start of blocks are kept.
+
**Language** (``LanguageKind``)
Language, this format style is targeted at.
@@ -319,7 +336,10 @@ the configuration (without a prefix: ``Auto``).
If ``true``, spaces may be inserted into '()'.
**SpacesBeforeTrailingComments** (``unsigned``)
- The number of spaces to before trailing line comments.
+ The number of spaces before trailing line comments (//-comments).
+
+ This does not affect trailing block comments (/\*\*/-comments) as those
+ commonly have different usage patterns and a number of special cases.
**SpacesInAngles** (``bool``)
If ``true``, spaces will be inserted after '<' and before '>' in
diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst
index 392e679f15..899ce728ba 100644
--- a/docs/LanguageExtensions.rst
+++ b/docs/LanguageExtensions.rst
@@ -134,6 +134,26 @@ The attribute name can also be specified with a preceding and following ``__``
(double underscore) to avoid interference from a macro with the same name. For
instance, ``__always_inline__`` can be used instead of ``always_inline``.
+``__is_identifier``
+-------------------
+
+This function-like macro takes a single identifier argument that might be either
+a reserved word or a regular identifier. It evaluates to 1 if the argument is just
+a regular identifier and not a reserved word, in the sense that it can then be
+used as the name of a user-defined function or variable. Otherwise it evaluates
+to 0. It can be used like this:
+
+.. code-block:: c++
+
+ ...
+ #ifdef __is_identifier // Compatibility with non-clang compilers.
+ #if __is_identifier(__wchar_t)
+ typedef wchar_t __wchar_t;
+ #endif
+ #endif
+
+ __wchar_t WideCharacter;
+ ...
Include File Checking Macros
============================
diff --git a/docs/Modules.rst b/docs/Modules.rst
index eec0b774cf..ce1e717bc2 100644
--- a/docs/Modules.rst
+++ b/docs/Modules.rst
@@ -198,6 +198,9 @@ Command-line parameters
``-fmodule-map-file=<file>``
Load the given module map file if a header from its directory or one of its subdirectories is loaded.
+``-fmodules-search-all``
+ If a symbol is not found, search modules referenced in the current module maps but not imported for symbols, so the error message can reference the module by name. Note that if the global module index has not been built before, this might take some time as it needs to build all the modules. Note that this option doesn't apply in module builds, to avoid the recursion.
+
Module Semantics
================
@@ -761,7 +764,7 @@ express this with a single module map file in the library:
because the header ``Foo_Private.h`` won't always be available. The
module map file could be customized based on whether
-``Foo_Private.h``is available or not, but doing so requires custom
+``Foo_Private.h`` is available or not, but doing so requires custom
build machinery.
Private module map files, which are named ``module.private.modulemap``
@@ -770,7 +773,7 @@ augment the primary module map file with an additional submodule. For
example, we would split the module map file above into two module map
files:
-.. parsed-literal::
+.. code-block:: c
/* module.modulemap */
module Foo {
@@ -839,7 +842,7 @@ Where To Learn More About Modules
=================================
The Clang source code provides additional information about modules:
-``clang/lib/Headers/module.map``
+``clang/lib/Headers/module.modulemap``
Module map for Clang's compiler-specific header files.
``clang/test/Modules/``
diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst
index 5b761a8326..19603d4e2c 100644
--- a/docs/UsersManual.rst
+++ b/docs/UsersManual.rst
@@ -1065,6 +1065,166 @@ are listed below.
only. This only applies to the AArch64 architecture.
+Using Sampling Profilers for Optimization
+-----------------------------------------
+
+Sampling profilers are used to collect runtime information, such as
+hardware counters, while your application executes. They are typically
+very efficient and do not incur a large runtime overhead. The
+sample data collected by the profiler can be used during compilation
+to determine what the most executed areas of the code are.
+
+In particular, sample profilers can provide execution counts for all
+instructions in the code and information on branches taken and function
+invocation. The compiler can use this information in its optimization
+cost models. For example, knowing that a branch is taken very
+frequently helps the compiler make better decisions when ordering
+basic blocks. Knowing that a function ``foo`` is called more
+frequently than another function ``bar`` helps the inliner.
+
+Using the data from a sample profiler requires some changes in the way
+a program is built. Before the compiler can use profiling information,
+the code needs to execute under the profiler. The following is the
+usual build cycle when using sample profilers for optimization:
+
+1. Build the code with source line table information. You can use all the
+ usual build flags that you always build your application with. The only
+ requirement is that you add ``-gline-tables-only`` or ``-g`` to the
+ command line. This is important for the profiler to be able to map
+ instructions back to source line locations.
+
+ .. code-block:: console
+
+ $ clang++ -O2 -gline-tables-only code.cc -o code
+
+2. Run the executable under a sampling profiler. The specific profiler
+ you use does not really matter, as long as its output can be converted
+ into the format that the LLVM optimizer understands. Currently, there
+ exists a conversion tool for the Linux Perf profiler
+ (https://perf.wiki.kernel.org/), so these examples assume that you
+ are using Linux Perf to profile your code.
+
+ .. code-block:: console
+
+ $ perf record -b ./code
+
+ Note the use of the ``-b`` flag. This tells Perf to use the Last Branch
+ Record (LBR) to record call chains. While this is not strictly required,
+ it provides better call information, which improves the accuracy of
+ the profile data.
+
+3. Convert the collected profile data to LLVM's sample profile format.
+ This is currently supported via the AutoFDO converter ``create_llvm_prof``.
+ It is available at http://github.com/google/autofdo. Once built and
+ installed, you can convert the ``perf.data`` file to LLVM using
+ the command:
+
+ .. code-block:: console
+
+ $ create_llvm_prof --binary=./code --out=code.prof
+
+ This will read ``perf.data`` and the binary file ``./code`` and emit
+ the profile data in ``code.prof``. Note that if you ran ``perf``
+ without the ``-b`` flag, you need to use ``--use_lbr=false`` when
+ calling ``create_llvm_prof``.
+
+4. Build the code again using the collected profile. This step feeds
+ the profile back to the optimizers. This should result in a binary
+ that executes faster than the original one. Note that you are not
+ required to build the code with the exact same arguments that you
+ used in the first step. The only requirement is that you build the code
+ with ``-gline-tables-only`` and ``-fprofile-sample-use``.
+
+ .. code-block:: console
+
+ $ clang++ -O2 -gline-tables-only -fprofile-sample-use=code.prof code.cc -o code
+
+
+Sample Profile Format
+^^^^^^^^^^^^^^^^^^^^^
+
+If you are not using Linux Perf to collect profiles, you will need to
+write a conversion tool from your profiler to LLVM's format. This section
+explains the file format expected by the backend.
+
+Sample profiles are written as ASCII text. The file is divided into sections,
+which correspond to each of the functions executed at runtime. Each
+section has the following format (taken from
+https://github.com/google/autofdo/blob/master/profile_writer.h):
+
+.. code-block:: console
+
+ function1:total_samples:total_head_samples
+ offset1[.discriminator]: number_of_samples [fn1:num fn2:num ... ]
+ offset2[.discriminator]: number_of_samples [fn3:num fn4:num ... ]
+ ...
+ offsetN[.discriminator]: number_of_samples [fn5:num fn6:num ... ]
+
+The file may contain blank lines between sections and within a
+section. However, the spacing within a single line is fixed. Additional
+spaces will result in an error while reading the file.
+
+Function names must be mangled in order for the profile loader to
+match them in the current translation unit. The two numbers in the
+function header specify how many total samples were accumulated in the
+function (first number), and the total number of samples accumulated
+in the prologue of the function (second number). This head sample
+count provides an indicator of how frequently the function is invoked.
+
+Each sampled line may contain several items. Some are optional (marked
+below):
+
+a. Source line offset. This number represents the line number
+ in the function where the sample was collected. The line number is
+ always relative to the line where symbol of the function is
+ defined. So, if the function has its header at line 280, the offset
+ 13 is at line 293 in the file.
+
+ Note that this offset should never be a negative number. This could
+ happen in cases like macros. The debug machinery will register the
+ line number at the point of macro expansion. So, if the macro was
+ expanded in a line before the start of the function, the profile
+ converter should emit a 0 as the offset (this means that the optimizers
+ will not be able to associate a meaningful weight to the instructions
+ in the macro).
+
+b. [OPTIONAL] Discriminator. This is used if the sampled program
+ was compiled with DWARF discriminator support
+ (http://wiki.dwarfstd.org/index.php?title=Path_Discriminators).
+ DWARF discriminators are unsigned integer values that allow the
+ compiler to distinguish between multiple execution paths on the
+ same source line location.
+
+ For example, consider the line of code ``if (cond) foo(); else bar();``.
+ If the predicate ``cond`` is true 80% of the time, then the edge
+ into function ``foo`` should be considered to be taken most of the
+ time. But both calls to ``foo`` and ``bar`` are at the same source
+ line, so a sample count at that line is not sufficient. The
+ compiler needs to know which part of that line is taken more
+ frequently.
+
+ This is what discriminators provide. In this case, the calls to
+ ``foo`` and ``bar`` will be at the same line, but will have
+ different discriminator values. This allows the compiler to correctly
+ set edge weights into ``foo`` and ``bar``.
+
+c. Number of samples. This is an integer quantity representing the
+ number of samples collected by the profiler at this source
+ location.
+
+d. [OPTIONAL] Potential call targets and samples. If present, this
+ line contains a call instruction. This models both direct and
+ number of samples. For example,
+
+ .. code-block:: console
+
+ 130: 7 foo:3 bar:2 baz:7
+
+ The above means that at relative line offset 130 there is a call
+ instruction that calls one of ``foo()``, ``bar()`` and ``baz()``,
+ with ``baz()`` being the relatively more frequently called target.
+
+
Controlling Size of Debug Information
-------------------------------------
diff --git a/docs/tools/dump_format_style.py b/docs/tools/dump_format_style.py
index addda2abc2..66bad8bb4e 100644..100755
--- a/docs/tools/dump_format_style.py
+++ b/docs/tools/dump_format_style.py
@@ -98,7 +98,7 @@ def read_options(header):
enum = Enum(name, comment)
elif line.endswith(';'):
state = State.InStruct
- field_type, field_name = re.match(r'([:\w]+)\s+(\w+);', line).groups()
+ field_type, field_name = re.match(r'([<>:\w]+)\s+(\w+);', line).groups()
option = Option(str(field_name), str(field_type), comment)
options.append(option)
else:
@@ -122,7 +122,8 @@ def read_options(header):
raise Exception('Not finished by the end of file')
for option in options:
- if not option.type in ['bool', 'unsigned', 'int', 'std::string']:
+ if not option.type in ['bool', 'unsigned', 'int', 'std::string',
+ 'std::vector<std::string>']:
if enums.has_key(option.type):
option.enum = enums[option.type]
else:
diff --git a/include/clang-c/CXString.h b/include/clang-c/CXString.h
index 592c4dc44e..cf198cbf5d 100644
--- a/include/clang-c/CXString.h
+++ b/include/clang-c/CXString.h
@@ -31,7 +31,7 @@ extern "C" {
* \brief A character string.
*
* The \c CXString type is used to return strings from the interface when
- * the ownership of that string might different from one call to the next.
+ * the ownership of that string might differ from one call to the next.
* Use \c clang_getCString() to retrieve the string data and, once finished
* with the string data, call \c clang_disposeString() to free the string.
*/
diff --git a/include/clang-c/Documentation.h b/include/clang-c/Documentation.h
new file mode 100644
index 0000000000..ad2da07783
--- /dev/null
+++ b/include/clang-c/Documentation.h
@@ -0,0 +1,554 @@
+/*==-- clang-c/Documentation.h - Utilities for comment processing -*- C -*-===*\
+|* *|
+|* The LLVM Compiler Infrastructure *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* This header provides a supplementary interface for inspecting *|
+|* documentation comments. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef CLANG_C_DOCUMENTATION_H
+#define CLANG_C_DOCUMENTATION_H
+
+#include "clang-c/Index.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \defgroup CINDEX_COMMENT Comment introspection
+ *
+ * The routines in this group provide access to information in documentation
+ * comments. These facilities are distinct from the core and may be subject to
+ * their own schedule of stability and deprecation.
+ *
+ * @{
+ */
+
+/**
+ * \brief A parsed comment.
+ */
+typedef struct {
+ const void *ASTNode;
+ CXTranslationUnit TranslationUnit;
+} CXComment;
+
+/**
+ * \brief Given a cursor that represents a documentable entity (e.g.,
+ * declaration), return the associated parsed comment as a
+ * \c CXComment_FullComment AST node.
+ */
+CINDEX_LINKAGE CXComment clang_Cursor_getParsedComment(CXCursor C);
+
+/**
+ * \brief Describes the type of the comment AST node (\c CXComment). A comment
+ * node can be considered block content (e. g., paragraph), inline content
+ * (plain text) or neither (the root AST node).
+ */
+enum CXCommentKind {
+ /**
+ * \brief Null comment. No AST node is constructed at the requested location
+ * because there is no text or a syntax error.
+ */
+ CXComment_Null = 0,
+
+ /**
+ * \brief Plain text. Inline content.
+ */
+ CXComment_Text = 1,
+
+ /**
+ * \brief A command with word-like arguments that is considered inline content.
+ *
+ * For example: \\c command.
+ */
+ CXComment_InlineCommand = 2,
+
+ /**
+ * \brief HTML start tag with attributes (name-value pairs). Considered
+ * inline content.
+ *
+ * For example:
+ * \verbatim
+ * <br> <br /> <a href="http://example.org/">
+ * \endverbatim
+ */
+ CXComment_HTMLStartTag = 3,
+
+ /**
+ * \brief HTML end tag. Considered inline content.
+ *
+ * For example:
+ * \verbatim
+ * </a>
+ * \endverbatim
+ */
+ CXComment_HTMLEndTag = 4,
+
+ /**
+ * \brief A paragraph, contains inline comment. The paragraph itself is
+ * block content.
+ */
+ CXComment_Paragraph = 5,
+
+ /**
+ * \brief A command that has zero or more word-like arguments (number of
+ * word-like arguments depends on command name) and a paragraph as an
+ * argument. Block command is block content.
+ *
+ * Paragraph argument is also a child of the block command.
+ *
+ * For example: \\brief has 0 word-like arguments and a paragraph argument.
+ *
+ * AST nodes of special kinds that parser knows about (e. g., \\param
+ * command) have their own node kinds.
+ */
+ CXComment_BlockCommand = 6,
+
+ /**
+ * \brief A \\param or \\arg command that describes the function parameter
+ * (name, passing direction, description).
+ *
+ * For example: \\param [in] ParamName description.
+ */
+ CXComment_ParamCommand = 7,
+
+ /**
+ * \brief A \\tparam command that describes a template parameter (name and
+ * description).
+ *
+ * For example: \\tparam T description.
+ */
+ CXComment_TParamCommand = 8,
+
+ /**
+ * \brief A verbatim block command (e. g., preformatted code). Verbatim
+ * block has an opening and a closing command and contains multiple lines of
+ * text (\c CXComment_VerbatimBlockLine child nodes).
+ *
+ * For example:
+ * \\verbatim
+ * aaa
+ * \\endverbatim
+ */
+ CXComment_VerbatimBlockCommand = 9,
+
+ /**
+ * \brief A line of text that is contained within a
+ * CXComment_VerbatimBlockCommand node.
+ */
+ CXComment_VerbatimBlockLine = 10,
+
+ /**
+ * \brief A verbatim line command. Verbatim line has an opening command,
+ * a single line of text (up to the newline after the opening command) and
+ * has no closing command.
+ */
+ CXComment_VerbatimLine = 11,
+
+ /**
+ * \brief A full comment attached to a declaration, contains block content.
+ */
+ CXComment_FullComment = 12
+};
+
+/**
+ * \brief The most appropriate rendering mode for an inline command, chosen on
+ * command semantics in Doxygen.
+ */
+enum CXCommentInlineCommandRenderKind {
+ /**
+ * \brief Command argument should be rendered in a normal font.
+ */
+ CXCommentInlineCommandRenderKind_Normal,
+
+ /**
+ * \brief Command argument should be rendered in a bold font.
+ */
+ CXCommentInlineCommandRenderKind_Bold,
+
+ /**
+ * \brief Command argument should be rendered in a monospaced font.
+ */
+ CXCommentInlineCommandRenderKind_Monospaced,
+
+ /**
+ * \brief Command argument should be rendered emphasized (typically italic
+ * font).
+ */
+ CXCommentInlineCommandRenderKind_Emphasized
+};
+
+/**
+ * \brief Describes parameter passing direction for \\param or \\arg command.
+ */
+enum CXCommentParamPassDirection {
+ /**
+ * \brief The parameter is an input parameter.
+ */
+ CXCommentParamPassDirection_In,
+
+ /**
+ * \brief The parameter is an output parameter.
+ */
+ CXCommentParamPassDirection_Out,
+
+ /**
+ * \brief The parameter is an input and output parameter.
+ */
+ CXCommentParamPassDirection_InOut
+};
+
+/**
+ * \param Comment AST node of any kind.
+ *
+ * \returns the type of the AST node.
+ */
+CINDEX_LINKAGE enum CXCommentKind clang_Comment_getKind(CXComment Comment);
+
+/**
+ * \param Comment AST node of any kind.
+ *
+ * \returns number of children of the AST node.
+ */
+CINDEX_LINKAGE unsigned clang_Comment_getNumChildren(CXComment Comment);
+
+/**
+ * \param Comment AST node of any kind.
+ *
+ * \param ChildIdx child index (zero-based).
+ *
+ * \returns the specified child of the AST node.
+ */
+CINDEX_LINKAGE
+CXComment clang_Comment_getChild(CXComment Comment, unsigned ChildIdx);
+
+/**
+ * \brief A \c CXComment_Paragraph node is considered whitespace if it contains
+ * only \c CXComment_Text nodes that are empty or whitespace.
+ *
+ * Other AST nodes (except \c CXComment_Paragraph and \c CXComment_Text) are
+ * never considered whitespace.
+ *
+ * \returns non-zero if \c Comment is whitespace.
+ */
+CINDEX_LINKAGE unsigned clang_Comment_isWhitespace(CXComment Comment);
+
+/**
+ * \returns non-zero if \c Comment is inline content and has a newline
+ * immediately following it in the comment text. Newlines between paragraphs
+ * do not count.
+ */
+CINDEX_LINKAGE
+unsigned clang_InlineContentComment_hasTrailingNewline(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_Text AST node.
+ *
+ * \returns text contained in the AST node.
+ */
+CINDEX_LINKAGE CXString clang_TextComment_getText(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_InlineCommand AST node.
+ *
+ * \returns name of the inline command.
+ */
+CINDEX_LINKAGE
+CXString clang_InlineCommandComment_getCommandName(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_InlineCommand AST node.
+ *
+ * \returns the most appropriate rendering mode, chosen on command
+ * semantics in Doxygen.
+ */
+CINDEX_LINKAGE enum CXCommentInlineCommandRenderKind
+clang_InlineCommandComment_getRenderKind(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_InlineCommand AST node.
+ *
+ * \returns number of command arguments.
+ */
+CINDEX_LINKAGE
+unsigned clang_InlineCommandComment_getNumArgs(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_InlineCommand AST node.
+ *
+ * \param ArgIdx argument index (zero-based).
+ *
+ * \returns text of the specified argument.
+ */
+CINDEX_LINKAGE
+CXString clang_InlineCommandComment_getArgText(CXComment Comment,
+ unsigned ArgIdx);
+
+/**
+ * \param Comment a \c CXComment_HTMLStartTag or \c CXComment_HTMLEndTag AST
+ * node.
+ *
+ * \returns HTML tag name.
+ */
+CINDEX_LINKAGE CXString clang_HTMLTagComment_getTagName(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_HTMLStartTag AST node.
+ *
+ * \returns non-zero if tag is self-closing (for example, &lt;br /&gt;).
+ */
+CINDEX_LINKAGE
+unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_HTMLStartTag AST node.
+ *
+ * \returns number of attributes (name-value pairs) attached to the start tag.
+ */
+CINDEX_LINKAGE unsigned clang_HTMLStartTag_getNumAttrs(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_HTMLStartTag AST node.
+ *
+ * \param AttrIdx attribute index (zero-based).
+ *
+ * \returns name of the specified attribute.
+ */
+CINDEX_LINKAGE
+CXString clang_HTMLStartTag_getAttrName(CXComment Comment, unsigned AttrIdx);
+
+/**
+ * \param Comment a \c CXComment_HTMLStartTag AST node.
+ *
+ * \param AttrIdx attribute index (zero-based).
+ *
+ * \returns value of the specified attribute.
+ */
+CINDEX_LINKAGE
+CXString clang_HTMLStartTag_getAttrValue(CXComment Comment, unsigned AttrIdx);
+
+/**
+ * \param Comment a \c CXComment_BlockCommand AST node.
+ *
+ * \returns name of the block command.
+ */
+CINDEX_LINKAGE
+CXString clang_BlockCommandComment_getCommandName(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_BlockCommand AST node.
+ *
+ * \returns number of word-like arguments.
+ */
+CINDEX_LINKAGE
+unsigned clang_BlockCommandComment_getNumArgs(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_BlockCommand AST node.
+ *
+ * \param ArgIdx argument index (zero-based).
+ *
+ * \returns text of the specified word-like argument.
+ */
+CINDEX_LINKAGE
+CXString clang_BlockCommandComment_getArgText(CXComment Comment,
+ unsigned ArgIdx);
+
+/**
+ * \param Comment a \c CXComment_BlockCommand or
+ * \c CXComment_VerbatimBlockCommand AST node.
+ *
+ * \returns paragraph argument of the block command.
+ */
+CINDEX_LINKAGE
+CXComment clang_BlockCommandComment_getParagraph(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_ParamCommand AST node.
+ *
+ * \returns parameter name.
+ */
+CINDEX_LINKAGE
+CXString clang_ParamCommandComment_getParamName(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_ParamCommand AST node.
+ *
+ * \returns non-zero if the parameter that this AST node represents was found
+ * in the function prototype and \c clang_ParamCommandComment_getParamIndex
+ * function will return a meaningful value.
+ */
+CINDEX_LINKAGE
+unsigned clang_ParamCommandComment_isParamIndexValid(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_ParamCommand AST node.
+ *
+ * \returns zero-based parameter index in function prototype.
+ */
+CINDEX_LINKAGE
+unsigned clang_ParamCommandComment_getParamIndex(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_ParamCommand AST node.
+ *
+ * \returns non-zero if parameter passing direction was specified explicitly in
+ * the comment.
+ */
+CINDEX_LINKAGE
+unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_ParamCommand AST node.
+ *
+ * \returns parameter passing direction.
+ */
+CINDEX_LINKAGE
+enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
+ CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_TParamCommand AST node.
+ *
+ * \returns template parameter name.
+ */
+CINDEX_LINKAGE
+CXString clang_TParamCommandComment_getParamName(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_TParamCommand AST node.
+ *
+ * \returns non-zero if the parameter that this AST node represents was found
+ * in the template parameter list and
+ * \c clang_TParamCommandComment_getDepth and
+ * \c clang_TParamCommandComment_getIndex functions will return a meaningful
+ * value.
+ */
+CINDEX_LINKAGE
+unsigned clang_TParamCommandComment_isParamPositionValid(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_TParamCommand AST node.
+ *
+ * \returns zero-based nesting depth of this parameter in the template parameter list.
+ *
+ * For example,
+ * \verbatim
+ * template<typename C, template<typename T> class TT>
+ * void test(TT<int> aaa);
+ * \endverbatim
+ * for C and TT nesting depth is 0,
+ * for T nesting depth is 1.
+ */
+CINDEX_LINKAGE
+unsigned clang_TParamCommandComment_getDepth(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_TParamCommand AST node.
+ *
+ * \returns zero-based parameter index in the template parameter list at a
+ * given nesting depth.
+ *
+ * For example,
+ * \verbatim
+ * template<typename C, template<typename T> class TT>
+ * void test(TT<int> aaa);
+ * \endverbatim
+ * for C and TT nesting depth is 0, so we can ask for index at depth 0:
+ * at depth 0 C's index is 0, TT's index is 1.
+ *
+ * For T nesting depth is 1, so we can ask for index at depth 0 and 1:
+ * at depth 0 T's index is 1 (same as TT's),
+ * at depth 1 T's index is 0.
+ */
+CINDEX_LINKAGE
+unsigned clang_TParamCommandComment_getIndex(CXComment Comment, unsigned Depth);
+
+/**
+ * \param Comment a \c CXComment_VerbatimBlockLine AST node.
+ *
+ * \returns text contained in the AST node.
+ */
+CINDEX_LINKAGE
+CXString clang_VerbatimBlockLineComment_getText(CXComment Comment);
+
+/**
+ * \param Comment a \c CXComment_VerbatimLine AST node.
+ *
+ * \returns text contained in the AST node.
+ */
+CINDEX_LINKAGE CXString clang_VerbatimLineComment_getText(CXComment Comment);
+
+/**
+ * \brief Convert an HTML tag AST node to string.
+ *
+ * \param Comment a \c CXComment_HTMLStartTag or \c CXComment_HTMLEndTag AST
+ * node.
+ *
+ * \returns string containing an HTML tag.
+ */
+CINDEX_LINKAGE CXString clang_HTMLTagComment_getAsString(CXComment Comment);
+
+/**
+ * \brief Convert a given full parsed comment to an HTML fragment.
+ *
+ * Specific details of HTML layout are subject to change. Don't try to parse
+ * this HTML back into an AST, use other APIs instead.
+ *
+ * Currently the following CSS classes are used:
+ * \li "para-brief" for \\brief paragraph and equivalent commands;
+ * \li "para-returns" for \\returns paragraph and equivalent commands;
+ * \li "word-returns" for the "Returns" word in \\returns paragraph.
+ *
+ * Function argument documentation is rendered as a \<dl\> list with arguments
+ * sorted in function prototype order. CSS classes used:
+ * \li "param-name-index-NUMBER" for parameter name (\<dt\>);
+ * \li "param-descr-index-NUMBER" for parameter description (\<dd\>);
+ * \li "param-name-index-invalid" and "param-descr-index-invalid" are used if
+ * parameter index is invalid.
+ *
+ * Template parameter documentation is rendered as a \<dl\> list with
+ * parameters sorted in template parameter list order. CSS classes used:
+ * \li "tparam-name-index-NUMBER" for parameter name (\<dt\>);
+ * \li "tparam-descr-index-NUMBER" for parameter description (\<dd\>);
+ * \li "tparam-name-index-other" and "tparam-descr-index-other" are used for
+ * names inside template template parameters;
+ * \li "tparam-name-index-invalid" and "tparam-descr-index-invalid" are used if
+ * parameter position is invalid.
+ *
+ * \param Comment a \c CXComment_FullComment AST node.
+ *
+ * \returns string containing an HTML fragment.
+ */
+CINDEX_LINKAGE CXString clang_FullComment_getAsHTML(CXComment Comment);
+
+/**
+ * \brief Convert a given full parsed comment to an XML document.
+ *
+ * A Relax NG schema for the XML can be found in comment-xml-schema.rng file
+ * inside clang source tree.
+ *
+ * \param Comment a \c CXComment_FullComment AST node.
+ *
+ * \returns string containing an XML document.
+ */
+CINDEX_LINKAGE CXString clang_FullComment_getAsXML(CXComment Comment);
+
+/**
+ * @}
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CLANG_C_DOCUMENTATION_H */
+
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 7eff0a4216..8393c6b7d4 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -32,7 +32,7 @@
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
*/
#define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 24
+#define CINDEX_VERSION_MINOR 25
#define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
@@ -653,12 +653,6 @@ enum CXDiagnosticSeverity {
CXDiagnostic_Note = 1,
/**
- * \brief This diagnostic is a remark that provides additional information
- * for the user.
- */
- CXDiagnostic_Remark = 5,
-
- /**
* \brief This diagnostic indicates suspicious code that may not be
* wrong.
*/
@@ -1740,7 +1734,7 @@ enum CXCursorKind {
/**
* \brief An expression that refers to some value declaration, such
- * as a function, varible, or enumerator.
+ * as a function, variable, or enumerator.
*/
CXCursor_DeclRefExpr = 101,
@@ -1978,7 +1972,7 @@ enum CXCursorKind {
*/
CXCursor_ObjCBoolLiteralExpr = 145,
- /** \brief Represents the "self" expression in a ObjC method.
+ /** \brief Represents the "self" expression in an Objective-C method.
*/
CXCursor_ObjCSelfExpr = 146,
@@ -2216,14 +2210,6 @@ typedef struct {
} CXCursor;
/**
- * \brief A comment AST node.
- */
-typedef struct {
- const void *ASTNode;
- CXTranslationUnit TranslationUnit;
-} CXComment;
-
-/**
* \defgroup CINDEX_CURSOR_MANIP Cursor manipulations
*
* @{
@@ -2510,10 +2496,10 @@ CINDEX_LINKAGE unsigned clang_CXCursorSet_insert(CXCursorSet cset,
* void C::f() { }
* \endcode
*
- * In the out-of-line definition of \c C::f, the semantic parent is the
+ * In the out-of-line definition of \c C::f, the semantic parent is
* the class \c C, of which this function is a member. The lexical parent is
* the place where the declaration actually occurs in the source code; in this
- * case, the definition occurs in the translation unit. In general, the
+ * case, the definition occurs in the translation unit. In general, the
* lexical parent for a given entity can change without affecting the semantics
* of the program, and the lexical parent of different declarations of the
* same entity may be different. Changing the semantic parent of a declaration,
@@ -2545,10 +2531,10 @@ CINDEX_LINKAGE CXCursor clang_getCursorSemanticParent(CXCursor cursor);
* void C::f() { }
* \endcode
*
- * In the out-of-line definition of \c C::f, the semantic parent is the
+ * In the out-of-line definition of \c C::f, the semantic parent is
* the class \c C, of which this function is a member. The lexical parent is
* the place where the declaration actually occurs in the source code; in this
- * case, the definition occurs in the translation unit. In general, the
+ * case, the definition occurs in the translation unit. In general, the
* lexical parent for a given entity can change without affecting the semantics
* of the program, and the lexical parent of different declarations of the
* same entity may be different. Changing the semantic parent of a declaration,
@@ -2673,7 +2659,7 @@ CINDEX_LINKAGE CXSourceLocation clang_getCursorLocation(CXCursor);
*
* The extent of a cursor starts with the file/line/column pointing at the
* first character within the source construct that the cursor refers to and
- * ends with the last character withinin that source construct. For a
+ * ends with the last character within that source construct. For a
* declaration, the extent covers the declaration itself. For a reference,
* the extent covers the location of the reference (e.g., where the referenced
* entity was actually used).
@@ -2695,7 +2681,7 @@ CINDEX_LINKAGE CXSourceRange clang_getCursorExtent(CXCursor);
*/
enum CXTypeKind {
/**
- * \brief Reprents an invalid type (e.g., where no type is available).
+ * \brief Represents an invalid type (e.g., where no type is available).
*/
CXType_Invalid = 0,
@@ -3367,8 +3353,8 @@ CINDEX_LINKAGE CXString clang_getCursorSpelling(CXCursor);
/**
* \brief Retrieve a range for a piece that forms the cursors spelling name.
* Most of the times there is only one range for the complete spelling but for
- * objc methods and objc message expressions, there are multiple pieces for each
- * selector identifier.
+ * Objective-C methods and Objective-C message expressions, there are multiple
+ * pieces for each selector identifier.
*
* \param pieceIndex the index of the spelling name piece. If this is greater
* than the actual number of pieces, it will return a NULL (invalid) range.
@@ -3464,25 +3450,25 @@ CINDEX_LINKAGE CXCursor clang_getCanonicalCursor(CXCursor);
/**
- * \brief If the cursor points to a selector identifier in a objc method or
- * message expression, this returns the selector index.
+ * \brief If the cursor points to a selector identifier in an Objective-C
+ * method or message expression, this returns the selector index.
*
* After getting a cursor with #clang_getCursor, this can be called to
* determine if the location points to a selector identifier.
*
- * \returns The selector index if the cursor is an objc method or message
+ * \returns The selector index if the cursor is an Objective-C method or message
* expression and the cursor is pointing to a selector identifier, or -1
* otherwise.
*/
CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor);
/**
- * \brief Given a cursor pointing to a C++ method call or an ObjC message,
- * returns non-zero if the method/message is "dynamic", meaning:
+ * \brief Given a cursor pointing to a C++ method call or an Objective-C
+ * message, returns non-zero if the method/message is "dynamic", meaning:
*
* For a C++ method: the call is virtual.
- * For an ObjC message: the receiver is an object instance, not 'super' or a
- * specific class.
+ * For an Objective-C message: the receiver is an object instance, not 'super'
+ * or a specific class.
*
* If the method/message is "static" or the cursor does not point to a
* method/message, it will return zero.
@@ -3490,8 +3476,8 @@ CINDEX_LINKAGE int clang_Cursor_getObjCSelectorIndex(CXCursor);
CINDEX_LINKAGE int clang_Cursor_isDynamicCall(CXCursor C);
/**
- * \brief Given a cursor pointing to an ObjC message, returns the CXType of the
- * receiver.
+ * \brief Given a cursor pointing to an Objective-C message, returns the CXType
+ * of the receiver.
*/
CINDEX_LINKAGE CXType clang_Cursor_getReceiverType(CXCursor C);
@@ -3526,7 +3512,7 @@ CINDEX_LINKAGE unsigned clang_Cursor_getObjCPropertyAttributes(CXCursor C,
/**
* \brief 'Qualifiers' written next to the return and parameter types in
- * ObjC method declarations.
+ * Objective-C method declarations.
*/
typedef enum {
CXObjCDeclQualifier_None = 0x0,
@@ -3539,15 +3525,16 @@ typedef enum {
} CXObjCDeclQualifierKind;
/**
- * \brief Given a cursor that represents an ObjC method or parameter
- * declaration, return the associated ObjC qualifiers for the return type or the
- * parameter respectively. The bits are formed from CXObjCDeclQualifierKind.
+ * \brief Given a cursor that represents an Objective-C method or parameter
+ * declaration, return the associated Objective-C qualifiers for the return
+ * type or the parameter respectively. The bits are formed from
+ * CXObjCDeclQualifierKind.
*/
CINDEX_LINKAGE unsigned clang_Cursor_getObjCDeclQualifiers(CXCursor C);
/**
- * \brief Given a cursor that represents an ObjC method or property declaration,
- * return non-zero if the declaration was affected by "@optional".
+ * \brief Given a cursor that represents an Objective-C method or property
+ * declaration, return non-zero if the declaration was affected by "@optional".
* Returns zero if the cursor is not such a declaration or it is "@required".
*/
CINDEX_LINKAGE unsigned clang_Cursor_isObjCOptional(CXCursor C);
@@ -3578,13 +3565,6 @@ CINDEX_LINKAGE CXString clang_Cursor_getRawCommentText(CXCursor C);
CINDEX_LINKAGE CXString clang_Cursor_getBriefCommentText(CXCursor C);
/**
- * \brief Given a cursor that represents a documentable entity (e.g.,
- * declaration), return the associated parsed comment as a
- * \c CXComment_FullComment AST node.
- */
-CINDEX_LINKAGE CXComment clang_Cursor_getParsedComment(CXCursor C);
-
-/**
* @}
*/
@@ -3657,514 +3637,6 @@ CXFile clang_Module_getTopLevelHeader(CXTranslationUnit,
*/
/**
- * \defgroup CINDEX_COMMENT Comment AST introspection
- *
- * The routines in this group provide access to information in the
- * documentation comment ASTs.
- *
- * @{
- */
-
-/**
- * \brief Describes the type of the comment AST node (\c CXComment). A comment
- * node can be considered block content (e. g., paragraph), inline content
- * (plain text) or neither (the root AST node).
- */
-enum CXCommentKind {
- /**
- * \brief Null comment. No AST node is constructed at the requested location
- * because there is no text or a syntax error.
- */
- CXComment_Null = 0,
-
- /**
- * \brief Plain text. Inline content.
- */
- CXComment_Text = 1,
-
- /**
- * \brief A command with word-like arguments that is considered inline content.
- *
- * For example: \\c command.
- */
- CXComment_InlineCommand = 2,
-
- /**
- * \brief HTML start tag with attributes (name-value pairs). Considered
- * inline content.
- *
- * For example:
- * \verbatim
- * <br> <br /> <a href="http://example.org/">
- * \endverbatim
- */
- CXComment_HTMLStartTag = 3,
-
- /**
- * \brief HTML end tag. Considered inline content.
- *
- * For example:
- * \verbatim
- * </a>
- * \endverbatim
- */
- CXComment_HTMLEndTag = 4,
-
- /**
- * \brief A paragraph, contains inline comment. The paragraph itself is
- * block content.
- */
- CXComment_Paragraph = 5,
-
- /**
- * \brief A command that has zero or more word-like arguments (number of
- * word-like arguments depends on command name) and a paragraph as an
- * argument. Block command is block content.
- *
- * Paragraph argument is also a child of the block command.
- *
- * For example: \\brief has 0 word-like arguments and a paragraph argument.
- *
- * AST nodes of special kinds that parser knows about (e. g., \\param
- * command) have their own node kinds.
- */
- CXComment_BlockCommand = 6,
-
- /**
- * \brief A \\param or \\arg command that describes the function parameter
- * (name, passing direction, description).
- *
- * For example: \\param [in] ParamName description.
- */
- CXComment_ParamCommand = 7,
-
- /**
- * \brief A \\tparam command that describes a template parameter (name and
- * description).
- *
- * For example: \\tparam T description.
- */
- CXComment_TParamCommand = 8,
-
- /**
- * \brief A verbatim block command (e. g., preformatted code). Verbatim
- * block has an opening and a closing command and contains multiple lines of
- * text (\c CXComment_VerbatimBlockLine child nodes).
- *
- * For example:
- * \\verbatim
- * aaa
- * \\endverbatim
- */
- CXComment_VerbatimBlockCommand = 9,
-
- /**
- * \brief A line of text that is contained within a
- * CXComment_VerbatimBlockCommand node.
- */
- CXComment_VerbatimBlockLine = 10,
-
- /**
- * \brief A verbatim line command. Verbatim line has an opening command,
- * a single line of text (up to the newline after the opening command) and
- * has no closing command.
- */
- CXComment_VerbatimLine = 11,
-
- /**
- * \brief A full comment attached to a declaration, contains block content.
- */
- CXComment_FullComment = 12
-};
-
-/**
- * \brief The most appropriate rendering mode for an inline command, chosen on
- * command semantics in Doxygen.
- */
-enum CXCommentInlineCommandRenderKind {
- /**
- * \brief Command argument should be rendered in a normal font.
- */
- CXCommentInlineCommandRenderKind_Normal,
-
- /**
- * \brief Command argument should be rendered in a bold font.
- */
- CXCommentInlineCommandRenderKind_Bold,
-
- /**
- * \brief Command argument should be rendered in a monospaced font.
- */
- CXCommentInlineCommandRenderKind_Monospaced,
-
- /**
- * \brief Command argument should be rendered emphasized (typically italic
- * font).
- */
- CXCommentInlineCommandRenderKind_Emphasized
-};
-
-/**
- * \brief Describes parameter passing direction for \\param or \\arg command.
- */
-enum CXCommentParamPassDirection {
- /**
- * \brief The parameter is an input parameter.
- */
- CXCommentParamPassDirection_In,
-
- /**
- * \brief The parameter is an output parameter.
- */
- CXCommentParamPassDirection_Out,
-
- /**
- * \brief The parameter is an input and output parameter.
- */
- CXCommentParamPassDirection_InOut
-};
-
-/**
- * \param Comment AST node of any kind.
- *
- * \returns the type of the AST node.
- */
-CINDEX_LINKAGE enum CXCommentKind clang_Comment_getKind(CXComment Comment);
-
-/**
- * \param Comment AST node of any kind.
- *
- * \returns number of children of the AST node.
- */
-CINDEX_LINKAGE unsigned clang_Comment_getNumChildren(CXComment Comment);
-
-/**
- * \param Comment AST node of any kind.
- *
- * \param ChildIdx child index (zero-based).
- *
- * \returns the specified child of the AST node.
- */
-CINDEX_LINKAGE
-CXComment clang_Comment_getChild(CXComment Comment, unsigned ChildIdx);
-
-/**
- * \brief A \c CXComment_Paragraph node is considered whitespace if it contains
- * only \c CXComment_Text nodes that are empty or whitespace.
- *
- * Other AST nodes (except \c CXComment_Paragraph and \c CXComment_Text) are
- * never considered whitespace.
- *
- * \returns non-zero if \c Comment is whitespace.
- */
-CINDEX_LINKAGE unsigned clang_Comment_isWhitespace(CXComment Comment);
-
-/**
- * \returns non-zero if \c Comment is inline content and has a newline
- * immediately following it in the comment text. Newlines between paragraphs
- * do not count.
- */
-CINDEX_LINKAGE
-unsigned clang_InlineContentComment_hasTrailingNewline(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_Text AST node.
- *
- * \returns text contained in the AST node.
- */
-CINDEX_LINKAGE CXString clang_TextComment_getText(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_InlineCommand AST node.
- *
- * \returns name of the inline command.
- */
-CINDEX_LINKAGE
-CXString clang_InlineCommandComment_getCommandName(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_InlineCommand AST node.
- *
- * \returns the most appropriate rendering mode, chosen on command
- * semantics in Doxygen.
- */
-CINDEX_LINKAGE enum CXCommentInlineCommandRenderKind
-clang_InlineCommandComment_getRenderKind(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_InlineCommand AST node.
- *
- * \returns number of command arguments.
- */
-CINDEX_LINKAGE
-unsigned clang_InlineCommandComment_getNumArgs(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_InlineCommand AST node.
- *
- * \param ArgIdx argument index (zero-based).
- *
- * \returns text of the specified argument.
- */
-CINDEX_LINKAGE
-CXString clang_InlineCommandComment_getArgText(CXComment Comment,
- unsigned ArgIdx);
-
-/**
- * \param Comment a \c CXComment_HTMLStartTag or \c CXComment_HTMLEndTag AST
- * node.
- *
- * \returns HTML tag name.
- */
-CINDEX_LINKAGE CXString clang_HTMLTagComment_getTagName(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_HTMLStartTag AST node.
- *
- * \returns non-zero if tag is self-closing (for example, &lt;br /&gt;).
- */
-CINDEX_LINKAGE
-unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_HTMLStartTag AST node.
- *
- * \returns number of attributes (name-value pairs) attached to the start tag.
- */
-CINDEX_LINKAGE unsigned clang_HTMLStartTag_getNumAttrs(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_HTMLStartTag AST node.
- *
- * \param AttrIdx attribute index (zero-based).
- *
- * \returns name of the specified attribute.
- */
-CINDEX_LINKAGE
-CXString clang_HTMLStartTag_getAttrName(CXComment Comment, unsigned AttrIdx);
-
-/**
- * \param Comment a \c CXComment_HTMLStartTag AST node.
- *
- * \param AttrIdx attribute index (zero-based).
- *
- * \returns value of the specified attribute.
- */
-CINDEX_LINKAGE
-CXString clang_HTMLStartTag_getAttrValue(CXComment Comment, unsigned AttrIdx);
-
-/**
- * \param Comment a \c CXComment_BlockCommand AST node.
- *
- * \returns name of the block command.
- */
-CINDEX_LINKAGE
-CXString clang_BlockCommandComment_getCommandName(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_BlockCommand AST node.
- *
- * \returns number of word-like arguments.
- */
-CINDEX_LINKAGE
-unsigned clang_BlockCommandComment_getNumArgs(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_BlockCommand AST node.
- *
- * \param ArgIdx argument index (zero-based).
- *
- * \returns text of the specified word-like argument.
- */
-CINDEX_LINKAGE
-CXString clang_BlockCommandComment_getArgText(CXComment Comment,
- unsigned ArgIdx);
-
-/**
- * \param Comment a \c CXComment_BlockCommand or
- * \c CXComment_VerbatimBlockCommand AST node.
- *
- * \returns paragraph argument of the block command.
- */
-CINDEX_LINKAGE
-CXComment clang_BlockCommandComment_getParagraph(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_ParamCommand AST node.
- *
- * \returns parameter name.
- */
-CINDEX_LINKAGE
-CXString clang_ParamCommandComment_getParamName(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_ParamCommand AST node.
- *
- * \returns non-zero if the parameter that this AST node represents was found
- * in the function prototype and \c clang_ParamCommandComment_getParamIndex
- * function will return a meaningful value.
- */
-CINDEX_LINKAGE
-unsigned clang_ParamCommandComment_isParamIndexValid(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_ParamCommand AST node.
- *
- * \returns zero-based parameter index in function prototype.
- */
-CINDEX_LINKAGE
-unsigned clang_ParamCommandComment_getParamIndex(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_ParamCommand AST node.
- *
- * \returns non-zero if parameter passing direction was specified explicitly in
- * the comment.
- */
-CINDEX_LINKAGE
-unsigned clang_ParamCommandComment_isDirectionExplicit(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_ParamCommand AST node.
- *
- * \returns parameter passing direction.
- */
-CINDEX_LINKAGE
-enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
- CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_TParamCommand AST node.
- *
- * \returns template parameter name.
- */
-CINDEX_LINKAGE
-CXString clang_TParamCommandComment_getParamName(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_TParamCommand AST node.
- *
- * \returns non-zero if the parameter that this AST node represents was found
- * in the template parameter list and
- * \c clang_TParamCommandComment_getDepth and
- * \c clang_TParamCommandComment_getIndex functions will return a meaningful
- * value.
- */
-CINDEX_LINKAGE
-unsigned clang_TParamCommandComment_isParamPositionValid(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_TParamCommand AST node.
- *
- * \returns zero-based nesting depth of this parameter in the template parameter list.
- *
- * For example,
- * \verbatim
- * template<typename C, template<typename T> class TT>
- * void test(TT<int> aaa);
- * \endverbatim
- * for C and TT nesting depth is 0,
- * for T nesting depth is 1.
- */
-CINDEX_LINKAGE
-unsigned clang_TParamCommandComment_getDepth(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_TParamCommand AST node.
- *
- * \returns zero-based parameter index in the template parameter list at a
- * given nesting depth.
- *
- * For example,
- * \verbatim
- * template<typename C, template<typename T> class TT>
- * void test(TT<int> aaa);
- * \endverbatim
- * for C and TT nesting depth is 0, so we can ask for index at depth 0:
- * at depth 0 C's index is 0, TT's index is 1.
- *
- * For T nesting depth is 1, so we can ask for index at depth 0 and 1:
- * at depth 0 T's index is 1 (same as TT's),
- * at depth 1 T's index is 0.
- */
-CINDEX_LINKAGE
-unsigned clang_TParamCommandComment_getIndex(CXComment Comment, unsigned Depth);
-
-/**
- * \param Comment a \c CXComment_VerbatimBlockLine AST node.
- *
- * \returns text contained in the AST node.
- */
-CINDEX_LINKAGE
-CXString clang_VerbatimBlockLineComment_getText(CXComment Comment);
-
-/**
- * \param Comment a \c CXComment_VerbatimLine AST node.
- *
- * \returns text contained in the AST node.
- */
-CINDEX_LINKAGE CXString clang_VerbatimLineComment_getText(CXComment Comment);
-
-/**
- * \brief Convert an HTML tag AST node to string.
- *
- * \param Comment a \c CXComment_HTMLStartTag or \c CXComment_HTMLEndTag AST
- * node.
- *
- * \returns string containing an HTML tag.
- */
-CINDEX_LINKAGE CXString clang_HTMLTagComment_getAsString(CXComment Comment);
-
-/**
- * \brief Convert a given full parsed comment to an HTML fragment.
- *
- * Specific details of HTML layout are subject to change. Don't try to parse
- * this HTML back into an AST, use other APIs instead.
- *
- * Currently the following CSS classes are used:
- * \li "para-brief" for \\brief paragraph and equivalent commands;
- * \li "para-returns" for \\returns paragraph and equivalent commands;
- * \li "word-returns" for the "Returns" word in \\returns paragraph.
- *
- * Function argument documentation is rendered as a \<dl\> list with arguments
- * sorted in function prototype order. CSS classes used:
- * \li "param-name-index-NUMBER" for parameter name (\<dt\>);
- * \li "param-descr-index-NUMBER" for parameter description (\<dd\>);
- * \li "param-name-index-invalid" and "param-descr-index-invalid" are used if
- * parameter index is invalid.
- *
- * Template parameter documentation is rendered as a \<dl\> list with
- * parameters sorted in template parameter list order. CSS classes used:
- * \li "tparam-name-index-NUMBER" for parameter name (\<dt\>);
- * \li "tparam-descr-index-NUMBER" for parameter description (\<dd\>);
- * \li "tparam-name-index-other" and "tparam-descr-index-other" are used for
- * names inside template template parameters;
- * \li "tparam-name-index-invalid" and "tparam-descr-index-invalid" are used if
- * parameter position is invalid.
- *
- * \param Comment a \c CXComment_FullComment AST node.
- *
- * \returns string containing an HTML fragment.
- */
-CINDEX_LINKAGE CXString clang_FullComment_getAsHTML(CXComment Comment);
-
-/**
- * \brief Convert a given full parsed comment to an XML document.
- *
- * A Relax NG schema for the XML can be found in comment-xml-schema.rng file
- * inside clang source tree.
- *
- * \param Comment a \c CXComment_FullComment AST node.
- *
- * \returns string containing an XML document.
- */
-CINDEX_LINKAGE CXString clang_FullComment_getAsXML(CXComment Comment);
-
-/**
- * @}
- */
-
-/**
* \defgroup CINDEX_CPP C++ AST introspection
*
* The routines in this group provide access information in the ASTs specific
@@ -4193,6 +3665,12 @@ CINDEX_LINKAGE unsigned clang_CXXMethod_isStatic(CXCursor C);
CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C);
/**
+ * \brief Determine if a C++ member function or member function template is
+ * declared 'const'.
+ */
+CINDEX_LINKAGE unsigned clang_CXXMethod_isConst(CXCursor C);
+
+/**
* \brief Given a cursor that represents a template, determine
* the cursor kind of the specializations would be generated by instantiating
* the template.
@@ -4282,7 +3760,7 @@ enum CXNameRefFlags {
* Non-contiguous names occur in Objective-C when a selector with two or more
* parameters is used, or in C++ when using an operator:
* \code
- * [object doSomething:here withValue:there]; // ObjC
+ * [object doSomething:here withValue:there]; // Objective-C
* return some_vector[1]; // C++
* \endcode
*/
@@ -5115,7 +4593,7 @@ CXDiagnostic clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *Results,
unsigned Index);
/**
- * \brief Determines what compeltions are appropriate for the context
+ * \brief Determines what completions are appropriate for the context
* the given code completion.
*
* \param Results the code completion results to query
@@ -5565,7 +5043,7 @@ typedef struct {
const CXIdxContainerInfo *declAsContainer;
/**
* \brief Whether the declaration exists in code or was created implicitly
- * by the compiler, e.g. implicit objc methods for properties.
+ * by the compiler, e.g. implicit Objective-C methods for properties.
*/
int isImplicit;
const CXIdxAttrInfo *const *attributes;
@@ -5638,8 +5116,8 @@ typedef enum {
*/
CXIdxEntityRef_Direct = 1,
/**
- * \brief An implicit reference, e.g. a reference of an ObjC method via the
- * dot syntax.
+ * \brief An implicit reference, e.g. a reference of an Objective-C method
+ * via the dot syntax.
*/
CXIdxEntityRef_Implicit = 2
} CXIdxEntityRefKind;
@@ -5833,7 +5311,7 @@ typedef enum {
/**
* \brief Skip a function/method body that was already parsed during an
- * indexing session assosiated with a \c CXIndexAction object.
+ * indexing session associated with a \c CXIndexAction object.
* Bodies in system headers are always skipped.
*/
CXIndexOpt_SkipParsedBodiesInSession = 0x10
@@ -5930,6 +5408,9 @@ CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc loc);
* @}
*/
+/* Include the comment API for compatibility. This will eventually go away. */
+#include "clang-c/Documentation.h"
+
#ifdef __cplusplus
}
#endif
diff --git a/include/clang/AST/ASTUnresolvedSet.h b/include/clang/AST/ASTUnresolvedSet.h
index e8be67006c..84b0842492 100644
--- a/include/clang/AST/ASTUnresolvedSet.h
+++ b/include/clang/AST/ASTUnresolvedSet.h
@@ -32,9 +32,6 @@ class ASTUnresolvedSet {
DeclsTy Decls;
- ASTUnresolvedSet(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
- void operator=(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
-
friend class LazyASTUnresolvedSet;
public:
diff --git a/include/clang/AST/ASTVector.h b/include/clang/AST/ASTVector.h
index d9d37b19c1..1490a13f84 100644
--- a/include/clang/AST/ASTVector.h
+++ b/include/clang/AST/ASTVector.h
@@ -47,11 +47,26 @@ public:
// Default ctor - Initialize to empty.
ASTVector() : Begin(0), End(0), Capacity(0, false) {}
+ ASTVector(ASTVector &&O) : Begin(O.Begin), End(O.End), Capacity(O.Capacity) {
+ O.Begin = O.End = 0;
+ O.Capacity.setPointer(0);
+ O.Capacity.setInt(false);
+ }
+
ASTVector(const ASTContext &C, unsigned N)
: Begin(0), End(0), Capacity(0, false) {
reserve(C, N);
}
+ ASTVector &operator=(ASTVector &&RHS) {
+ ASTVector O(std::move(RHS));
+ using std::swap;
+ swap(Begin, O.Begin);
+ swap(End, O.End);
+ swap(Capacity, O.Capacity);
+ return *this;
+ }
+
~ASTVector() {
if (std::is_class<T>::value) {
// Destroy the constructed elements in the vector.
diff --git a/include/clang/AST/Comment.h b/include/clang/AST/Comment.h
index 50e9196b1a..90dfb2570a 100644
--- a/include/clang/AST/Comment.h
+++ b/include/clang/AST/Comment.h
@@ -100,16 +100,27 @@ protected:
};
enum { NumInlineCommandCommentBits = NumInlineContentCommentBits + 10 };
+ class HTMLTagCommentBitfields {
+ friend class HTMLTagComment;
+
+ unsigned : NumInlineContentCommentBits;
+
+ /// True if this tag is safe to pass through to HTML output even if the
+ /// comment comes from an untrusted source.
+ unsigned IsSafeToPassThrough : 1;
+ };
+ enum { NumHTMLTagCommentBits = NumInlineContentCommentBits + 1 };
+
class HTMLStartTagCommentBitfields {
friend class HTMLStartTagComment;
- unsigned : NumInlineContentCommentBits;
+ unsigned : NumHTMLTagCommentBits;
/// True if this tag is self-closing (e. g., <br />). This is based on tag
/// spelling in comment (plain <br> would not set this flag).
unsigned IsSelfClosing : 1;
};
- enum { NumHTMLStartTagCommentBits = NumInlineContentCommentBits + 1 };
+ enum { NumHTMLStartTagCommentBits = NumHTMLTagCommentBits + 1 };
class ParagraphCommentBitfields {
friend class ParagraphComment;
@@ -155,6 +166,7 @@ protected:
InlineContentCommentBitfields InlineContentCommentBits;
TextCommentBitfields TextCommentBits;
InlineCommandCommentBitfields InlineCommandCommentBits;
+ HTMLTagCommentBitfields HTMLTagCommentBits;
HTMLStartTagCommentBitfields HTMLStartTagCommentBits;
ParagraphCommentBitfields ParagraphCommentBits;
BlockCommandCommentBitfields BlockCommandCommentBits;
@@ -360,8 +372,7 @@ public:
};
/// Abstract class for opening and closing HTML tags. HTML tags are always
-/// treated as inline content (regardless HTML semantics); opening and closing
-/// tags are not matched.
+/// treated as inline content (regardless HTML semantics).
class HTMLTagComment : public InlineContentComment {
protected:
StringRef TagName;
@@ -377,6 +388,7 @@ protected:
TagName(TagName),
TagNameRange(TagNameBegin, TagNameEnd) {
setLocation(TagNameBegin);
+ HTMLTagCommentBits.IsSafeToPassThrough = 1;
}
public:
@@ -392,6 +404,14 @@ public:
return SourceRange(L.getLocWithOffset(1),
L.getLocWithOffset(1 + TagName.size()));
}
+
+ bool isSafeToPassThrough() const {
+ return HTMLTagCommentBits.IsSafeToPassThrough;
+ }
+
+ void setUnsafeToPassThrough() {
+ HTMLTagCommentBits.IsSafeToPassThrough = 0;
+ }
};
/// An opening HTML tag with attributes.
diff --git a/include/clang/AST/CommentHTMLTags.td b/include/clang/AST/CommentHTMLTags.td
index f98e32ddca..79951b80ee 100644
--- a/include/clang/AST/CommentHTMLTags.td
+++ b/include/clang/AST/CommentHTMLTags.td
@@ -52,3 +52,83 @@ def Tr : Tag<"tr"> { let EndTagOptional = 1; }
def Th : Tag<"th"> { let EndTagOptional = 1; }
def Td : Tag<"td"> { let EndTagOptional = 1; }
+// Define a blacklist of attributes that are not safe to pass through to HTML
+// output if the input is untrusted.
+//
+// FIXME: this should be a whitelist. When changing this to a whitelist, don't
+// forget to change the default in the TableGen backend.
+class Attribute<string spelling> {
+ string Spelling = spelling;
+ bit IsSafeToPassThrough = 1;
+}
+class EventHandlerContentAttribute<string spelling> : Attribute<spelling> {
+ let IsSafeToPassThrough = 0;
+}
+
+// This list is based on HTML5 draft as of 04 February 2014.
+//
+// The list is intentionally organized as one item per line to make it easier
+// to compare with the HTML spec.
+foreach AttrName = [
+ "onabort",
+ "onblur",
+ "oncancel",
+ "oncanplay",
+ "oncanplaythrough",
+ "onchange",
+ "onclick",
+ "onclose",
+ "oncuechange",
+ "ondblclick",
+ "ondrag",
+ "ondragend",
+ "ondragenter",
+ "ondragexit",
+ "ondragleave",
+ "ondragover",
+ "ondragstart",
+ "ondrop",
+ "ondurationchange",
+ "onemptied",
+ "onended",
+ "onerror",
+ "onfocus",
+ "oninput",
+ "oninvalid",
+ "onkeydown",
+ "onkeypress",
+ "onkeyup",
+ "onload",
+ "onloadeddata",
+ "onloadedmetadata",
+ "onloadstart",
+ "onmousedown",
+ "onmouseenter",
+ "onmouseleave",
+ "onmousemove",
+ "onmouseout",
+ "onmouseover",
+ "onmouseup",
+ "onmousewheel",
+ "onpause",
+ "onplay",
+ "onplaying",
+ "onprogress",
+ "onratechange",
+ "onreset",
+ "onresize",
+ "onscroll",
+ "onseeked",
+ "onseeking",
+ "onselect",
+ "onshow",
+ "onstalled",
+ "onsubmit",
+ "onsuspend",
+ "ontimeupdate",
+ "ontoggle",
+ "onvolumechange",
+ "onwaiting"
+ ] in {
+ def Attr#AttrName : EventHandlerContentAttribute<AttrName>;
+}
diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h
index d10258e6f9..c44a47f33e 100644
--- a/include/clang/AST/DataRecursiveASTVisitor.h
+++ b/include/clang/AST/DataRecursiveASTVisitor.h
@@ -2406,6 +2406,14 @@ bool DataRecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C)
}
template<typename Derived>
+bool
+DataRecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) {
+ VisitOMPClauseList(C);
+ TraverseStmt(C->getStep());
+ return true;
+}
+
+template<typename Derived>
bool DataRecursiveASTVisitor<Derived>::VisitOMPCopyinClause(OMPCopyinClause *C) {
VisitOMPClauseList(C);
return true;
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 526187e31b..1ad8a90c4f 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -2374,11 +2374,6 @@ class TypeDecl : public NamedDecl {
/// LocStart - The start of the source range for this declaration.
SourceLocation LocStart;
friend class ASTContext;
- friend class DeclContext;
- friend class TagDecl;
- friend class TemplateTypeParmDecl;
- friend class TagType;
- friend class ASTReader;
protected:
TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index f64ef8b552..46774e0cf1 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -405,7 +405,7 @@ class CXXRecordDecl : public RecordDecl {
/// \brief True if this class has a constexpr default constructor.
///
/// This is true for either a user-declared constexpr default constructor
- /// or an implicitly declared constexpr default constructor..
+ /// or an implicitly declared constexpr default constructor.
bool HasConstexprDefaultConstructor : 1;
/// \brief True when this class contains at least one non-static data
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index adc8308f53..729f8ba7de 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -699,6 +699,9 @@ public:
/// or CastExprs, returning their operand.
Expr *IgnoreParenCasts() LLVM_READONLY;
+ /// Ignore casts. Strip off any CastExprs, returning their operand.
+ Expr *IgnoreCasts() LLVM_READONLY;
+
/// IgnoreParenImpCasts - Ignore parentheses and implicit casts. Strip off
/// any ParenExpr or ImplicitCastExprs, returning their operand.
Expr *IgnoreParenImpCasts() LLVM_READONLY;
@@ -760,6 +763,11 @@ public:
const Expr *IgnoreParenCasts() const LLVM_READONLY {
return const_cast<Expr*>(this)->IgnoreParenCasts();
}
+ /// Strip off casts, but keep parentheses.
+ const Expr *IgnoreCasts() const LLVM_READONLY {
+ return const_cast<Expr*>(this)->IgnoreCasts();
+ }
+
const Expr *IgnoreParenNoopCasts(ASTContext &Ctx) const LLVM_READONLY {
return const_cast<Expr*>(this)->IgnoreParenNoopCasts(Ctx);
}
@@ -1164,6 +1172,7 @@ public:
Function,
LFunction, // Same as Function, but as wide string.
FuncDName,
+ FuncSig,
PrettyFunction,
/// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the
/// 'virtual' keyword is omitted for virtual member functions.
@@ -2226,6 +2235,13 @@ public:
typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator;
+ typedef llvm::iterator_range<arg_iterator> arg_range;
+ typedef llvm::iterator_range<const_arg_iterator> arg_const_range;
+
+ arg_range arguments() { return arg_range(arg_begin(), arg_end()); }
+ arg_const_range arguments() const {
+ return arg_const_range(arg_begin(), arg_end());
+ }
arg_iterator arg_begin() { return SubExprs+PREARGS_START+getNumPreArgs(); }
arg_iterator arg_end() {
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 6ed55ca02d..aff0021a77 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -2431,6 +2431,9 @@ public:
decls_iterator decls_end() const {
return UnresolvedSetIterator(Results + NumResults);
}
+ llvm::iterator_range<decls_iterator> decls() const {
+ return llvm::iterator_range<decls_iterator>(decls_begin(), decls_end());
+ }
/// \brief Gets the number of declarations in the unresolved set.
unsigned getNumDecls() const { return NumResults; }
diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h
index 64b5ce4c5b..f91b491b8f 100644
--- a/include/clang/AST/OpenMPClause.h
+++ b/include/clang/AST/OpenMPClause.h
@@ -553,6 +553,91 @@ public:
}
};
+/// \brief This represents clause 'linear' in the '#pragma omp ...'
+/// directives.
+///
+/// \code
+/// #pragma omp simd linear(a,b : 2)
+/// \endcode
+/// In this example directive '#pragma omp simd' has clause 'linear'
+/// with variables 'a', 'b' and linear step '2'.
+///
+class OMPLinearClause : public OMPVarListClause<OMPLinearClause> {
+ friend class OMPClauseReader;
+ /// \brief Location of ':'.
+ SourceLocation ColonLoc;
+
+ /// \brief Sets the linear step for clause.
+ void setStep(Expr *Step) { *varlist_end() = Step; }
+
+ /// \brief Build 'linear' clause with given number of variables \a NumVars.
+ ///
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param ColonLoc Location of ':'.
+ /// \param EndLoc Ending location of the clause.
+ /// \param NumVars Number of variables.
+ ///
+ OMPLinearClause(SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc,
+ unsigned NumVars)
+ : OMPVarListClause<OMPLinearClause>(OMPC_linear, StartLoc, LParenLoc,
+ EndLoc, NumVars),
+ ColonLoc(ColonLoc) {}
+
+ /// \brief Build an empty clause.
+ ///
+ /// \param NumVars Number of variables.
+ ///
+ explicit OMPLinearClause(unsigned NumVars)
+ : OMPVarListClause<OMPLinearClause>(OMPC_linear, SourceLocation(),
+ SourceLocation(), SourceLocation(),
+ NumVars),
+ ColonLoc(SourceLocation()) {}
+
+public:
+ /// \brief Creates clause with a list of variables \a VL and a linear step
+ /// \a Step.
+ ///
+ /// \param C AST Context.
+ /// \param StartLoc Starting location of the clause.
+ /// \param LParenLoc Location of '('.
+ /// \param ColonLoc Location of ':'.
+ /// \param EndLoc Ending location of the clause.
+ /// \param VL List of references to the variables.
+ /// \param Step Linear step.
+ static OMPLinearClause *Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc, SourceLocation EndLoc,
+ ArrayRef<Expr *> VL, Expr *Step);
+
+ /// \brief Creates an empty clause with the place for \a NumVars variables.
+ ///
+ /// \param C AST context.
+ /// \param NumVars Number of variables.
+ ///
+ static OMPLinearClause *CreateEmpty(const ASTContext &C, unsigned NumVars);
+
+ /// \brief Sets the location of ':'.
+ void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; }
+ /// \brief Returns the location of '('.
+ SourceLocation getColonLoc() const { return ColonLoc; }
+
+ /// \brief Returns linear step.
+ Expr *getStep() { return *varlist_end(); }
+ /// \brief Returns linear step.
+ const Expr *getStep() const { return *varlist_end(); }
+
+ StmtRange children() {
+ return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
+ reinterpret_cast<Stmt **>(varlist_end() + 1));
+ }
+
+ static bool classof(const OMPClause *T) {
+ return T->getClauseKind() == OMPC_linear;
+ }
+};
+
/// \brief This represents clause 'copyin' in the '#pragma omp ...' directives.
///
/// \code
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 1a2ce44556..714d5a6921 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -2443,6 +2443,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
}
template<typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) {
+ VisitOMPClauseList(C);
+ TraverseStmt(C->getStep());
+ return true;
+}
+
+template<typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPCopyinClause(OMPCopyinClause *C) {
VisitOMPClauseList(C);
return true;
diff --git a/include/clang/ASTMatchers/Dynamic/Diagnostics.h b/include/clang/ASTMatchers/Dynamic/Diagnostics.h
index 53629bf567..82a14f1929 100644
--- a/include/clang/ASTMatchers/Dynamic/Diagnostics.h
+++ b/include/clang/ASTMatchers/Dynamic/Diagnostics.h
@@ -60,11 +60,12 @@ public:
enum ErrorType {
ET_None = 0,
- ET_RegistryNotFound = 1,
+ ET_RegistryMatcherNotFound = 1,
ET_RegistryWrongArgCount = 2,
ET_RegistryWrongArgType = 3,
ET_RegistryNotBindable = 4,
ET_RegistryAmbiguousOverload = 5,
+ ET_RegistryValueNotFound = 6,
ET_ParserStringError = 100,
ET_ParserNoOpenParen = 101,
diff --git a/include/clang/ASTMatchers/Dynamic/Parser.h b/include/clang/ASTMatchers/Dynamic/Parser.h
index 5901495bdd..4045f57d1b 100644
--- a/include/clang/ASTMatchers/Dynamic/Parser.h
+++ b/include/clang/ASTMatchers/Dynamic/Parser.h
@@ -18,13 +18,14 @@
///
/// \code
/// Grammar for the expressions supported:
-/// <Expression> := <Literal> | <MatcherExpression>
+/// <Expression> := <Literal> | <NamedValue> | <MatcherExpression>
/// <Literal> := <StringLiteral> | <Unsigned>
/// <StringLiteral> := "quoted string"
/// <Unsigned> := [0-9]+
-/// <MatcherExpression> := <MatcherName>(<ArgumentList>) |
-/// <MatcherName>(<ArgumentList>).bind(<StringLiteral>)
-/// <MatcherName> := [a-zA-Z]+
+/// <NamedValue> := <Identifier>
+/// <MatcherExpression> := <Identifier>(<ArgumentList>) |
+/// <Identifier>(<ArgumentList>).bind(<StringLiteral>)
+/// <Identifier> := [a-zA-Z]+
/// <ArgumentList> := <Expression> | <Expression>,<ArgumentList>
/// \endcode
///
@@ -62,6 +63,17 @@ public:
public:
virtual ~Sema();
+ /// \brief Lookup a value by name.
+ ///
+ /// This can be used in the Sema layer to declare known constants or to
+ /// allow to split an expression in pieces.
+ ///
+ /// \param Name The name of the value to lookup.
+ ///
+ /// \return The named value. It could be any type that VariantValue
+ /// supports. An empty value means that the name is not recognized.
+ virtual VariantValue getNamedValue(StringRef Name);
+
/// \brief Process a matcher expression.
///
/// All the arguments passed here have already been processed.
@@ -89,15 +101,26 @@ public:
///
/// \param MatcherName The matcher name found by the parser.
///
- /// \param NameRange The location of the name in the matcher source.
- /// Useful for error reporting.
- ///
- /// \return The matcher constructor, or Optional<MatcherCtor>() if an error
- /// occurred. In that case, \c Error will contain a description of the
- /// error.
+ /// \return The matcher constructor, or Optional<MatcherCtor>() if not
+ /// found.
virtual llvm::Optional<MatcherCtor>
- lookupMatcherCtor(StringRef MatcherName, const SourceRange &NameRange,
- Diagnostics *Error) = 0;
+ lookupMatcherCtor(StringRef MatcherName) = 0;
+ };
+
+ /// \brief Sema implementation that uses the matcher registry to process the
+ /// tokens.
+ class RegistrySema : public Parser::Sema {
+ public:
+ virtual ~RegistrySema();
+
+ llvm::Optional<MatcherCtor>
+ lookupMatcherCtor(StringRef MatcherName) override;
+
+ VariantMatcher actOnMatcherExpression(MatcherCtor Ctor,
+ const SourceRange &NameRange,
+ StringRef BindID,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) override;
};
/// \brief Parse a matcher expression, creating matchers from the registry.
@@ -160,7 +183,9 @@ private:
Diagnostics *Error);
bool parseExpressionImpl(VariantValue *Value);
- bool parseMatcherExpressionImpl(VariantValue *Value);
+ bool parseMatcherExpressionImpl(const TokenInfo &NameToken,
+ VariantValue *Value);
+ bool parseIdentifierPrefixImpl(VariantValue *Value);
void addCompletion(const TokenInfo &CompToken, StringRef TypedText,
StringRef Decl);
diff --git a/include/clang/ASTMatchers/Dynamic/Registry.h b/include/clang/ASTMatchers/Dynamic/Registry.h
index d7df698b65..72ae6126f7 100644
--- a/include/clang/ASTMatchers/Dynamic/Registry.h
+++ b/include/clang/ASTMatchers/Dynamic/Registry.h
@@ -55,11 +55,8 @@ public:
/// \brief Look up a matcher in the registry by name,
///
/// \return An opaque value which may be used to refer to the matcher
- /// constructor, or Optional<MatcherCtor>() if not found. In that case
- /// \c Error will contain the description of the error.
- static llvm::Optional<MatcherCtor>
- lookupMatcherCtor(StringRef MatcherName, const SourceRange &NameRange,
- Diagnostics *Error);
+ /// constructor, or Optional<MatcherCtor>() if not found.
+ static llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName);
/// \brief Compute the list of completions for \p Context.
///
diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h
index c6853572ec..336da3e5dd 100644
--- a/include/clang/ASTMatchers/Dynamic/VariantValue.h
+++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h
@@ -78,7 +78,8 @@ public:
/// \brief Clones the provided matchers.
///
/// They should be the result of a polymorphic matcher.
- static VariantMatcher PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers);
+ static VariantMatcher
+ PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers);
/// \brief Creates a 'variadic' operator matcher.
///
@@ -208,6 +209,10 @@ public:
VariantValue(const std::string &String);
VariantValue(const VariantMatcher &Matchers);
+ /// \brief Returns true iff this is not an empty value.
+ LLVM_EXPLICIT operator bool() const { return hasValue(); }
+ bool hasValue() const { return Type != VT_Nothing; }
+
/// \brief Unsigned value functions.
bool isUnsigned() const;
unsigned getUnsigned() const;
diff --git a/include/clang/Analysis/Analyses/PostOrderCFGView.h b/include/clang/Analysis/Analyses/PostOrderCFGView.h
index 4e3244e7b7..9ceace748b 100644
--- a/include/clang/Analysis/Analyses/PostOrderCFGView.h
+++ b/include/clang/Analysis/Analyses/PostOrderCFGView.h
@@ -76,14 +76,18 @@ private:
BlockOrderTy BlockOrder;
public:
- typedef std::vector<const CFGBlock*>::reverse_iterator iterator;
+ typedef std::vector<const CFGBlock *>::reverse_iterator iterator;
+ typedef std::vector<const CFGBlock *>::const_reverse_iterator const_iterator;
PostOrderCFGView(const CFG *cfg);
iterator begin() { return Blocks.rbegin(); }
iterator end() { return Blocks.rend(); }
- bool empty() { return begin() == end(); }
+ const_iterator begin() const { return Blocks.rbegin(); }
+ const_iterator end() const { return Blocks.rend(); }
+
+ bool empty() const { return begin() == end(); }
struct BlockOrderCompare;
friend struct BlockOrderCompare;
diff --git a/include/clang/Analysis/Analyses/ThreadSafetyCommon.h b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
new file mode 100644
index 0000000000..6a3ae3605b
--- /dev/null
+++ b/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
@@ -0,0 +1,388 @@
+//===- ThreadSafetyCommon.h ------------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Parts of thread safety analysis that are not specific to thread safety
+// itself have been factored into classes here, where they can be potentially
+// used by other analyses. Currently these include:
+//
+// * Generalize clang CFG visitors.
+// * Conversion of the clang CFG to SSA form.
+// * Translation of clang Exprs to TIL SExprs
+//
+// UNDER CONSTRUCTION. USE AT YOUR OWN RISK.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_THREAD_SAFETY_COMMON_H
+#define LLVM_CLANG_THREAD_SAFETY_COMMON_H
+
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Basic/OperatorKinds.h"
+
+#include <memory>
+#include <vector>
+
+
+namespace clang {
+namespace threadSafety {
+
+// This class defines the interface of a clang CFG Visitor.
+// CFGWalker will invoke the following methods.
+// Note that methods are not virtual; the visitor is templatized.
+class CFGVisitor {
+ // Enter the CFG for Decl D, and perform any initial setup operations.
+ void enterCFG(CFG *Cfg, const NamedDecl *D, const CFGBlock *First) {}
+
+ // Enter a CFGBlock.
+ void enterCFGBlock(const CFGBlock *B) {}
+
+ // Returns true if this visitor implements handlePredecessor
+ bool visitPredecessors() { return true; }
+
+ // Process a predecessor edge.
+ void handlePredecessor(const CFGBlock *Pred) {}
+
+ // Process a successor back edge to a previously visited block.
+ void handlePredecessorBackEdge(const CFGBlock *Pred) {}
+
+ // Called just before processing statements.
+ void enterCFGBlockBody(const CFGBlock *B) {}
+
+ // Process an ordinary statement.
+ void handleStatement(const Stmt *S) {}
+
+ // Process a destructor call
+ void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD) {}
+
+ // Called after all statements have been handled.
+ void exitCFGBlockBody(const CFGBlock *B) {}
+
+ // Return true
+ bool visitSuccessors() { return true; }
+
+ // Process a successor edge.
+ void handleSuccessor(const CFGBlock *Succ) {}
+
+ // Process a successor back edge to a previously visited block.
+ void handleSuccessorBackEdge(const CFGBlock *Succ) {}
+
+ // Leave a CFGBlock.
+ void exitCFGBlock(const CFGBlock *B) {}
+
+ // Leave the CFG, and perform any final cleanup operations.
+ void exitCFG(const CFGBlock *Last) {}
+};
+
+
+// Walks the clang CFG, and invokes methods on a given CFGVisitor.
+class CFGWalker {
+public:
+ CFGWalker() : CFGraph(nullptr), ACtx(nullptr), SortedGraph(nullptr) {}
+
+ // Initialize the CFGWalker. This setup only needs to be done once, even
+ // if there are multiple passes over the CFG.
+ bool init(AnalysisDeclContext &AC) {
+ ACtx = &AC;
+ CFGraph = AC.getCFG();
+ if (!CFGraph)
+ return false;
+
+ // Ignore anonymous functions.
+ if (!dyn_cast_or_null<NamedDecl>(AC.getDecl()))
+ return false;
+
+ SortedGraph = AC.getAnalysis<PostOrderCFGView>();
+ if (!SortedGraph)
+ return false;
+
+ return true;
+ }
+
+ // Traverse the CFG, calling methods on V as appropriate.
+ template <class Visitor>
+ void walk(Visitor &V) {
+ PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
+
+ V.enterCFG(CFGraph, getDecl(), &CFGraph->getEntry());
+
+ for (const auto *CurrBlock : *SortedGraph) {
+ VisitedBlocks.insert(CurrBlock);
+
+ V.enterCFGBlock(CurrBlock);
+
+ // Process predecessors, handling back edges last
+ if (V.visitPredecessors()) {
+ SmallVector<CFGBlock*, 4> BackEdges;
+ // Process successors
+ for (CFGBlock::const_pred_iterator SI = CurrBlock->pred_begin(),
+ SE = CurrBlock->pred_end();
+ SI != SE; ++SI) {
+ if (*SI == nullptr)
+ continue;
+
+ if (!VisitedBlocks.alreadySet(*SI)) {
+ BackEdges.push_back(*SI);
+ continue;
+ }
+ V.handlePredecessor(*SI);
+ }
+
+ for (auto *Blk : BackEdges)
+ V.handlePredecessorBackEdge(Blk);
+ }
+
+ V.enterCFGBlockBody(CurrBlock);
+
+ // Process statements
+ for (const auto &BI : *CurrBlock) {
+ switch (BI.getKind()) {
+ case CFGElement::Statement: {
+ V.handleStatement(BI.castAs<CFGStmt>().getStmt());
+ break;
+ }
+ case CFGElement::AutomaticObjectDtor: {
+ CFGAutomaticObjDtor AD = BI.castAs<CFGAutomaticObjDtor>();
+ CXXDestructorDecl *DD = const_cast<CXXDestructorDecl*>(
+ AD.getDestructorDecl(ACtx->getASTContext()));
+ VarDecl *VD = const_cast<VarDecl*>(AD.getVarDecl());
+ V.handleDestructorCall(VD, DD);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ V.exitCFGBlockBody(CurrBlock);
+
+ // Process successors, handling back edges first.
+ if (V.visitSuccessors()) {
+ SmallVector<CFGBlock*, 8> ForwardEdges;
+
+ // Process successors
+ for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
+ SE = CurrBlock->succ_end();
+ SI != SE; ++SI) {
+ if (*SI == nullptr)
+ continue;
+
+ if (!VisitedBlocks.alreadySet(*SI)) {
+ ForwardEdges.push_back(*SI);
+ continue;
+ }
+ V.handleSuccessorBackEdge(*SI);
+ }
+
+ for (auto *Blk : ForwardEdges)
+ V.handleSuccessor(Blk);
+ }
+
+ V.exitCFGBlock(CurrBlock);
+ }
+ V.exitCFG(&CFGraph->getExit());
+ }
+
+ const CFG *getGraph() const { return CFGraph; }
+ CFG *getGraph() { return CFGraph; }
+
+ const FunctionDecl *getDecl() const {
+ return dyn_cast<FunctionDecl>(ACtx->getDecl());
+ }
+
+ const PostOrderCFGView *getSortedGraph() const { return SortedGraph; }
+
+private:
+ CFG *CFGraph;
+ AnalysisDeclContext *ACtx;
+ PostOrderCFGView *SortedGraph;
+};
+
+
+// Translate clang::Expr to til::SExpr.
+class SExprBuilder {
+public:
+ /// \brief Encapsulates the lexical context of a function call. The lexical
+ /// context includes the arguments to the call, including the implicit object
+ /// argument. When an attribute containing a mutex expression is attached to
+ /// a method, the expression may refer to formal parameters of the method.
+ /// Actual arguments must be substituted for formal parameters to derive
+ /// the appropriate mutex expression in the lexical context where the function
+ /// is called. PrevCtx holds the context in which the arguments themselves
+ /// should be evaluated; multiple calling contexts can be chained together
+ /// by the lock_returned attribute.
+ struct CallingContext {
+ const NamedDecl *AttrDecl; // The decl to which the attr is attached.
+ const Expr *SelfArg; // Implicit object argument -- e.g. 'this'
+ unsigned NumArgs; // Number of funArgs
+ const Expr *const *FunArgs; // Function arguments
+ CallingContext *Prev; // The previous context; or 0 if none.
+ bool SelfArrow; // is Self referred to with -> or .?
+
+ CallingContext(const NamedDecl *D = nullptr, const Expr *S = nullptr,
+ unsigned N = 0, const Expr *const *A = nullptr,
+ CallingContext *P = nullptr)
+ : AttrDecl(D), SelfArg(S), NumArgs(N), FunArgs(A), Prev(P),
+ SelfArrow(false)
+ {}
+ };
+
+ SExprBuilder(til::MemRegionRef A)
+ : Arena(A), SelfVar(nullptr), Scfg(nullptr), CurrentBB(nullptr),
+ CurrentBlockInfo(nullptr) {
+ // FIXME: we don't always have a self-variable.
+ SelfVar = new (Arena) til::Variable(til::Variable::VK_SFun);
+ }
+
+ // Translate a clang statement or expression to a TIL expression.
+ // Also performs substitution of variables; Ctx provides the context.
+ // Dispatches on the type of S.
+ til::SExpr *translate(const Stmt *S, CallingContext *Ctx);
+ til::SCFG *buildCFG(CFGWalker &Walker);
+
+ til::SExpr *lookupStmt(const Stmt *S);
+
+ til::BasicBlock *lookupBlock(const CFGBlock *B) {
+ return BlockMap[B->getBlockID()];
+ }
+
+ const til::SCFG *getCFG() const { return Scfg; }
+ til::SCFG *getCFG() { return Scfg; }
+
+private:
+ til::SExpr *translateDeclRefExpr(const DeclRefExpr *DRE,
+ CallingContext *Ctx) ;
+ til::SExpr *translateCXXThisExpr(const CXXThisExpr *TE, CallingContext *Ctx);
+ til::SExpr *translateMemberExpr(const MemberExpr *ME, CallingContext *Ctx);
+ til::SExpr *translateCallExpr(const CallExpr *CE, CallingContext *Ctx);
+ til::SExpr *translateCXXMemberCallExpr(const CXXMemberCallExpr *ME,
+ CallingContext *Ctx);
+ til::SExpr *translateCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE,
+ CallingContext *Ctx);
+ til::SExpr *translateUnaryOperator(const UnaryOperator *UO,
+ CallingContext *Ctx);
+ til::SExpr *translateBinAssign(til::TIL_BinaryOpcode Op,
+ const BinaryOperator *BO,
+ CallingContext *Ctx);
+ til::SExpr *translateBinaryOperator(const BinaryOperator *BO,
+ CallingContext *Ctx);
+ til::SExpr *translateCastExpr(const CastExpr *CE, CallingContext *Ctx);
+ til::SExpr *translateArraySubscriptExpr(const ArraySubscriptExpr *E,
+ CallingContext *Ctx);
+ til::SExpr *translateConditionalOperator(const ConditionalOperator *C,
+ CallingContext *Ctx);
+ til::SExpr *translateBinaryConditionalOperator(
+ const BinaryConditionalOperator *C, CallingContext *Ctx);
+
+ til::SExpr *translateDeclStmt(const DeclStmt *S, CallingContext *Ctx);
+
+ // Map from statements in the clang CFG to SExprs in the til::SCFG.
+ typedef llvm::DenseMap<const Stmt*, til::SExpr*> StatementMap;
+
+ // Map from clang local variables to indices in a LVarDefinitionMap.
+ typedef llvm::DenseMap<const ValueDecl *, unsigned> LVarIndexMap;
+
+ // Map from local variable indices to SSA variables (or constants).
+ typedef std::pair<const ValueDecl *, til::SExpr *> NameVarPair;
+ typedef CopyOnWriteVector<NameVarPair> LVarDefinitionMap;
+
+ struct BlockInfo {
+ LVarDefinitionMap ExitMap;
+ bool HasBackEdges;
+ unsigned UnprocessedSuccessors; // Successors yet to be processed
+ unsigned ProcessedPredecessors; // Predecessors already processed
+
+ BlockInfo()
+ : HasBackEdges(false), UnprocessedSuccessors(0),
+ ProcessedPredecessors(0) {}
+ BlockInfo(BlockInfo &&RHS)
+ : ExitMap(std::move(RHS.ExitMap)),
+ HasBackEdges(RHS.HasBackEdges),
+ UnprocessedSuccessors(RHS.UnprocessedSuccessors),
+ ProcessedPredecessors(RHS.ProcessedPredecessors) {}
+
+ BlockInfo &operator=(BlockInfo &&RHS) {
+ if (this != &RHS) {
+ ExitMap = std::move(RHS.ExitMap);
+ HasBackEdges = RHS.HasBackEdges;
+ UnprocessedSuccessors = RHS.UnprocessedSuccessors;
+ ProcessedPredecessors = RHS.ProcessedPredecessors;
+ }
+ return *this;
+ }
+
+ private:
+ BlockInfo(const BlockInfo &) LLVM_DELETED_FUNCTION;
+ void operator=(const BlockInfo &) LLVM_DELETED_FUNCTION;
+ };
+
+ // We implement the CFGVisitor API
+ friend class CFGWalker;
+
+ void enterCFG(CFG *Cfg, const FunctionDecl *D, const CFGBlock *First);
+ void enterCFGBlock(const CFGBlock *B);
+ bool visitPredecessors() { return true; }
+ void handlePredecessor(const CFGBlock *Pred);
+ void handlePredecessorBackEdge(const CFGBlock *Pred);
+ void enterCFGBlockBody(const CFGBlock *B);
+ void handleStatement(const Stmt *S);
+ void handleDestructorCall(const VarDecl *VD, const CXXDestructorDecl *DD);
+ void exitCFGBlockBody(const CFGBlock *B);
+ bool visitSuccessors() { return true; }
+ void handleSuccessor(const CFGBlock *Succ);
+ void handleSuccessorBackEdge(const CFGBlock *Succ);
+ void exitCFGBlock(const CFGBlock *B);
+ void exitCFG(const CFGBlock *Last);
+
+ void insertStmt(const Stmt *S, til::SExpr *E) {
+ SMap.insert(std::make_pair(S, E));
+ }
+ til::SExpr *getCurrentLVarDefinition(const ValueDecl *VD);
+
+ til::SExpr *addStatement(til::SExpr *E, const Stmt *S, const ValueDecl *VD=0);
+ til::SExpr *lookupVarDecl(const ValueDecl *VD);
+ til::SExpr *addVarDecl(const ValueDecl *VD, til::SExpr *E);
+ til::SExpr *updateVarDecl(const ValueDecl *VD, til::SExpr *E);
+
+ void makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E);
+ void mergeEntryMap(LVarDefinitionMap Map);
+ void mergeEntryMapBackEdge();
+ void mergePhiNodesBackEdge(const CFGBlock *Blk);
+
+private:
+ til::MemRegionRef Arena;
+ til::Variable *SelfVar; // Variable to use for 'this'. May be null.
+ til::SCFG *Scfg;
+
+ StatementMap SMap; // Map from Stmt to TIL Variables
+ LVarIndexMap LVarIdxMap; // Indices of clang local vars.
+ std::vector<til::BasicBlock *> BlockMap; // Map from clang to til BBs.
+ std::vector<BlockInfo> BBInfo; // Extra information per BB.
+ // Indexed by clang BlockID.
+ std::unique_ptr<SExprBuilder::CallingContext> CallCtx; // Root calling context
+
+ LVarDefinitionMap CurrentLVarMap;
+ std::vector<til::Variable*> CurrentArguments;
+ std::vector<til::Variable*> CurrentInstructions;
+ std::vector<til::Variable*> IncompleteArgs;
+ til::BasicBlock *CurrentBB;
+ BlockInfo *CurrentBlockInfo;
+};
+
+
+// Dump an SCFG to llvm::errs().
+void printSCFG(CFGWalker &Walker);
+
+
+} // end namespace threadSafety
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_THREAD_SAFETY_COMMON_H
diff --git a/include/clang/Analysis/Analyses/ThreadSafetyOps.def b/include/clang/Analysis/Analyses/ThreadSafetyOps.def
new file mode 100644
index 0000000000..42184d8246
--- /dev/null
+++ b/include/clang/Analysis/Analyses/ThreadSafetyOps.def
@@ -0,0 +1,46 @@
+//===- ThreadSafetyTIL.h ---------------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the list of core opcodes for the Thread Safety
+// Typed Intermediate language. Please see ThreadSafetyTIL.h for more
+// information.
+//
+//===----------------------------------------------------------------------===//
+
+
+TIL_OPCODE_DEF(Future)
+TIL_OPCODE_DEF(Undefined)
+TIL_OPCODE_DEF(Wildcard)
+
+TIL_OPCODE_DEF(Literal)
+TIL_OPCODE_DEF(LiteralPtr)
+TIL_OPCODE_DEF(Variable)
+TIL_OPCODE_DEF(Function)
+TIL_OPCODE_DEF(SFunction)
+TIL_OPCODE_DEF(Code)
+
+TIL_OPCODE_DEF(Apply)
+TIL_OPCODE_DEF(SApply)
+TIL_OPCODE_DEF(Project)
+
+TIL_OPCODE_DEF(Call)
+TIL_OPCODE_DEF(Alloc)
+TIL_OPCODE_DEF(Load)
+TIL_OPCODE_DEF(Store)
+TIL_OPCODE_DEF(ArrayFirst)
+TIL_OPCODE_DEF(ArrayAdd)
+
+TIL_OPCODE_DEF(UnaryOp)
+TIL_OPCODE_DEF(BinaryOp)
+TIL_OPCODE_DEF(Cast)
+
+TIL_OPCODE_DEF(SCFG)
+TIL_OPCODE_DEF(Phi)
+TIL_OPCODE_DEF(Goto)
+TIL_OPCODE_DEF(Branch)
diff --git a/include/clang/Analysis/Analyses/ThreadSafetyTIL.h b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
new file mode 100644
index 0000000000..252eb7566e
--- /dev/null
+++ b/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
@@ -0,0 +1,1313 @@
+//===- ThreadSafetyTIL.h ---------------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a simple intermediate language that is used by the
+// thread safety analysis (See ThreadSafety.cpp). The thread safety analysis
+// works by comparing mutex expressions, e.g.
+//
+// class A { Mutex mu; int dat GUARDED_BY(this->mu); }
+// class B { A a; }
+//
+// void foo(B* b) {
+// (*b).a.mu.lock(); // locks (*b).a.mu
+// b->a.dat = 0; // substitute &b->a for 'this';
+// // requires lock on (&b->a)->mu
+// (b->a.mu).unlock(); // unlocks (b->a.mu)
+// }
+//
+// As illustrated by the above example, clang Exprs are not well-suited to
+// represent mutex expressions directly, since there is no easy way to compare
+// Exprs for equivalence. The thread safety analysis thus lowers clang Exprs
+// into a simple intermediate language (IL). The IL supports:
+//
+// (1) comparisons for semantic equality of expressions
+// (2) SSA renaming of variables
+// (3) wildcards and pattern matching over expressions
+// (4) hash-based expression lookup
+//
+// The IL is currently very experimental, is intended only for use within
+// the thread safety analysis, and is subject to change without notice.
+// After the API stabilizes and matures, it may be appropriate to make this
+// more generally available to other analyses.
+//
+// UNDER CONSTRUCTION. USE AT YOUR OWN RISK.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_THREAD_SAFETY_TIL_H
+#define LLVM_CLANG_THREAD_SAFETY_TIL_H
+
+#include "clang/Analysis/Analyses/ThreadSafetyUtil.h"
+#include "clang/AST/ExprCXX.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Compiler.h"
+
+#include <cassert>
+#include <cstddef>
+#include <utility>
+
+
+namespace clang {
+namespace threadSafety {
+namespace til {
+
+using llvm::StringRef;
+using clang::SourceLocation;
+
+
+enum TIL_Opcode {
+#define TIL_OPCODE_DEF(X) COP_##X,
+#include "clang/Analysis/Analyses/ThreadSafetyOps.def"
+#undef TIL_OPCODE_DEF
+ COP_MAX
+};
+
+
+typedef clang::BinaryOperatorKind TIL_BinaryOpcode;
+typedef clang::UnaryOperatorKind TIL_UnaryOpcode;
+typedef clang::CastKind TIL_CastOpcode;
+
+
+enum TraversalKind {
+ TRV_Normal,
+ TRV_Lazy, // subexpression may need to be traversed lazily
+ TRV_Tail // subexpression occurs in a tail position
+};
+
+
+// Base class for AST nodes in the typed intermediate language.
+class SExpr {
+public:
+ TIL_Opcode opcode() const { return static_cast<TIL_Opcode>(Opcode); }
+
+ // Subclasses of SExpr must define the following:
+ //
+ // This(const This& E, ...) {
+ // copy constructor: construct copy of E, with some additional arguments.
+ // }
+ //
+ // template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ // traverse all subexpressions, following the traversal/rewriter interface
+ // }
+ //
+ // template <class C> typename C::CType compare(CType* E, C& Cmp) {
+ // compare all subexpressions, following the comparator interface
+ // }
+
+ void *operator new(size_t S, clang::threadSafety::til::MemRegionRef &R) {
+ return ::operator new(S, R);
+ }
+
+ // SExpr objects cannot be deleted.
+ // This declaration is public to workaround a gcc bug that breaks building
+ // with REQUIRES_EH=1.
+ void operator delete(void *) LLVM_DELETED_FUNCTION;
+
+protected:
+ SExpr(TIL_Opcode Op) : Opcode(Op), Reserved(0), Flags(0) {}
+ SExpr(const SExpr &E) : Opcode(E.Opcode), Reserved(0), Flags(E.Flags) {}
+
+ const unsigned char Opcode;
+ unsigned char Reserved;
+ unsigned short Flags;
+
+private:
+ SExpr() LLVM_DELETED_FUNCTION;
+
+ // SExpr objects must be created in an arena.
+ void *operator new(size_t) LLVM_DELETED_FUNCTION;
+};
+
+
+// Class for owning references to SExprs.
+// Includes attach/detach logic for counting variable references and lazy
+// rewriting strategies.
+class SExprRef {
+public:
+ SExprRef() : Ptr(nullptr) { }
+ SExprRef(std::nullptr_t P) : Ptr(nullptr) { }
+ SExprRef(SExprRef &&R) : Ptr(R.Ptr) { R.Ptr = nullptr; }
+
+ // Defined after Variable and Future, below.
+ inline SExprRef(SExpr *P);
+ inline ~SExprRef();
+
+ SExpr *get() { return Ptr; }
+ const SExpr *get() const { return Ptr; }
+
+ SExpr *operator->() { return get(); }
+ const SExpr *operator->() const { return get(); }
+
+ SExpr &operator*() { return *Ptr; }
+ const SExpr &operator*() const { return *Ptr; }
+
+ bool operator==(const SExprRef &R) const { return Ptr == R.Ptr; }
+ bool operator!=(const SExprRef &R) const { return !operator==(R); }
+ bool operator==(const SExpr *P) const { return Ptr == P; }
+ bool operator!=(const SExpr *P) const { return !operator==(P); }
+ bool operator==(std::nullptr_t) const { return Ptr == nullptr; }
+ bool operator!=(std::nullptr_t) const { return Ptr != nullptr; }
+
+ inline void reset(SExpr *E);
+
+private:
+ inline void attach();
+ inline void detach();
+
+ SExpr *Ptr;
+};
+
+
+// Contains various helper functions for SExprs.
+namespace ThreadSafetyTIL {
+ inline bool isTrivial(const SExpr *E) {
+ unsigned Op = E->opcode();
+ return Op == COP_Variable || Op == COP_Literal || Op == COP_LiteralPtr;
+ }
+}
+
+class Function;
+class SFunction;
+class BasicBlock;
+
+
+// A named variable, e.g. "x".
+//
+// There are two distinct places in which a Variable can appear in the AST.
+// A variable declaration introduces a new variable, and can occur in 3 places:
+// Let-expressions: (Let (x = t) u)
+// Functions: (Function (x : t) u)
+// Self-applicable functions (SFunction (x) t)
+//
+// If a variable occurs in any other location, it is a reference to an existing
+// variable declaration -- e.g. 'x' in (x * y + z). To save space, we don't
+// allocate a separate AST node for variable references; a reference is just a
+// pointer to the original declaration.
+class Variable : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Variable; }
+
+ // Let-variable, function parameter, or self-variable
+ enum VariableKind {
+ VK_Let,
+ VK_Fun,
+ VK_SFun
+ };
+
+ // These are defined after SExprRef contructor, below
+ inline Variable(VariableKind K, SExpr *D = nullptr,
+ const clang::ValueDecl *Cvd = nullptr);
+ inline Variable(SExpr *D = nullptr, const clang::ValueDecl *Cvd = nullptr);
+ inline Variable(const Variable &Vd, SExpr *D);
+
+ VariableKind kind() const { return static_cast<VariableKind>(Flags); }
+
+ const StringRef name() const { return Cvdecl ? Cvdecl->getName() : "_x"; }
+ const clang::ValueDecl *clangDecl() const { return Cvdecl; }
+
+ // Returns the definition (for let vars) or type (for parameter & self vars)
+ SExpr *definition() { return Definition.get(); }
+ const SExpr *definition() const { return Definition.get(); }
+
+ void attachVar() const { ++NumUses; }
+ void detachVar() const { assert(NumUses > 0); --NumUses; }
+
+ unsigned getID() const { return Id; }
+ unsigned getBlockID() const { return BlockID; }
+
+ void setID(unsigned Bid, unsigned I) {
+ BlockID = static_cast<unsigned short>(Bid);
+ Id = static_cast<unsigned short>(I);
+ }
+ void setClangDecl(const clang::ValueDecl *VD) { Cvdecl = VD; }
+ void setDefinition(SExpr *E);
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ // This routine is only called for variable references.
+ return Visitor.reduceVariableRef(this);
+ }
+
+ template <class C> typename C::CType compare(Variable* E, C& Cmp) {
+ return Cmp.compareVariableRefs(this, E);
+ }
+
+private:
+ friend class Function;
+ friend class SFunction;
+ friend class BasicBlock;
+
+ // Function, SFunction, and BasicBlock will reset the kind.
+ void setKind(VariableKind K) { Flags = K; }
+
+ SExprRef Definition; // The TIL type or definition
+ const clang::ValueDecl *Cvdecl; // The clang declaration for this variable.
+
+ unsigned short BlockID;
+ unsigned short Id;
+ mutable unsigned NumUses;
+};
+
+
+// Placeholder for an expression that has not yet been created.
+// Used to implement lazy copy and rewriting strategies.
+class Future : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Future; }
+
+ enum FutureStatus {
+ FS_pending,
+ FS_evaluating,
+ FS_done
+ };
+
+ Future() :
+ SExpr(COP_Future), Status(FS_pending), Result(nullptr), Location(nullptr)
+ {}
+private:
+ virtual ~Future() LLVM_DELETED_FUNCTION;
+public:
+
+ // Registers the location in the AST where this future is stored.
+ // Forcing the future will automatically update the AST.
+ static inline void registerLocation(SExprRef *Member) {
+ if (Future *F = dyn_cast_or_null<Future>(Member->get()))
+ F->Location = Member;
+ }
+
+ // A lazy rewriting strategy should subclass Future and override this method.
+ virtual SExpr *create() { return nullptr; }
+
+ // Return the result of this future if it exists, otherwise return null.
+ SExpr *maybeGetResult() {
+ return Result;
+ }
+
+ // Return the result of this future; forcing it if necessary.
+ SExpr *result() {
+ switch (Status) {
+ case FS_pending:
+ force();
+ return Result;
+ case FS_evaluating:
+ return nullptr; // infinite loop; illegal recursion.
+ case FS_done:
+ return Result;
+ }
+ }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ assert(Result && "Cannot traverse Future that has not been forced.");
+ return Visitor.traverse(Result);
+ }
+
+ template <class C> typename C::CType compare(Future* E, C& Cmp) {
+ if (!Result || !E->Result)
+ return Cmp.comparePointers(this, E);
+ return Cmp.compare(Result, E->Result);
+ }
+
+private:
+ // Force the future.
+ inline void force();
+
+ FutureStatus Status;
+ SExpr *Result;
+ SExprRef *Location;
+};
+
+
+inline void SExprRef::attach() {
+ if (!Ptr)
+ return;
+
+ TIL_Opcode Op = Ptr->opcode();
+ if (Op == COP_Variable) {
+ cast<Variable>(Ptr)->attachVar();
+ } else if (Op == COP_Future) {
+ cast<Future>(Ptr)->registerLocation(this);
+ }
+}
+
+inline void SExprRef::detach() {
+ if (Ptr && Ptr->opcode() == COP_Variable) {
+ cast<Variable>(Ptr)->detachVar();
+ }
+}
+
+inline SExprRef::SExprRef(SExpr *P) : Ptr(P) {
+ attach();
+}
+
+inline SExprRef::~SExprRef() {
+ detach();
+}
+
+inline void SExprRef::reset(SExpr *P) {
+ detach();
+ Ptr = P;
+ attach();
+}
+
+
+inline Variable::Variable(VariableKind K, SExpr *D, const clang::ValueDecl *Cvd)
+ : SExpr(COP_Variable), Definition(D), Cvdecl(Cvd),
+ BlockID(0), Id(0), NumUses(0) {
+ Flags = K;
+}
+
+inline Variable::Variable(SExpr *D, const clang::ValueDecl *Cvd)
+ : SExpr(COP_Variable), Definition(D), Cvdecl(Cvd),
+ BlockID(0), Id(0), NumUses(0) {
+ Flags = VK_Let;
+}
+
+inline Variable::Variable(const Variable &Vd, SExpr *D) // rewrite constructor
+ : SExpr(Vd), Definition(D), Cvdecl(Vd.Cvdecl),
+ BlockID(0), Id(0), NumUses(0) {
+ Flags = Vd.kind();
+}
+
+inline void Variable::setDefinition(SExpr *E) {
+ Definition.reset(E);
+}
+
+void Future::force() {
+ Status = FS_evaluating;
+ SExpr *R = create();
+ Result = R;
+ if (Location)
+ Location->reset(R);
+ Status = FS_done;
+}
+
+
+// Placeholder for C++ expressions that cannot be represented in the TIL.
+class Undefined : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Undefined; }
+
+ Undefined(const clang::Stmt *S = nullptr) : SExpr(COP_Undefined), Cstmt(S) {}
+ Undefined(const Undefined &U) : SExpr(U), Cstmt(U.Cstmt) {}
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ return Visitor.reduceUndefined(*this);
+ }
+
+ template <class C> typename C::CType compare(Undefined* E, C& Cmp) {
+ return Cmp.comparePointers(Cstmt, E->Cstmt);
+ }
+
+private:
+ const clang::Stmt *Cstmt;
+};
+
+
+// Placeholder for a wildcard that matches any other expression.
+class Wildcard : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Wildcard; }
+
+ Wildcard() : SExpr(COP_Wildcard) {}
+ Wildcard(const Wildcard &W) : SExpr(W) {}
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ return Visitor.reduceWildcard(*this);
+ }
+
+ template <class C> typename C::CType compare(Wildcard* E, C& Cmp) {
+ return Cmp.trueResult();
+ }
+};
+
+
+// Base class for literal values.
+class Literal : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Literal; }
+
+ Literal(const clang::Expr *C) : SExpr(COP_Literal), Cexpr(C) {}
+ Literal(const Literal &L) : SExpr(L), Cexpr(L.Cexpr) {}
+
+ // The clang expression for this literal.
+ const clang::Expr *clangExpr() const { return Cexpr; }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ return Visitor.reduceLiteral(*this);
+ }
+
+ template <class C> typename C::CType compare(Literal* E, C& Cmp) {
+ // TODO -- use value, not pointer equality
+ return Cmp.comparePointers(Cexpr, E->Cexpr);
+ }
+
+private:
+ const clang::Expr *Cexpr;
+};
+
+// Literal pointer to an object allocated in memory.
+// At compile time, pointer literals are represented by symbolic names.
+class LiteralPtr : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_LiteralPtr; }
+
+ LiteralPtr(const clang::ValueDecl *D) : SExpr(COP_LiteralPtr), Cvdecl(D) {}
+ LiteralPtr(const LiteralPtr &R) : SExpr(R), Cvdecl(R.Cvdecl) {}
+
+ // The clang declaration for the value that this pointer points to.
+ const clang::ValueDecl *clangDecl() const { return Cvdecl; }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ return Visitor.reduceLiteralPtr(*this);
+ }
+
+ template <class C> typename C::CType compare(LiteralPtr* E, C& Cmp) {
+ return Cmp.comparePointers(Cvdecl, E->Cvdecl);
+ }
+
+private:
+ const clang::ValueDecl *Cvdecl;
+};
+
+// A function -- a.k.a. lambda abstraction.
+// Functions with multiple arguments are created by currying,
+// e.g. (function (x: Int) (function (y: Int) (add x y)))
+class Function : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Function; }
+
+ Function(Variable *Vd, SExpr *Bd)
+ : SExpr(COP_Function), VarDecl(Vd), Body(Bd) {
+ Vd->setKind(Variable::VK_Fun);
+ }
+ Function(const Function &F, Variable *Vd, SExpr *Bd) // rewrite constructor
+ : SExpr(F), VarDecl(Vd), Body(Bd) {
+ Vd->setKind(Variable::VK_Fun);
+ }
+
+ Variable *variableDecl() { return VarDecl; }
+ const Variable *variableDecl() const { return VarDecl; }
+
+ SExpr *body() { return Body.get(); }
+ const SExpr *body() const { return Body.get(); }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ // This is a variable declaration, so traverse the definition.
+ typename V::R_SExpr E0 = Visitor.traverse(VarDecl->Definition, TRV_Lazy);
+ // Tell the rewriter to enter the scope of the function.
+ Variable *Nvd = Visitor.enterScope(*VarDecl, E0);
+ typename V::R_SExpr E1 = Visitor.traverse(Body);
+ Visitor.exitScope(*VarDecl);
+ return Visitor.reduceFunction(*this, Nvd, E1);
+ }
+
+ template <class C> typename C::CType compare(Function* E, C& Cmp) {
+ typename C::CType Ct =
+ Cmp.compare(VarDecl->definition(), E->VarDecl->definition());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ Cmp.enterScope(variableDecl(), E->variableDecl());
+ Ct = Cmp.compare(body(), E->body());
+ Cmp.leaveScope();
+ return Ct;
+ }
+
+private:
+ Variable *VarDecl;
+ SExprRef Body;
+};
+
+
+// A self-applicable function.
+// A self-applicable function can be applied to itself. It's useful for
+// implementing objects and late binding
+class SFunction : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_SFunction; }
+
+ SFunction(Variable *Vd, SExpr *B)
+ : SExpr(COP_SFunction), VarDecl(Vd), Body(B) {
+ assert(Vd->Definition == nullptr);
+ Vd->setKind(Variable::VK_SFun);
+ Vd->Definition.reset(this);
+ }
+ SFunction(const SFunction &F, Variable *Vd, SExpr *B) // rewrite constructor
+ : SExpr(F), VarDecl(Vd), Body(B) {
+ assert(Vd->Definition == nullptr);
+ Vd->setKind(Variable::VK_SFun);
+ Vd->Definition.reset(this);
+ }
+
+ Variable *variableDecl() { return VarDecl; }
+ const Variable *variableDecl() const { return VarDecl; }
+
+ SExpr *body() { return Body.get(); }
+ const SExpr *body() const { return Body.get(); }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ // A self-variable points to the SFunction itself.
+ // A rewrite must introduce the variable with a null definition, and update
+ // it after 'this' has been rewritten.
+ Variable *Nvd = Visitor.enterScope(*VarDecl, nullptr /* def */);
+ typename V::R_SExpr E1 = Visitor.traverse(Body);
+ Visitor.exitScope(*VarDecl);
+ // A rewrite operation will call SFun constructor to set Vvd->Definition.
+ return Visitor.reduceSFunction(*this, Nvd, E1);
+ }
+
+ template <class C> typename C::CType compare(SFunction* E, C& Cmp) {
+ Cmp.enterScope(variableDecl(), E->variableDecl());
+ typename C::CType Ct = Cmp.compare(body(), E->body());
+ Cmp.leaveScope();
+ return Ct;
+ }
+
+private:
+ Variable *VarDecl;
+ SExprRef Body;
+};
+
+
+// A block of code -- e.g. the body of a function.
+class Code : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Code; }
+
+ Code(SExpr *T, SExpr *B) : SExpr(COP_Code), ReturnType(T), Body(B) {}
+ Code(const Code &C, SExpr *T, SExpr *B) // rewrite constructor
+ : SExpr(C), ReturnType(T), Body(B) {}
+
+ SExpr *returnType() { return ReturnType.get(); }
+ const SExpr *returnType() const { return ReturnType.get(); }
+
+ SExpr *body() { return Body.get(); }
+ const SExpr *body() const { return Body.get(); }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ typename V::R_SExpr Nt = Visitor.traverse(ReturnType, TRV_Lazy);
+ typename V::R_SExpr Nb = Visitor.traverse(Body, TRV_Lazy);
+ return Visitor.reduceCode(*this, Nt, Nb);
+ }
+
+ template <class C> typename C::CType compare(Code* E, C& Cmp) {
+ typename C::CType Ct = Cmp.compare(returnType(), E->returnType());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(body(), E->body());
+ }
+
+private:
+ SExprRef ReturnType;
+ SExprRef Body;
+};
+
+
+// Apply an argument to a function
+class Apply : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Apply; }
+
+ Apply(SExpr *F, SExpr *A) : SExpr(COP_Apply), Fun(F), Arg(A) {}
+ Apply(const Apply &A, SExpr *F, SExpr *Ar) // rewrite constructor
+ : SExpr(A), Fun(F), Arg(Ar)
+ {}
+
+ SExpr *fun() { return Fun.get(); }
+ const SExpr *fun() const { return Fun.get(); }
+
+ SExpr *arg() { return Arg.get(); }
+ const SExpr *arg() const { return Arg.get(); }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ typename V::R_SExpr Nf = Visitor.traverse(Fun);
+ typename V::R_SExpr Na = Visitor.traverse(Arg);
+ return Visitor.reduceApply(*this, Nf, Na);
+ }
+
+ template <class C> typename C::CType compare(Apply* E, C& Cmp) {
+ typename C::CType Ct = Cmp.compare(fun(), E->fun());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(arg(), E->arg());
+ }
+
+private:
+ SExprRef Fun;
+ SExprRef Arg;
+};
+
+
+// Apply a self-argument to a self-applicable function
+class SApply : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_SApply; }
+
+ SApply(SExpr *Sf, SExpr *A = nullptr) : SExpr(COP_SApply), Sfun(Sf), Arg(A) {}
+ SApply(SApply &A, SExpr *Sf, SExpr *Ar = nullptr) // rewrite constructor
+ : SExpr(A), Sfun(Sf), Arg(Ar) {}
+
+ SExpr *sfun() { return Sfun.get(); }
+ const SExpr *sfun() const { return Sfun.get(); }
+
+ SExpr *arg() { return Arg.get() ? Arg.get() : Sfun.get(); }
+ const SExpr *arg() const { return Arg.get() ? Arg.get() : Sfun.get(); }
+
+ bool isDelegation() const { return Arg == nullptr; }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ typename V::R_SExpr Nf = Visitor.traverse(Sfun);
+ typename V::R_SExpr Na = Arg.get() ? Visitor.traverse(Arg) : nullptr;
+ return Visitor.reduceSApply(*this, Nf, Na);
+ }
+
+ template <class C> typename C::CType compare(SApply* E, C& Cmp) {
+ typename C::CType Ct = Cmp.compare(sfun(), E->sfun());
+ if (Cmp.notTrue(Ct) || (!arg() && !E->arg()))
+ return Ct;
+ return Cmp.compare(arg(), E->arg());
+ }
+
+private:
+ SExprRef Sfun;
+ SExprRef Arg;
+};
+
+
+// Project a named slot from a C++ struct or class.
+class Project : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Project; }
+
+ Project(SExpr *R, clang::ValueDecl *Cvd)
+ : SExpr(COP_Project), Rec(R), Cvdecl(Cvd) {}
+ Project(const Project &P, SExpr *R) : SExpr(P), Rec(R), Cvdecl(P.Cvdecl) {}
+
+ SExpr *record() { return Rec.get(); }
+ const SExpr *record() const { return Rec.get(); }
+
+ const clang::ValueDecl *clangValueDecl() const { return Cvdecl; }
+
+ StringRef slotName() const { return Cvdecl->getName(); }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ typename V::R_SExpr Nr = Visitor.traverse(Rec);
+ return Visitor.reduceProject(*this, Nr);
+ }
+
+ template <class C> typename C::CType compare(Project* E, C& Cmp) {
+ typename C::CType Ct = Cmp.compare(record(), E->record());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.comparePointers(Cvdecl, E->Cvdecl);
+ }
+
+private:
+ SExprRef Rec;
+ clang::ValueDecl *Cvdecl;
+};
+
+
+// Call a function (after all arguments have been applied).
+class Call : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Call; }
+
+ Call(SExpr *T, const clang::CallExpr *Ce = nullptr)
+ : SExpr(COP_Call), Target(T), Cexpr(Ce) {}
+ Call(const Call &C, SExpr *T) : SExpr(C), Target(T), Cexpr(C.Cexpr) {}
+
+ SExpr *target() { return Target.get(); }
+ const SExpr *target() const { return Target.get(); }
+
+ const clang::CallExpr *clangCallExpr() const { return Cexpr; }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ typename V::R_SExpr Nt = Visitor.traverse(Target);
+ return Visitor.reduceCall(*this, Nt);
+ }
+
+ template <class C> typename C::CType compare(Call* E, C& Cmp) {
+ return Cmp.compare(target(), E->target());
+ }
+
+private:
+ SExprRef Target;
+ const clang::CallExpr *Cexpr;
+};
+
+
+// Allocate memory for a new value on the heap or stack.
+class Alloc : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Call; }
+
+ enum AllocKind {
+ AK_Stack,
+ AK_Heap
+ };
+
+ Alloc(SExpr *D, AllocKind K) : SExpr(COP_Alloc), Dtype(D) { Flags = K; }
+ Alloc(const Alloc &A, SExpr *Dt) : SExpr(A), Dtype(Dt) { Flags = A.kind(); }
+
+ AllocKind kind() const { return static_cast<AllocKind>(Flags); }
+
+ SExpr *dataType() { return Dtype.get(); }
+ const SExpr *dataType() const { return Dtype.get(); }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ typename V::R_SExpr Nd = Visitor.traverse(Dtype);
+ return Visitor.reduceAlloc(*this, Nd);
+ }
+
+ template <class C> typename C::CType compare(Alloc* E, C& Cmp) {
+ typename C::CType Ct = Cmp.compareIntegers(kind(), E->kind());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(dataType(), E->dataType());
+ }
+
+private:
+ SExprRef Dtype;
+};
+
+
+// Load a value from memory.
+class Load : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Load; }
+
+ Load(SExpr *P) : SExpr(COP_Load), Ptr(P) {}
+ Load(const Load &L, SExpr *P) : SExpr(L), Ptr(P) {}
+
+ SExpr *pointer() { return Ptr.get(); }
+ const SExpr *pointer() const { return Ptr.get(); }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ typename V::R_SExpr Np = Visitor.traverse(Ptr);
+ return Visitor.reduceLoad(*this, Np);
+ }
+
+ template <class C> typename C::CType compare(Load* E, C& Cmp) {
+ return Cmp.compare(pointer(), E->pointer());
+ }
+
+private:
+ SExprRef Ptr;
+};
+
+
+// Store a value to memory.
+// Source is a pointer, destination is the value to store.
+class Store : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Store; }
+
+ Store(SExpr *P, SExpr *V) : SExpr(COP_Store), Dest(P), Source(V) {}
+ Store(const Store &S, SExpr *P, SExpr *V) : SExpr(S), Dest(P), Source(V) {}
+
+ SExpr *destination() { return Dest.get(); } // Address to store to
+ const SExpr *destination() const { return Dest.get(); }
+
+ SExpr *source() { return Source.get(); } // Value to store
+ const SExpr *source() const { return Source.get(); }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ typename V::R_SExpr Np = Visitor.traverse(Dest);
+ typename V::R_SExpr Nv = Visitor.traverse(Source);
+ return Visitor.reduceStore(*this, Np, Nv);
+ }
+
+ template <class C> typename C::CType compare(Store* E, C& Cmp) {
+ typename C::CType Ct = Cmp.compare(destination(), E->destination());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(source(), E->source());
+ }
+
+private:
+ SExprRef Dest;
+ SExprRef Source;
+};
+
+
+// If p is a reference to an array, then first(p) is a reference to the first
+// element. The usual array notation p[i] becomes first(p + i).
+class ArrayFirst : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayFirst; }
+
+ ArrayFirst(SExpr *A) : SExpr(COP_ArrayFirst), Array(A) {}
+ ArrayFirst(const ArrayFirst &E, SExpr *A) : SExpr(E), Array(A) {}
+
+ SExpr *array() { return Array.get(); }
+ const SExpr *array() const { return Array.get(); }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ typename V::R_SExpr Na = Visitor.traverse(Array);
+ return Visitor.reduceArrayFirst(*this, Na);
+ }
+
+ template <class C> typename C::CType compare(ArrayFirst* E, C& Cmp) {
+ return Cmp.compare(array(), E->array());
+ }
+
+private:
+ SExprRef Array;
+};
+
+
+// Pointer arithmetic, restricted to arrays only.
+// If p is a reference to an array, then p + n, where n is an integer, is
+// a reference to a subarray.
+class ArrayAdd : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_ArrayAdd; }
+
+ ArrayAdd(SExpr *A, SExpr *N) : SExpr(COP_ArrayAdd), Array(A), Index(N) {}
+ ArrayAdd(const ArrayAdd &E, SExpr *A, SExpr *N)
+ : SExpr(E), Array(A), Index(N) {}
+
+ SExpr *array() { return Array.get(); }
+ const SExpr *array() const { return Array.get(); }
+
+ SExpr *index() { return Index.get(); }
+ const SExpr *index() const { return Index.get(); }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ typename V::R_SExpr Na = Visitor.traverse(Array);
+ typename V::R_SExpr Ni = Visitor.traverse(Index);
+ return Visitor.reduceArrayAdd(*this, Na, Ni);
+ }
+
+ template <class C> typename C::CType compare(ArrayAdd* E, C& Cmp) {
+ typename C::CType Ct = Cmp.compare(array(), E->array());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(index(), E->index());
+ }
+
+private:
+ SExprRef Array;
+ SExprRef Index;
+};
+
+
+// Simple unary operation -- e.g. !, ~, etc.
+class UnaryOp : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_UnaryOp; }
+
+ UnaryOp(TIL_UnaryOpcode Op, SExpr *E) : SExpr(COP_UnaryOp), Expr0(E) {
+ Flags = Op;
+ }
+ UnaryOp(const UnaryOp &U, SExpr *E) : SExpr(U), Expr0(E) { Flags = U.Flags; }
+
+ TIL_UnaryOpcode unaryOpcode() const {
+ return static_cast<TIL_UnaryOpcode>(Flags);
+ }
+
+ SExpr *expr() { return Expr0.get(); }
+ const SExpr *expr() const { return Expr0.get(); }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ typename V::R_SExpr Ne = Visitor.traverse(Expr0);
+ return Visitor.reduceUnaryOp(*this, Ne);
+ }
+
+ template <class C> typename C::CType compare(UnaryOp* E, C& Cmp) {
+ typename C::CType Ct =
+ Cmp.compareIntegers(unaryOpcode(), E->unaryOpcode());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(expr(), E->expr());
+ }
+
+private:
+ SExprRef Expr0;
+};
+
+
+// Simple binary operation -- e.g. +, -, etc.
+class BinaryOp : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_BinaryOp; }
+
+ BinaryOp(TIL_BinaryOpcode Op, SExpr *E0, SExpr *E1)
+ : SExpr(COP_BinaryOp), Expr0(E0), Expr1(E1) {
+ Flags = Op;
+ }
+ BinaryOp(const BinaryOp &B, SExpr *E0, SExpr *E1)
+ : SExpr(B), Expr0(E0), Expr1(E1) {
+ Flags = B.Flags;
+ }
+
+ TIL_BinaryOpcode binaryOpcode() const {
+ return static_cast<TIL_BinaryOpcode>(Flags);
+ }
+
+ SExpr *expr0() { return Expr0.get(); }
+ const SExpr *expr0() const { return Expr0.get(); }
+
+ SExpr *expr1() { return Expr1.get(); }
+ const SExpr *expr1() const { return Expr1.get(); }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ typename V::R_SExpr Ne0 = Visitor.traverse(Expr0);
+ typename V::R_SExpr Ne1 = Visitor.traverse(Expr1);
+ return Visitor.reduceBinaryOp(*this, Ne0, Ne1);
+ }
+
+ template <class C> typename C::CType compare(BinaryOp* E, C& Cmp) {
+ typename C::CType Ct =
+ Cmp.compareIntegers(binaryOpcode(), E->binaryOpcode());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ Ct = Cmp.compare(expr0(), E->expr0());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(expr1(), E->expr1());
+ }
+
+private:
+ SExprRef Expr0;
+ SExprRef Expr1;
+};
+
+
+// Cast expression
+class Cast : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Cast; }
+
+ Cast(TIL_CastOpcode Op, SExpr *E) : SExpr(COP_Cast), Expr0(E) { Flags = Op; }
+ Cast(const Cast &C, SExpr *E) : SExpr(C), Expr0(E) { Flags = C.Flags; }
+
+ TIL_CastOpcode castOpcode() const {
+ return static_cast<TIL_CastOpcode>(Flags);
+ }
+
+ SExpr *expr() { return Expr0.get(); }
+ const SExpr *expr() const { return Expr0.get(); }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ typename V::R_SExpr Ne = Visitor.traverse(Expr0);
+ return Visitor.reduceCast(*this, Ne);
+ }
+
+ template <class C> typename C::CType compare(Cast* E, C& Cmp) {
+ typename C::CType Ct =
+ Cmp.compareIntegers(castOpcode(), E->castOpcode());
+ if (Cmp.notTrue(Ct))
+ return Ct;
+ return Cmp.compare(expr(), E->expr());
+ }
+
+private:
+ SExprRef Expr0;
+};
+
+
+
+class BasicBlock;
+
+// An SCFG is a control-flow graph. It consists of a set of basic blocks, each
+// of which terminates in a branch to another basic block. There is one
+// entry point, and one exit point.
+class SCFG : public SExpr {
+public:
+ typedef SimpleArray<BasicBlock *> BlockArray;
+ typedef BlockArray::iterator iterator;
+ typedef BlockArray::const_iterator const_iterator;
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_SCFG; }
+
+ SCFG(MemRegionRef A, unsigned Nblocks)
+ : SExpr(COP_SCFG), Blocks(A, Nblocks),
+ Entry(nullptr), Exit(nullptr) {}
+ SCFG(const SCFG &Cfg, BlockArray &&Ba) // steals memory from Ba
+ : SExpr(COP_SCFG), Blocks(std::move(Ba)), Entry(nullptr), Exit(nullptr) {
+ // TODO: set entry and exit!
+ }
+
+ iterator begin() { return Blocks.begin(); }
+ iterator end() { return Blocks.end(); }
+
+ const_iterator begin() const { return cbegin(); }
+ const_iterator end() const { return cend(); }
+
+ const_iterator cbegin() const { return Blocks.cbegin(); }
+ const_iterator cend() const { return Blocks.cend(); }
+
+ const BasicBlock *entry() const { return Entry; }
+ BasicBlock *entry() { return Entry; }
+ const BasicBlock *exit() const { return Exit; }
+ BasicBlock *exit() { return Exit; }
+
+ void add(BasicBlock *BB);
+ void setEntry(BasicBlock *BB) { Entry = BB; }
+ void setExit(BasicBlock *BB) { Exit = BB; }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor);
+
+ template <class C> typename C::CType compare(SCFG *E, C &Cmp) {
+ // TODO -- implement CFG comparisons
+ return Cmp.comparePointers(this, E);
+ }
+
+private:
+ BlockArray Blocks;
+ BasicBlock *Entry;
+ BasicBlock *Exit;
+};
+
+
+// A basic block is part of an SCFG, and can be treated as a function in
+// continuation passing style. It consists of a sequence of phi nodes, which
+// are "arguments" to the function, followed by a sequence of instructions.
+// Both arguments and instructions define new variables. It ends with a
+// branch or goto to another basic block in the same SCFG.
+class BasicBlock {
+public:
+ typedef SimpleArray<Variable*> VarArray;
+
+ BasicBlock(MemRegionRef A, unsigned Nargs, unsigned Nins,
+ SExpr *Term = nullptr)
+ : BlockID(0), NumVars(0), NumPredecessors(0), Parent(nullptr),
+ Args(A, Nargs), Instrs(A, Nins), Terminator(Term) {}
+ BasicBlock(const BasicBlock &B, VarArray &&As, VarArray &&Is, SExpr *T)
+ : BlockID(0), NumVars(B.NumVars), NumPredecessors(B.NumPredecessors),
+ Parent(nullptr), Args(std::move(As)), Instrs(std::move(Is)),
+ Terminator(T) {}
+
+ unsigned blockID() const { return BlockID; }
+ unsigned numPredecessors() const { return NumPredecessors; }
+
+ const BasicBlock *parent() const { return Parent; }
+ BasicBlock *parent() { return Parent; }
+
+ const VarArray &arguments() const { return Args; }
+ VarArray &arguments() { return Args; }
+
+ const VarArray &instructions() const { return Instrs; }
+ VarArray &instructions() { return Instrs; }
+
+ const SExpr *terminator() const { return Terminator.get(); }
+ SExpr *terminator() { return Terminator.get(); }
+
+ void setBlockID(unsigned i) { BlockID = i; }
+ void setParent(BasicBlock *P) { Parent = P; }
+ void setNumPredecessors(unsigned NP) { NumPredecessors = NP; }
+ void setTerminator(SExpr *E) { Terminator.reset(E); }
+
+ void addArgument(Variable *V) {
+ V->setID(BlockID, NumVars++);
+ Args.push_back(V);
+ }
+ void addInstruction(Variable *V) {
+ V->setID(BlockID, NumVars++);
+ Instrs.push_back(V);
+ }
+
+ template <class V> BasicBlock *traverse(V &Visitor) {
+ typename V::template Container<Variable*> Nas(Visitor, Args.size());
+ typename V::template Container<Variable*> Nis(Visitor, Instrs.size());
+
+ for (auto *A : Args) {
+ typename V::R_SExpr Ne = Visitor.traverse(A->Definition);
+ Variable *Nvd = Visitor.enterScope(*A, Ne);
+ Nas.push_back(Nvd);
+ }
+ for (auto *I : Instrs) {
+ typename V::R_SExpr Ne = Visitor.traverse(I->Definition);
+ Variable *Nvd = Visitor.enterScope(*I, Ne);
+ Nis.push_back(Nvd);
+ }
+ typename V::R_SExpr Nt = Visitor.traverse(Terminator);
+
+ // TODO: use reverse iterator
+ for (unsigned J = 0, JN = Instrs.size(); J < JN; ++J)
+ Visitor.exitScope(*Instrs[JN-J]);
+ for (unsigned I = 0, IN = Instrs.size(); I < IN; ++I)
+ Visitor.exitScope(*Args[IN-I]);
+
+ return Visitor.reduceBasicBlock(*this, Nas, Nis, Nt);
+ }
+
+ template <class C> typename C::CType compare(BasicBlock *E, C &Cmp) {
+ // TODO: implement CFG comparisons
+ return Cmp.comparePointers(this, E);
+ }
+
+private:
+ friend class SCFG;
+
+ unsigned BlockID;
+ unsigned NumVars;
+ unsigned NumPredecessors; // Number of blocks which jump to this one.
+
+ BasicBlock *Parent; // The parent block is the enclosing lexical scope.
+ // The parent dominates this block.
+ VarArray Args; // Phi nodes. One argument per predecessor.
+ VarArray Instrs;
+ SExprRef Terminator;
+};
+
+
+inline void SCFG::add(BasicBlock *BB) {
+ BB->setBlockID(Blocks.size());
+ Blocks.push_back(BB);
+}
+
+
+template <class V>
+typename V::R_SExpr SCFG::traverse(V &Visitor) {
+ Visitor.enterCFG(*this);
+ typename V::template Container<BasicBlock *> Bbs(Visitor, Blocks.size());
+ for (auto *B : Blocks) {
+ BasicBlock *Nbb = B->traverse(Visitor);
+ Bbs.push_back(Nbb);
+ }
+ Visitor.exitCFG(*this);
+ return Visitor.reduceSCFG(*this, Bbs);
+}
+
+
+class Phi : public SExpr {
+public:
+ // TODO: change to SExprRef
+ typedef SimpleArray<SExpr *> ValArray;
+
+ // In minimal SSA form, all Phi nodes are MultiVal.
+ // During conversion to SSA, incomplete Phi nodes may be introduced, which
+ // are later determined to be SingleVal.
+ enum Status {
+ PH_MultiVal = 0, // Phi node has multiple distinct values. (Normal)
+ PH_SingleVal, // Phi node has one distinct value, and can be eliminated
+ PH_Incomplete // Phi node is incomplete
+ };
+
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Phi; }
+
+ Phi(MemRegionRef A, unsigned Nvals) : SExpr(COP_Phi), Values(A, Nvals) {}
+ Phi(const Phi &P, ValArray &&Vs) // steals memory of Vs
+ : SExpr(COP_Phi), Values(std::move(Vs)) {}
+
+ const ValArray &values() const { return Values; }
+ ValArray &values() { return Values; }
+
+ Status status() const { return static_cast<Status>(Flags); }
+ void setStatus(Status s) { Flags = s; }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ typename V::template Container<typename V::R_SExpr> Nvs(Visitor,
+ Values.size());
+ for (auto *Val : Values) {
+ typename V::R_SExpr Nv = Visitor.traverse(Val);
+ Nvs.push_back(Nv);
+ }
+ return Visitor.reducePhi(*this, Nvs);
+ }
+
+ template <class C> typename C::CType compare(Phi *E, C &Cmp) {
+ // TODO: implement CFG comparisons
+ return Cmp.comparePointers(this, E);
+ }
+
+private:
+ ValArray Values;
+};
+
+
+class Goto : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Goto; }
+
+ Goto(BasicBlock *B, unsigned Index)
+ : SExpr(COP_Goto), TargetBlock(B), Index(0) {}
+ Goto(const Goto &G, BasicBlock *B, unsigned I)
+ : SExpr(COP_Goto), TargetBlock(B), Index(I) {}
+
+ const BasicBlock *targetBlock() const { return TargetBlock; }
+ BasicBlock *targetBlock() { return TargetBlock; }
+
+ unsigned index() const { return Index; }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ // TODO -- rewrite indices properly
+ BasicBlock *Ntb = Visitor.reduceBasicBlockRef(TargetBlock);
+ return Visitor.reduceGoto(*this, Ntb, Index);
+ }
+
+ template <class C> typename C::CType compare(Goto *E, C &Cmp) {
+ // TODO -- implement CFG comparisons
+ return Cmp.comparePointers(this, E);
+ }
+
+private:
+ BasicBlock *TargetBlock;
+ unsigned Index; // Index into Phi nodes of target block.
+};
+
+
+class Branch : public SExpr {
+public:
+ static bool classof(const SExpr *E) { return E->opcode() == COP_Branch; }
+
+ Branch(SExpr *C, BasicBlock *T, BasicBlock *E)
+ : SExpr(COP_Branch), Condition(C), ThenBlock(T), ElseBlock(E),
+ ThenIndex(0), ElseIndex(0)
+ {}
+ Branch(const Branch &Br, SExpr *C, BasicBlock *T, BasicBlock *E)
+ : SExpr(COP_Branch), Condition(C), ThenBlock(T), ElseBlock(E),
+ ThenIndex(0), ElseIndex(0)
+ {}
+
+ const SExpr *condition() const { return Condition; }
+ SExpr *condition() { return Condition; }
+
+ const BasicBlock *thenBlock() const { return ThenBlock; }
+ BasicBlock *thenBlock() { return ThenBlock; }
+
+ const BasicBlock *elseBlock() const { return ElseBlock; }
+ BasicBlock *elseBlock() { return ElseBlock; }
+
+ unsigned thenIndex() const { return ThenIndex; }
+ unsigned elseIndex() const { return ElseIndex; }
+
+ template <class V> typename V::R_SExpr traverse(V &Visitor) {
+ typename V::R_SExpr Nc = Visitor.traverse(Condition);
+ BasicBlock *Ntb = Visitor.reduceBasicBlockRef(ThenBlock);
+ BasicBlock *Nte = Visitor.reduceBasicBlockRef(ElseBlock);
+ return Visitor.reduceBranch(*this, Nc, Ntb, Nte);
+ }
+
+ template <class C> typename C::CType compare(Branch *E, C &Cmp) {
+ // TODO -- implement CFG comparisons
+ return Cmp.comparePointers(this, E);
+ }
+
+private:
+ SExpr *Condition;
+ BasicBlock *ThenBlock;
+ BasicBlock *ElseBlock;
+ unsigned ThenIndex;
+ unsigned ElseIndex;
+};
+
+
+SExpr *getCanonicalVal(SExpr *E);
+void simplifyIncompleteArg(Variable *V, til::Phi *Ph);
+
+
+
+
+} // end namespace til
+} // end namespace threadSafety
+} // end namespace clang
+
+#endif // LLVM_CLANG_THREAD_SAFETY_TIL_H
diff --git a/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h b/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
new file mode 100644
index 0000000000..f7b94d5a4a
--- /dev/null
+++ b/include/clang/Analysis/Analyses/ThreadSafetyTraverse.h
@@ -0,0 +1,762 @@
+//===- ThreadSafetyTraverse.h ----------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a framework for doing generic traversals and rewriting
+// operations over the Thread Safety TIL.
+//
+// UNDER CONSTRUCTION. USE AT YOUR OWN RISK.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_THREAD_SAFETY_TRAVERSE_H
+#define LLVM_CLANG_THREAD_SAFETY_TRAVERSE_H
+
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+
+namespace clang {
+namespace threadSafety {
+namespace til {
+
+// Defines an interface used to traverse SExprs. Traversals have been made as
+// generic as possible, and are intended to handle any kind of pass over the
+// AST, e.g. visiters, copying, non-destructive rewriting, destructive
+// (in-place) rewriting, hashing, typing, etc.
+//
+// Traversals implement the functional notion of a "fold" operation on SExprs.
+// Each SExpr class provides a traverse method, which does the following:
+// * e->traverse(v):
+// // compute a result r_i for each subexpression e_i
+// for (i = 1..n) r_i = v.traverse(e_i);
+// // combine results into a result for e, where X is the class of e
+// return v.reduceX(*e, r_1, .. r_n).
+//
+// A visitor can control the traversal by overriding the following methods:
+// * v.traverse(e):
+// return v.traverseByCase(e), which returns v.traverseX(e)
+// * v.traverseX(e): (X is the class of e)
+// return e->traverse(v).
+// * v.reduceX(*e, r_1, .. r_n):
+// compute a result for a node of type X
+//
+// The reduceX methods control the kind of traversal (visitor, copy, etc.).
+// These are separated into a separate class R for the purpose of code reuse.
+// The full reducer interface also has methods to handle scopes
+template <class Self, class R> class Traversal : public R {
+public:
+ Self *self() { return reinterpret_cast<Self *>(this); }
+
+ // Traverse an expression -- returning a result of type R_SExpr.
+ // Override this method to do something for every expression, regardless
+ // of which kind it is. TraversalKind indicates the context in which
+ // the expression occurs, and can be:
+ // TRV_Normal
+ // TRV_Lazy -- e may need to be traversed lazily, using a Future.
+ // TRV_Tail -- e occurs in a tail position
+ typename R::R_SExpr traverse(SExprRef &E, TraversalKind K = TRV_Normal) {
+ return traverse(E.get(), K);
+ }
+
+ typename R::R_SExpr traverse(SExpr *E, TraversalKind K = TRV_Normal) {
+ return traverseByCase(E);
+ }
+
+ // Helper method to call traverseX(e) on the appropriate type.
+ typename R::R_SExpr traverseByCase(SExpr *E) {
+ switch (E->opcode()) {
+#define TIL_OPCODE_DEF(X) \
+ case COP_##X: \
+ return self()->traverse##X(cast<X>(E));
+#include "clang/Analysis/Analyses/ThreadSafetyOps.def"
+#undef TIL_OPCODE_DEF
+ case COP_MAX:
+ return self()->reduceNull();
+ }
+ }
+
+// Traverse e, by static dispatch on the type "X" of e.
+// Override these methods to do something for a particular kind of term.
+#define TIL_OPCODE_DEF(X) \
+ typename R::R_SExpr traverse##X(X *e) { return e->traverse(*self()); }
+#include "clang/Analysis/Analyses/ThreadSafetyOps.def"
+#undef TIL_OPCODE_DEF
+};
+
+
+// Implements a Reducer that makes a deep copy of an SExpr.
+// The default behavior of reduce##X(...) is to create a copy of the original.
+// Subclasses can override reduce##X to implement non-destructive rewriting
+// passes.
+class CopyReducer {
+public:
+ CopyReducer() {}
+
+ void setArena(MemRegionRef A) { Arena = A; }
+
+ // R_SExpr is the result type for a traversal.
+ // A copy or non-destructive rewrite returns a newly allocated term.
+ typedef SExpr *R_SExpr;
+
+ // Container is a minimal interface used to store results when traversing
+ // SExprs of variable arity, such as Phi, Goto, and SCFG.
+ template <class T> class Container {
+ public:
+ // Allocate a new container with a capacity for n elements.
+ Container(CopyReducer &R, unsigned N) : Elems(R.Arena, N) {}
+
+ // Push a new element onto the container.
+ void push_back(T E) { Elems.push_back(E); }
+
+ private:
+ friend class CopyReducer;
+ SimpleArray<T> Elems;
+ };
+
+public:
+ R_SExpr reduceNull() {
+ return nullptr;
+ }
+ // R_SExpr reduceFuture(...) is never used.
+
+ R_SExpr reduceUndefined(Undefined &Orig) {
+ return new (Arena) Undefined(Orig);
+ }
+ R_SExpr reduceWildcard(Wildcard &Orig) {
+ return new (Arena) Wildcard(Orig);
+ }
+
+ R_SExpr reduceLiteral(Literal &Orig) {
+ return new (Arena) Literal(Orig);
+ }
+ R_SExpr reduceLiteralPtr(LiteralPtr &Orig) {
+ return new (Arena) LiteralPtr(Orig);
+ }
+
+ R_SExpr reduceFunction(Function &Orig, Variable *Nvd, R_SExpr E0) {
+ return new (Arena) Function(Orig, Nvd, E0);
+ }
+ R_SExpr reduceSFunction(SFunction &Orig, Variable *Nvd, R_SExpr E0) {
+ return new (Arena) SFunction(Orig, Nvd, E0);
+ }
+ R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) {
+ return new (Arena) Code(Orig, E0, E1);
+ }
+
+ R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) {
+ return new (Arena) Apply(Orig, E0, E1);
+ }
+ R_SExpr reduceSApply(SApply &Orig, R_SExpr E0, R_SExpr E1) {
+ return new (Arena) SApply(Orig, E0, E1);
+ }
+ R_SExpr reduceProject(Project &Orig, R_SExpr E0) {
+ return new (Arena) Project(Orig, E0);
+ }
+ R_SExpr reduceCall(Call &Orig, R_SExpr E0) {
+ return new (Arena) Call(Orig, E0);
+ }
+
+ R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) {
+ return new (Arena) Alloc(Orig, E0);
+ }
+ R_SExpr reduceLoad(Load &Orig, R_SExpr E0) {
+ return new (Arena) Load(Orig, E0);
+ }
+ R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) {
+ return new (Arena) Store(Orig, E0, E1);
+ }
+ R_SExpr reduceArrayFirst(ArrayFirst &Orig, R_SExpr E0) {
+ return new (Arena) ArrayFirst(Orig, E0);
+ }
+ R_SExpr reduceArrayAdd(ArrayAdd &Orig, R_SExpr E0, R_SExpr E1) {
+ return new (Arena) ArrayAdd(Orig, E0, E1);
+ }
+ R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) {
+ return new (Arena) UnaryOp(Orig, E0);
+ }
+ R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1) {
+ return new (Arena) BinaryOp(Orig, E0, E1);
+ }
+ R_SExpr reduceCast(Cast &Orig, R_SExpr E0) {
+ return new (Arena) Cast(Orig, E0);
+ }
+
+ R_SExpr reduceSCFG(SCFG &Orig, Container<BasicBlock *> &Bbs) {
+ return new (Arena) SCFG(Orig, std::move(Bbs.Elems));
+ }
+ R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &As) {
+ return new (Arena) Phi(Orig, std::move(As.Elems));
+ }
+ R_SExpr reduceGoto(Goto &Orig, BasicBlock *B, unsigned Index) {
+ return new (Arena) Goto(Orig, B, Index);
+ }
+ R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) {
+ return new (Arena) Branch(O, C, B0, B1);
+ }
+
+ BasicBlock *reduceBasicBlock(BasicBlock &Orig, Container<Variable *> &As,
+ Container<Variable *> &Is, R_SExpr T) {
+ return new (Arena) BasicBlock(Orig, std::move(As.Elems),
+ std::move(Is.Elems), T);
+ }
+
+ // Create a new variable from orig, and push it onto the lexical scope.
+ Variable *enterScope(Variable &Orig, R_SExpr E0) {
+ return new (Arena) Variable(Orig, E0);
+ }
+ // Exit the lexical scope of orig.
+ void exitScope(const Variable &Orig) {}
+
+ void enterCFG(SCFG &Cfg) {}
+ void exitCFG(SCFG &Cfg) {}
+
+ // Map Variable references to their rewritten definitions.
+ Variable *reduceVariableRef(Variable *Ovd) { return Ovd; }
+
+ // Map BasicBlock references to their rewritten defs.
+ BasicBlock *reduceBasicBlockRef(BasicBlock *Obb) { return Obb; }
+
+private:
+ MemRegionRef Arena;
+};
+
+
+class SExprCopier : public Traversal<SExprCopier, CopyReducer> {
+public:
+ SExprCopier(MemRegionRef A) { setArena(A); }
+
+ // Create a copy of e in region a.
+ static SExpr *copy(SExpr *E, MemRegionRef A) {
+ SExprCopier Copier(A);
+ return Copier.traverse(E);
+ }
+};
+
+
+// Implements a Reducer that visits each subexpression, and returns either
+// true or false.
+class VisitReducer {
+public:
+ VisitReducer() {}
+
+ // A visitor returns a bool, representing success or failure.
+ typedef bool R_SExpr;
+
+ // A visitor "container" is a single bool, which accumulates success.
+ template <class T> class Container {
+ public:
+ Container(VisitReducer &R, unsigned N) : Success(true) {}
+ void push_back(bool E) { Success = Success && E; }
+
+ private:
+ friend class VisitReducer;
+ bool Success;
+ };
+
+public:
+ R_SExpr reduceNull() { return true; }
+ R_SExpr reduceUndefined(Undefined &Orig) { return true; }
+ R_SExpr reduceWildcard(Wildcard &Orig) { return true; }
+
+ R_SExpr reduceLiteral(Literal &Orig) { return true; }
+ R_SExpr reduceLiteralPtr(Literal &Orig) { return true; }
+
+ R_SExpr reduceFunction(Function &Orig, Variable *Nvd, R_SExpr E0) {
+ return Nvd && E0;
+ }
+ R_SExpr reduceSFunction(SFunction &Orig, Variable *Nvd, R_SExpr E0) {
+ return Nvd && E0;
+ }
+ R_SExpr reduceCode(Code &Orig, R_SExpr E0, R_SExpr E1) {
+ return E0 && E1;
+ }
+ R_SExpr reduceApply(Apply &Orig, R_SExpr E0, R_SExpr E1) {
+ return E0 && E1;
+ }
+ R_SExpr reduceSApply(SApply &Orig, R_SExpr E0, R_SExpr E1) {
+ return E0 && E1;
+ }
+ R_SExpr reduceProject(Project &Orig, R_SExpr E0) { return E0; }
+ R_SExpr reduceCall(Call &Orig, R_SExpr E0) { return E0; }
+ R_SExpr reduceAlloc(Alloc &Orig, R_SExpr E0) { return E0; }
+ R_SExpr reduceLoad(Load &Orig, R_SExpr E0) { return E0; }
+ R_SExpr reduceStore(Store &Orig, R_SExpr E0, R_SExpr E1) { return E0 && E1; }
+ R_SExpr reduceArrayFirst(Store &Orig, R_SExpr E0) { return E0; }
+ R_SExpr reduceArrayAdd(Store &Orig, R_SExpr E0, R_SExpr E1) {
+ return E0 && E1;
+ }
+ R_SExpr reduceUnaryOp(UnaryOp &Orig, R_SExpr E0) { return E0; }
+ R_SExpr reduceBinaryOp(BinaryOp &Orig, R_SExpr E0, R_SExpr E1) {
+ return E0 && E1;
+ }
+ R_SExpr reduceCast(Cast &Orig, R_SExpr E0) { return E0; }
+
+ R_SExpr reduceSCFG(SCFG &Orig, Container<BasicBlock *> Bbs) {
+ return Bbs.Success;
+ }
+ R_SExpr reducePhi(Phi &Orig, Container<R_SExpr> &As) {
+ return As.Success;
+ }
+ R_SExpr reduceGoto(Goto &Orig, BasicBlock *B, unsigned Index) {
+ return true;
+ }
+ R_SExpr reduceBranch(Branch &O, R_SExpr C, BasicBlock *B0, BasicBlock *B1) {
+ return C;
+ }
+
+ BasicBlock *reduceBasicBlock(BasicBlock &Orig, Container<Variable *> &As,
+ Container<Variable *> &Is, R_SExpr T) {
+ return (As.Success && Is.Success && T) ? &Orig : nullptr;
+ }
+
+ Variable *enterScope(Variable &Orig, R_SExpr E0) {
+ return E0 ? &Orig : nullptr;
+ }
+ void exitScope(const Variable &Orig) {}
+
+ void enterCFG(SCFG &Cfg) {}
+ void exitCFG(SCFG &Cfg) {}
+
+ Variable *reduceVariableRef(Variable *Ovd) { return Ovd; }
+
+ BasicBlock *reduceBasicBlockRef(BasicBlock *Obb) { return Obb; }
+};
+
+
+// A visitor will visit each node, and halt if any reducer returns false.
+template <class Self>
+class SExprVisitor : public Traversal<Self, VisitReducer> {
+public:
+ SExprVisitor() : Success(true) {}
+
+ bool traverse(SExpr *E, TraversalKind K = TRV_Normal) {
+ Success = Success && this->traverseByCase(E);
+ return Success;
+ }
+
+ static bool visit(SExpr *E) {
+ SExprVisitor Visitor;
+ return Visitor.traverse(E);
+ }
+
+private:
+ bool Success;
+};
+
+
+// Basic class for comparison operations over expressions.
+template <typename Self>
+class Comparator {
+protected:
+ Self *self() { return reinterpret_cast<Self *>(this); }
+
+public:
+ bool compareByCase(SExpr *E1, SExpr* E2) {
+ switch (E1->opcode()) {
+#define TIL_OPCODE_DEF(X) \
+ case COP_##X: \
+ return cast<X>(E1)->compare(cast<X>(E2), *self());
+#include "clang/Analysis/Analyses/ThreadSafetyOps.def"
+#undef TIL_OPCODE_DEF
+ case COP_MAX:
+ return false;
+ }
+ }
+};
+
+
+class EqualsComparator : public Comparator<EqualsComparator> {
+public:
+ // Result type for the comparison, e.g. bool for simple equality,
+ // or int for lexigraphic comparison (-1, 0, 1). Must have one value which
+ // denotes "true".
+ typedef bool CType;
+
+ CType trueResult() { return true; }
+ bool notTrue(CType ct) { return !ct; }
+
+ bool compareIntegers(unsigned i, unsigned j) { return i == j; }
+ bool comparePointers(const void* P, const void* Q) { return P == Q; }
+
+ bool compare(SExpr *E1, SExpr* E2) {
+ if (E1->opcode() != E2->opcode())
+ return false;
+ return compareByCase(E1, E2);
+ }
+
+ // TODO -- handle alpha-renaming of variables
+ void enterScope(Variable* V1, Variable* V2) { }
+ void leaveScope() { }
+
+ bool compareVariableRefs(Variable* V1, Variable* V2) {
+ return V1 == V2;
+ }
+
+ static bool compareExprs(SExpr *E1, SExpr* E2) {
+ EqualsComparator Eq;
+ return Eq.compare(E1, E2);
+ }
+};
+
+
+// Pretty printer for TIL expressions
+template <typename Self, typename StreamType>
+class PrettyPrinter {
+private:
+ bool Verbose; // Print out additional information
+
+public:
+ PrettyPrinter(bool V = false) : Verbose(V) { }
+
+ static void print(SExpr *E, StreamType &SS) {
+ Self printer;
+ printer.printSExpr(E, SS, Prec_MAX);
+ }
+
+protected:
+ Self *self() { return reinterpret_cast<Self *>(this); }
+
+ void newline(StreamType &SS) {
+ SS << "\n";
+ }
+
+ void printBlockLabel(StreamType & SS, BasicBlock *BB, unsigned index) {
+ if (!BB) {
+ SS << "BB_null";
+ return;
+ }
+ SS << "BB_";
+ SS << BB->blockID();
+ }
+
+ // TODO: further distinguish between binary operations.
+ static const unsigned Prec_Atom = 0;
+ static const unsigned Prec_Postfix = 1;
+ static const unsigned Prec_Unary = 2;
+ static const unsigned Prec_Binary = 3;
+ static const unsigned Prec_Other = 4;
+ static const unsigned Prec_Decl = 5;
+ static const unsigned Prec_MAX = 6;
+
+ // Return the precedence of a given node, for use in pretty printing.
+ unsigned precedence(SExpr *E) {
+ switch (E->opcode()) {
+ case COP_Future: return Prec_Atom;
+ case COP_Undefined: return Prec_Atom;
+ case COP_Wildcard: return Prec_Atom;
+
+ case COP_Literal: return Prec_Atom;
+ case COP_LiteralPtr: return Prec_Atom;
+ case COP_Variable: return Prec_Atom;
+ case COP_Function: return Prec_Decl;
+ case COP_SFunction: return Prec_Decl;
+ case COP_Code: return Prec_Decl;
+
+ case COP_Apply: return Prec_Postfix;
+ case COP_SApply: return Prec_Postfix;
+ case COP_Project: return Prec_Postfix;
+
+ case COP_Call: return Prec_Postfix;
+ case COP_Alloc: return Prec_Other;
+ case COP_Load: return Prec_Postfix;
+ case COP_Store: return Prec_Other;
+ case COP_ArrayFirst: return Prec_Postfix;
+ case COP_ArrayAdd: return Prec_Postfix;
+
+ case COP_UnaryOp: return Prec_Unary;
+ case COP_BinaryOp: return Prec_Binary;
+ case COP_Cast: return Prec_Unary;
+
+ case COP_SCFG: return Prec_Decl;
+ case COP_Phi: return Prec_Atom;
+ case COP_Goto: return Prec_Atom;
+ case COP_Branch: return Prec_Atom;
+ case COP_MAX: return Prec_MAX;
+ }
+ return Prec_MAX;
+ }
+
+ void printSExpr(SExpr *E, StreamType &SS, unsigned P) {
+ if (!E) {
+ self()->printNull(SS);
+ return;
+ }
+ if (self()->precedence(E) > P) {
+ // Wrap expr in () if necessary.
+ SS << "(";
+ self()->printSExpr(E, SS, Prec_MAX);
+ SS << ")";
+ return;
+ }
+
+ switch (E->opcode()) {
+#define TIL_OPCODE_DEF(X) \
+ case COP_##X: \
+ self()->print##X(cast<X>(E), SS); \
+ return;
+#include "clang/Analysis/Analyses/ThreadSafetyOps.def"
+#undef TIL_OPCODE_DEF
+ case COP_MAX:
+ return;
+ }
+ }
+
+ void printNull(StreamType &SS) {
+ SS << "#null";
+ }
+
+ void printFuture(Future *E, StreamType &SS) {
+ self()->printSExpr(E->maybeGetResult(), SS, Prec_Atom);
+ }
+
+ void printUndefined(Undefined *E, StreamType &SS) {
+ SS << "#undefined";
+ }
+
+ void printWildcard(Wildcard *E, StreamType &SS) {
+ SS << "_";
+ }
+
+ void printLiteral(Literal *E, StreamType &SS) {
+ const clang::Expr *CE = E->clangExpr();
+ switch (CE->getStmtClass()) {
+ case Stmt::IntegerLiteralClass:
+ SS << cast<IntegerLiteral>(CE)->getValue().toString(10, true);
+ return;
+ case Stmt::StringLiteralClass:
+ SS << "\"" << cast<StringLiteral>(CE)->getString() << "\"";
+ return;
+ case Stmt::CharacterLiteralClass:
+ case Stmt::CXXNullPtrLiteralExprClass:
+ case Stmt::GNUNullExprClass:
+ case Stmt::CXXBoolLiteralExprClass:
+ case Stmt::FloatingLiteralClass:
+ case Stmt::ImaginaryLiteralClass:
+ case Stmt::ObjCStringLiteralClass:
+ default:
+ SS << "#lit";
+ return;
+ }
+ }
+
+ void printLiteralPtr(LiteralPtr *E, StreamType &SS) {
+ SS << E->clangDecl()->getNameAsString();
+ }
+
+ void printVariable(Variable *V, StreamType &SS, bool IsVarDecl = false) {
+ SExpr* E = nullptr;
+ if (!IsVarDecl) {
+ E = getCanonicalVal(V);
+ if (E != V) {
+ printSExpr(E, SS, Prec_Atom);
+ if (Verbose) {
+ SS << " /*";
+ SS << V->name() << V->getBlockID() << "_" << V->getID();
+ SS << "*/";
+ }
+ return;
+ }
+ }
+ SS << V->name() << V->getBlockID() << "_" << V->getID();
+ }
+
+ void printFunction(Function *E, StreamType &SS, unsigned sugared = 0) {
+ switch (sugared) {
+ default:
+ SS << "\\("; // Lambda
+ case 1:
+ SS << "("; // Slot declarations
+ break;
+ case 2:
+ SS << ", "; // Curried functions
+ break;
+ }
+ self()->printVariable(E->variableDecl(), SS, true);
+ SS << ": ";
+ self()->printSExpr(E->variableDecl()->definition(), SS, Prec_MAX);
+
+ SExpr *B = E->body();
+ if (B && B->opcode() == COP_Function)
+ self()->printFunction(cast<Function>(B), SS, 2);
+ else
+ self()->printSExpr(B, SS, Prec_Decl);
+ }
+
+ void printSFunction(SFunction *E, StreamType &SS) {
+ SS << "@";
+ self()->printVariable(E->variableDecl(), SS, true);
+ SS << " ";
+ self()->printSExpr(E->body(), SS, Prec_Decl);
+ }
+
+ void printCode(Code *E, StreamType &SS) {
+ SS << ": ";
+ self()->printSExpr(E->returnType(), SS, Prec_Decl-1);
+ SS << " = ";
+ self()->printSExpr(E->body(), SS, Prec_Decl);
+ }
+
+ void printApply(Apply *E, StreamType &SS, bool sugared = false) {
+ SExpr *F = E->fun();
+ if (F->opcode() == COP_Apply) {
+ printApply(cast<Apply>(F), SS, true);
+ SS << ", ";
+ } else {
+ self()->printSExpr(F, SS, Prec_Postfix);
+ SS << "(";
+ }
+ self()->printSExpr(E->arg(), SS, Prec_MAX);
+ if (!sugared)
+ SS << ")$";
+ }
+
+ void printSApply(SApply *E, StreamType &SS) {
+ self()->printSExpr(E->sfun(), SS, Prec_Postfix);
+ if (E->isDelegation()) {
+ SS << "@(";
+ self()->printSExpr(E->arg(), SS, Prec_MAX);
+ SS << ")";
+ }
+ }
+
+ void printProject(Project *E, StreamType &SS) {
+ self()->printSExpr(E->record(), SS, Prec_Postfix);
+ SS << ".";
+ SS << E->slotName();
+ }
+
+ void printCall(Call *E, StreamType &SS) {
+ SExpr *T = E->target();
+ if (T->opcode() == COP_Apply) {
+ self()->printApply(cast<Apply>(T), SS, true);
+ SS << ")";
+ }
+ else {
+ self()->printSExpr(T, SS, Prec_Postfix);
+ SS << "()";
+ }
+ }
+
+ void printAlloc(Alloc *E, StreamType &SS) {
+ SS << "new ";
+ self()->printSExpr(E->dataType(), SS, Prec_Other-1);
+ }
+
+ void printLoad(Load *E, StreamType &SS) {
+ self()->printSExpr(E->pointer(), SS, Prec_Postfix);
+ SS << "^";
+ }
+
+ void printStore(Store *E, StreamType &SS) {
+ self()->printSExpr(E->destination(), SS, Prec_Other-1);
+ SS << " := ";
+ self()->printSExpr(E->source(), SS, Prec_Other-1);
+ }
+
+ void printArrayFirst(ArrayFirst *E, StreamType &SS) {
+ self()->printSExpr(E->array(), SS, Prec_Postfix);
+ if (ArrayAdd *A = dyn_cast_or_null<ArrayAdd>(E)) {
+ SS << "[";
+ printSExpr(A->index(), SS, Prec_MAX);
+ SS << "]";
+ return;
+ }
+ SS << "[0]";
+ }
+
+ void printArrayAdd(ArrayAdd *E, StreamType &SS) {
+ self()->printSExpr(E->array(), SS, Prec_Postfix);
+ SS << " + ";
+ self()->printSExpr(E->index(), SS, Prec_Atom);
+ }
+
+ void printUnaryOp(UnaryOp *E, StreamType &SS) {
+ self()->printSExpr(E->expr(), SS, Prec_Unary);
+ }
+
+ void printBinaryOp(BinaryOp *E, StreamType &SS) {
+ self()->printSExpr(E->expr0(), SS, Prec_Binary-1);
+ SS << " " << clang::BinaryOperator::getOpcodeStr(E->binaryOpcode()) << " ";
+ self()->printSExpr(E->expr1(), SS, Prec_Binary-1);
+ }
+
+ void printCast(Cast *E, StreamType &SS) {
+ SS << "~";
+ self()->printSExpr(E->expr(), SS, Prec_Unary);
+ }
+
+ void printSCFG(SCFG *E, StreamType &SS) {
+ SS << "#CFG {\n";
+ for (auto BBI : *E) {
+ SS << "BB_" << BBI->blockID() << ":";
+ newline(SS);
+ for (auto A : BBI->arguments()) {
+ SS << "let ";
+ self()->printVariable(A, SS, true);
+ SS << " = ";
+ self()->printSExpr(A->definition(), SS, Prec_MAX);
+ SS << ";";
+ newline(SS);
+ }
+ for (auto I : BBI->instructions()) {
+ if (I->definition()->opcode() != COP_Store) {
+ SS << "let ";
+ self()->printVariable(I, SS, true);
+ SS << " = ";
+ }
+ self()->printSExpr(I->definition(), SS, Prec_MAX);
+ SS << ";";
+ newline(SS);
+ }
+ SExpr *T = BBI->terminator();
+ if (T) {
+ self()->printSExpr(T, SS, Prec_MAX);
+ SS << ";";
+ newline(SS);
+ }
+ newline(SS);
+ }
+ SS << "}";
+ newline(SS);
+ }
+
+ void printPhi(Phi *E, StreamType &SS) {
+ SS << "phi(";
+ if (E->status() == Phi::PH_SingleVal)
+ self()->printSExpr(E->values()[0], SS, Prec_MAX);
+ else {
+ unsigned i = 0;
+ for (auto V : E->values()) {
+ if (i++ > 0)
+ SS << ", ";
+ self()->printSExpr(V, SS, Prec_MAX);
+ }
+ }
+ SS << ")";
+ }
+
+ void printGoto(Goto *E, StreamType &SS) {
+ SS << "goto ";
+ printBlockLabel(SS, E->targetBlock(), E->index());
+ }
+
+ void printBranch(Branch *E, StreamType &SS) {
+ SS << "branch (";
+ self()->printSExpr(E->condition(), SS, Prec_MAX);
+ SS << ") ";
+ printBlockLabel(SS, E->thenBlock(), E->thenIndex());
+ SS << " ";
+ printBlockLabel(SS, E->elseBlock(), E->elseIndex());
+ }
+};
+
+
+} // end namespace til
+} // end namespace threadSafety
+} // end namespace clang
+
+#endif // LLVM_CLANG_THREAD_SAFETY_TRAVERSE_H
diff --git a/include/clang/Analysis/Analyses/ThreadSafetyUtil.h b/include/clang/Analysis/Analyses/ThreadSafetyUtil.h
new file mode 100644
index 0000000000..3b768c5a69
--- /dev/null
+++ b/include/clang/Analysis/Analyses/ThreadSafetyUtil.h
@@ -0,0 +1,292 @@
+//===- ThreadSafetyUtil.h --------------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines some basic utility classes for use by ThreadSafetyTIL.h
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_THREAD_SAFETY_UTIL_H
+#define LLVM_CLANG_THREAD_SAFETY_UTIL_H
+
+#include "llvm/Support/AlignOf.h"
+#include "llvm/Support/Allocator.h"
+
+#include <cassert>
+#include <cstddef>
+#include <utility>
+
+namespace clang {
+namespace threadSafety {
+namespace til {
+
+// Simple wrapper class to abstract away from the details of memory management.
+// SExprs are allocated in pools, and deallocated all at once.
+class MemRegionRef {
+private:
+ union AlignmentType {
+ double d;
+ void *p;
+ long double dd;
+ long long ii;
+ };
+
+public:
+ MemRegionRef() : Allocator(nullptr) {}
+ MemRegionRef(llvm::BumpPtrAllocator *A) : Allocator(A) {}
+
+ void *allocate(size_t Sz) {
+ return Allocator->Allocate(Sz, llvm::AlignOf<AlignmentType>::Alignment);
+ }
+
+ template <typename T> T *allocateT() { return Allocator->Allocate<T>(); }
+
+ template <typename T> T *allocateT(size_t NumElems) {
+ return Allocator->Allocate<T>(NumElems);
+ }
+
+private:
+ llvm::BumpPtrAllocator *Allocator;
+};
+
+
+} // end namespace til
+} // end namespace threadSafety
+} // end namespace clang
+
+
+inline void *operator new(size_t Sz,
+ clang::threadSafety::til::MemRegionRef &R) {
+ return R.allocate(Sz);
+}
+
+
+namespace clang {
+namespace threadSafety {
+namespace til {
+
+using llvm::StringRef;
+
+// A simple fixed size array class that does not manage its own memory,
+// suitable for use with bump pointer allocation.
+template <class T> class SimpleArray {
+public:
+ SimpleArray() : Data(nullptr), Size(0), Capacity(0) {}
+ SimpleArray(T *Dat, size_t Cp, size_t Sz = 0)
+ : Data(Dat), Size(Sz), Capacity(Cp) {}
+ SimpleArray(MemRegionRef A, size_t Cp)
+ : Data(Cp == 0 ? nullptr : A.allocateT<T>(Cp)), Size(0), Capacity(Cp) {}
+ SimpleArray(SimpleArray<T> &&A)
+ : Data(A.Data), Size(A.Size), Capacity(A.Capacity) {
+ A.Data = nullptr;
+ A.Size = 0;
+ A.Capacity = 0;
+ }
+
+ SimpleArray &operator=(SimpleArray &&RHS) {
+ if (this != &RHS) {
+ Data = RHS.Data;
+ Size = RHS.Size;
+ Capacity = RHS.Capacity;
+
+ RHS.Data = nullptr;
+ RHS.Size = RHS.Capacity = 0;
+ }
+ return *this;
+ }
+
+ void reserve(size_t Ncp, MemRegionRef A) {
+ if (Ncp < Capacity)
+ return;
+ T *Odata = Data;
+ Data = A.allocateT<T>(Ncp);
+ Capacity = Ncp;
+ memcpy(Data, Odata, sizeof(T) * Size);
+ return;
+ }
+
+ typedef T *iterator;
+ typedef const T *const_iterator;
+
+ size_t size() const { return Size; }
+ size_t capacity() const { return Capacity; }
+
+ T &operator[](unsigned i) {
+ assert(i < Size && "Array index out of bounds.");
+ return Data[i];
+ }
+ const T &operator[](unsigned i) const {
+ assert(i < Size && "Array index out of bounds.");
+ return Data[i];
+ }
+
+ iterator begin() { return Data; }
+ iterator end() { return Data + Size; }
+
+ const_iterator cbegin() const { return Data; }
+ const_iterator cend() const { return Data + Size; }
+
+ void push_back(const T &Elem) {
+ assert(Size < Capacity);
+ Data[Size++] = Elem;
+ }
+
+ void setValues(unsigned Sz, const T& C) {
+ assert(Sz <= Capacity);
+ Size = Sz;
+ for (unsigned i = 0; i < Sz; ++i) {
+ Data[i] = C;
+ }
+ }
+
+ template <class Iter> unsigned append(Iter I, Iter E) {
+ size_t Osz = Size;
+ size_t J = Osz;
+ for (; J < Capacity && I != E; ++J, ++I)
+ Data[J] = *I;
+ Size = J;
+ return J - Osz;
+ }
+
+private:
+ SimpleArray(const SimpleArray<T> &A) LLVM_DELETED_FUNCTION;
+
+ T *Data;
+ size_t Size;
+ size_t Capacity;
+};
+
+} // end namespace til
+
+
+// A copy on write vector.
+// The vector can be in one of three states:
+// * invalid -- no operations are permitted.
+// * read-only -- read operations are permitted.
+// * writable -- read and write operations are permitted.
+// The init(), destroy(), and makeWritable() methods will change state.
+template<typename T>
+class CopyOnWriteVector {
+ class VectorData {
+ public:
+ VectorData() : NumRefs(1) { }
+ VectorData(const VectorData &VD) : NumRefs(1), Vect(VD.Vect) { }
+
+ unsigned NumRefs;
+ std::vector<T> Vect;
+ };
+
+ // No copy constructor or copy assignment. Use clone() with move assignment.
+ CopyOnWriteVector(const CopyOnWriteVector &V) LLVM_DELETED_FUNCTION;
+ void operator=(const CopyOnWriteVector &V) LLVM_DELETED_FUNCTION;
+
+public:
+ CopyOnWriteVector() : Data(nullptr) {}
+ CopyOnWriteVector(CopyOnWriteVector &&V) : Data(V.Data) { V.Data = nullptr; }
+ ~CopyOnWriteVector() { destroy(); }
+
+ // Returns true if this holds a valid vector.
+ bool valid() const { return Data; }
+
+ // Returns true if this vector is writable.
+ bool writable() const { return Data && Data->NumRefs == 1; }
+
+ // If this vector is not valid, initialize it to a valid vector.
+ void init() {
+ if (!Data) {
+ Data = new VectorData();
+ }
+ }
+
+ // Destroy this vector; thus making it invalid.
+ void destroy() {
+ if (!Data)
+ return;
+ if (Data->NumRefs <= 1)
+ delete Data;
+ else
+ --Data->NumRefs;
+ Data = nullptr;
+ }
+
+ // Make this vector writable, creating a copy if needed.
+ void makeWritable() {
+ if (!Data) {
+ Data = new VectorData();
+ return;
+ }
+ if (Data->NumRefs == 1)
+ return; // already writeable.
+ --Data->NumRefs;
+ Data = new VectorData(*Data);
+ }
+
+ // Create a lazy copy of this vector.
+ CopyOnWriteVector clone() { return CopyOnWriteVector(Data); }
+
+ CopyOnWriteVector &operator=(CopyOnWriteVector &&V) {
+ destroy();
+ Data = V.Data;
+ V.Data = nullptr;
+ return *this;
+ }
+
+ typedef typename std::vector<T>::const_iterator const_iterator;
+
+ const std::vector<T> &elements() const { return Data->Vect; }
+
+ const_iterator begin() const { return elements().cbegin(); }
+ const_iterator end() const { return elements().cend(); }
+
+ const T& operator[](unsigned i) const { return elements()[i]; }
+
+ unsigned size() const { return Data ? elements().size() : 0; }
+
+ // Return true if V and this vector refer to the same data.
+ bool sameAs(const CopyOnWriteVector &V) const { return Data == V.Data; }
+
+ // Clear vector. The vector must be writable.
+ void clear() {
+ assert(writable() && "Vector is not writable!");
+ Data->Vect.clear();
+ }
+
+ // Push a new element onto the end. The vector must be writable.
+ void push_back(const T &Elem) {
+ assert(writable() && "Vector is not writable!");
+ Data->Vect.push_back(Elem);
+ }
+
+ // Gets a mutable reference to the element at index(i).
+ // The vector must be writable.
+ T& elem(unsigned i) {
+ assert(writable() && "Vector is not writable!");
+ return Data->Vect[i];
+ }
+
+ // Drops elements from the back until the vector has size i.
+ void downsize(unsigned i) {
+ assert(writable() && "Vector is not writable!");
+ Data->Vect.erase(Data->Vect.begin() + i, Data->Vect.end());
+ }
+
+private:
+ CopyOnWriteVector(VectorData *D) : Data(D) {
+ if (!Data)
+ return;
+ ++Data->NumRefs;
+ }
+
+ VectorData *Data;
+};
+
+
+} // end namespace threadSafety
+} // end namespace clang
+
+#endif // LLVM_CLANG_THREAD_SAFETY_UTIL_H
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index 123d1443a2..87ba26db4f 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -47,6 +47,7 @@ namespace clang {
class CXXRecordDecl;
class CXXDeleteExpr;
class CXXNewExpr;
+ class BinaryOperator;
/// CFGElement - Represents a top-level expression in a basic block.
class CFGElement {
@@ -698,6 +699,15 @@ public:
}
};
+/// \brief CFGCallback defines methods that should be called when a logical
+/// operator error is found when building the CFG.
+class CFGCallback {
+public:
+ CFGCallback() {}
+ virtual void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {}
+ virtual ~CFGCallback() {}
+};
+
/// CFG - Represents a source-level, intra-procedural CFG that represents the
/// control-flow of a Stmt. The Stmt can represent an entire function body,
/// or a single expression. A CFG will always contain one empty block that
@@ -716,7 +726,7 @@ public:
public:
typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs;
ForcedBlkExprs **forcedBlkExprs;
-
+ CFGCallback *Observer;
bool PruneTriviallyFalseEdges;
bool AddEHEdges;
bool AddInitializers;
@@ -740,7 +750,7 @@ public:
}
BuildOptions()
- : forcedBlkExprs(0), PruneTriviallyFalseEdges(true)
+ : forcedBlkExprs(0), Observer(0), PruneTriviallyFalseEdges(true)
,AddEHEdges(false)
,AddInitializers(false)
,AddImplicitDtors(false)
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 73606835f0..02391e515c 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -1080,7 +1080,7 @@ def InitPriority : InheritableAttr {
}
def Section : InheritableAttr {
- let Spellings = [GCC<"section">];
+ let Spellings = [GCC<"section">, Declspec<"allocate">];
let Args = [StringArgument<"Name">];
let Subjects = SubjectList<[Function, GlobalVar,
ObjCMethod, ObjCProperty], ErrorDiag,
@@ -1702,6 +1702,7 @@ def MSInheritance : InheritableAttr {
Keyword<"__multiple_inheritance">,
Keyword<"__virtual_inheritance">,
Keyword<"__unspecified_inheritance">];
+ let Documentation = [SectionDocs];
let AdditionalMembers = [{
static bool hasVBPtrOffsetField(Spelling Inheritance) {
return Inheritance == Keyword_unspecified_inheritance;
diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td
index 2f62175849..7e923af812 100644
--- a/include/clang/Basic/AttrDocs.td
+++ b/include/clang/Basic/AttrDocs.td
@@ -27,6 +27,14 @@ This page lists the attributes currently supported by Clang.
}];
}
+def SectionDocs : Documentation {
+ let Category = DocCatVariable;
+ let Content = [{
+The ``section`` attribute allows you to specify a specific section a
+global variable or function should be in after translation.
+ }];
+}
+
def TLSModelDocs : Documentation {
let Category = DocCatVariable;
let Content = [{
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index 540ec25bad..3a1c58f431 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -733,11 +733,16 @@ LIBBUILTIN(vscanf, "icC*Ra", "fS:0:", "stdio.h", ALL_LANGUAGES)
LIBBUILTIN(vfscanf, "iP*RcC*Ra", "fS:1:", "stdio.h", ALL_LANGUAGES)
LIBBUILTIN(vsscanf, "icC*RcC*Ra", "fS:1:", "stdio.h", ALL_LANGUAGES)
// C99
+// In some systems setjmp is a macro that expands to _setjmp. We undefine
+// it here to avoid having two identical LIBBUILTIN entries.
#undef setjmp
LIBBUILTIN(setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES)
// Non-C library functions, active in GNU mode only.
+// Functions with (returns_twice) attribute (marked as "j") are still active in
+// all languages, because losing this attribute would result in miscompilation
+// when these functions are used in non-GNU mode. PR16138.
LIBBUILTIN(alloca, "v*z", "f", "stdlib.h", ALL_GNU_LANGUAGES)
// POSIX string.h
LIBBUILTIN(stpcpy, "c*c*cC*", "f", "string.h", ALL_GNU_LANGUAGES)
@@ -756,18 +761,16 @@ LIBBUILTIN(strcasecmp, "icC*cC*", "f", "strings.h", ALL_GNU_LANGUAGES)
LIBBUILTIN(strncasecmp, "icC*cC*z", "f", "strings.h", ALL_GNU_LANGUAGES)
// POSIX unistd.h
LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_GNU_LANGUAGES)
-LIBBUILTIN(vfork, "p", "fj", "unistd.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(vfork, "p", "fj", "unistd.h", ALL_LANGUAGES)
// POSIX setjmp.h
-// In some systems setjmp is a macro that expands to _setjmp. We undefine
-// it here to avoid having two identical LIBBUILTIN entries.
-LIBBUILTIN(_setjmp, "iJ", "fj", "setjmp.h", ALL_GNU_LANGUAGES)
-LIBBUILTIN(__sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_GNU_LANGUAGES)
-LIBBUILTIN(sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_GNU_LANGUAGES)
-LIBBUILTIN(setjmp_syscall, "iJ", "fj", "setjmp.h", ALL_GNU_LANGUAGES)
-LIBBUILTIN(savectx, "iJ", "fj", "setjmp.h", ALL_GNU_LANGUAGES)
-LIBBUILTIN(qsetjmp, "iJ", "fj", "setjmp.h", ALL_GNU_LANGUAGES)
-LIBBUILTIN(getcontext, "iK*", "fj", "setjmp.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(_setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(__sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(setjmp_syscall, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(savectx, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(qsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
+LIBBUILTIN(getcontext, "iK*", "fj", "setjmp.h", ALL_LANGUAGES)
LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h", ALL_GNU_LANGUAGES)
LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h", ALL_GNU_LANGUAGES)
diff --git a/include/clang/Basic/BuiltinsARM.def b/include/clang/Basic/BuiltinsARM.def
index aab9255a6d..99dbb9affa 100644
--- a/include/clang/Basic/BuiltinsARM.def
+++ b/include/clang/Basic/BuiltinsARM.def
@@ -65,4 +65,7 @@ BUILTIN(__builtin_arm_sevl, "v", "")
BUILTIN(__builtin_arm_dmb, "vUi", "nc")
BUILTIN(__builtin_arm_dsb, "vUi", "nc")
+// MSVC
+BUILTIN(__yield, "v", "")
+
#undef BUILTIN
diff --git a/include/clang/Basic/BuiltinsARM64.def b/include/clang/Basic/BuiltinsARM64.def
index dcc1b5180e..7500411e9e 100644
--- a/include/clang/Basic/BuiltinsARM64.def
+++ b/include/clang/Basic/BuiltinsARM64.def
@@ -15,7 +15,7 @@
// The format of this database matches clang/Basic/Builtins.def.
// In libgcc
-BUILTIN(__clear_cache, "vv*v*", "")
+BUILTIN(__clear_cache, "vv*v*", "i")
BUILTIN(__builtin_arm_ldrex, "v.", "t")
BUILTIN(__builtin_arm_strex, "i.", "t")
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index 4a67fc1f5f..8faaea381a 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -760,5 +760,7 @@ BUILTIN(__builtin_ia32_xbegin, "i", "")
BUILTIN(__builtin_ia32_xend, "v", "")
BUILTIN(__builtin_ia32_xabort, "vIc", "")
BUILTIN(__builtin_ia32_xtest, "i", "")
+BUILTIN(__builtin_ia32_rdtsc, "ULLi", "")
+BUILTIN(__builtin_ia32_rdtscp, "ULLiUi*", "")
#undef BUILTIN
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 6082ec8b1f..f7f84440a5 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -341,6 +341,14 @@ private:
/// \brief Second string argument for the delayed diagnostic.
std::string DelayedDiagArg2;
+ /// \brief Flag name value.
+ ///
+ /// Some flags accept values. For instance, -Wframe-larger-than or -Rpass.
+ /// When reporting a diagnostic with those flags, it is useful to also
+ /// report the value that actually triggered the flag. The content of this
+ /// string is a value to be emitted after the flag name.
+ std::string FlagNameValue;
+
public:
explicit DiagnosticsEngine(
const IntrusiveRefCntPtr<DiagnosticIDs> &Diags,
@@ -681,6 +689,12 @@ public:
/// \brief Clear out the current diagnostic.
void Clear() { CurDiagID = ~0U; }
+ /// \brief Return the value associated to this diagnostic flag.
+ StringRef getFlagNameValue() const { return StringRef(FlagNameValue); }
+
+ /// \brief Set the value associated to this diagnostic flag.
+ void setFlagNameValue(StringRef V) { FlagNameValue = V; }
+
private:
/// \brief Report the delayed diagnostic.
void ReportDelayed();
@@ -994,8 +1008,25 @@ public:
bool hasMaxFixItHints() const {
return NumFixits == DiagnosticsEngine::MaxFixItHints;
}
+
+ void addFlagValue(StringRef V) const { DiagObj->setFlagNameValue(V); }
+};
+
+struct AddFlagValue {
+ explicit AddFlagValue(StringRef V) : Val(V) {}
+ StringRef Val;
};
+/// \brief Register a value for the flag in the current diagnostic. This
+/// value will be shown as the suffix "=value" after the flag name. It is
+/// useful in cases where the diagnostic flag accepts values (e.g.,
+/// -Rpass or -Wframe-larger-than).
+inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
+ const AddFlagValue V) {
+ DB.addFlagValue(V.Val);
+ return DB;
+}
+
inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
StringRef S) {
DB.AddString(S);
@@ -1089,8 +1120,10 @@ inline DiagnosticBuilder DiagnosticsEngine::Report(SourceLocation Loc,
assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!");
CurDiagLoc = Loc;
CurDiagID = DiagID;
+ FlagNameValue.clear();
return DiagnosticBuilder(this);
}
+
inline DiagnosticBuilder DiagnosticsEngine::Report(unsigned DiagID) {
return Report(SourceLocation(), DiagID);
}
diff --git a/include/clang/Basic/Diagnostic.td b/include/clang/Basic/Diagnostic.td
index 61a4508615..5bcc2d5c16 100644
--- a/include/clang/Basic/Diagnostic.td
+++ b/include/clang/Basic/Diagnostic.td
@@ -102,6 +102,7 @@ class DefaultWarnNoWerror {
class DefaultWarnShowInSystemHeader {
bit WarningShowInSystemHeader = 1;
}
+class DefaultRemark { DiagMapping DefaultMapping = MAP_REMARK; }
// Definitions for Diagnostics.
include "DiagnosticASTKinds.td"
diff --git a/include/clang/Basic/DiagnosticCommentKinds.td b/include/clang/Basic/DiagnosticCommentKinds.td
index 49781fec9a..49296f9b5e 100644
--- a/include/clang/Basic/DiagnosticCommentKinds.td
+++ b/include/clang/Basic/DiagnosticCommentKinds.td
@@ -41,6 +41,10 @@ def warn_doc_html_start_end_mismatch : Warning<
def note_doc_html_end_tag : Note<
"end tag">;
+def warn_doc_html_missing_end_tag : Warning<
+ "HTML tag '%0' requires an end tag">,
+ InGroup<DocumentationHTML>, DefaultIgnore;
+
// Commands
def warn_doc_block_command_empty_paragraph : Warning<
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index 71080ba552..f65fecdcf6 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -82,6 +82,9 @@ def err_drv_invalid_libcxx_deployment : Error<
def err_drv_malformed_sanitizer_blacklist : Error<
"malformed sanitizer blacklist: '%0'">;
+def err_target_unsupported_arch
+ : Error<"the target architecture '%0' is not supported by the target '%1'">;
+
def err_drv_I_dash_not_supported : Error<
"'%0' not supported, please use -iquote instead">;
def err_drv_unknown_argument : Error<"unknown argument: '%0'">;
@@ -111,6 +114,8 @@ def err_drv_unknown_objc_runtime : Error<
"unknown or ill-formed Objective-C runtime '%0'">;
def err_drv_emit_llvm_link : Error<
"-emit-llvm cannot be used when linking">;
+def err_drv_optimization_remark_pattern : Error<
+ "%0 in '%1'">;
def warn_O4_is_O3 : Warning<"-O4 is equivalent to -O3">, InGroup<Deprecated>;
def warn_drv_optimization_value : Warning<"optimization level '%0' is unsupported; using '%1%2' instead">,
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 32c824a930..7b500eed5c 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -32,6 +32,12 @@ def err_fe_backend_plugin: Error<"%0">, CatBackend;
def remark_fe_backend_plugin: Remark<"%0">, CatBackend, InGroup<RemarkBackendPlugin>;
def note_fe_backend_plugin: Note<"%0">, CatBackend;
+def remark_fe_backend_optimization_remark : Remark<"%0">, CatBackend,
+ InGroup<BackendOptimizationRemark>, DefaultRemark;
+def note_fe_backend_optimization_remark_missing_loc : Note<"use "
+ "-gline-tables-only -gcolumn-info to track source location information "
+ "for this optimization remark">;
+
def err_fe_invalid_code_complete_file : Error<
"cannot locate code-completion file %0">, DefaultFatal;
def err_fe_stdout_binary : Error<"unable to change standard output to binary">,
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 5df740fa95..b1665f5373 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -41,6 +41,7 @@ def PointerBoolConversion : DiagGroup<"pointer-bool-conversion">;
def BoolConversion : DiagGroup<"bool-conversion", [ PointerBoolConversion ] >;
def IntConversion : DiagGroup<"int-conversion">;
def EnumConversion : DiagGroup<"enum-conversion">;
+def FloatConversion : DiagGroup<"float-conversion">;
def EnumTooLarge : DiagGroup<"enum-too-large">;
def NonLiteralNullConversion : DiagGroup<"non-literal-null-conversion">;
def NullConversion : DiagGroup<"null-conversion">;
@@ -48,6 +49,7 @@ def ImplicitConversionFloatingPointToBool :
DiagGroup<"implicit-conversion-floating-point-to-bool">;
def ObjCLiteralConversion : DiagGroup<"objc-literal-conversion">;
def BadArrayNewLength : DiagGroup<"bad-array-new-length">;
+def MacroRedefined : DiagGroup<"macro-redefined">;
def BuiltinMacroRedefined : DiagGroup<"builtin-macro-redefined">;
def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">;
def C99Compat : DiagGroup<"c99-compat">;
@@ -80,11 +82,11 @@ def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">;
def DeprecatedRegister : DiagGroup<"deprecated-register">;
def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings",
[CXX11CompatDeprecatedWritableStr]>;
-// FIXME: Why are DeprecatedImplementations and DeprecatedWritableStr
-// not in this group?
+// FIXME: Why is DeprecatedImplementations not in this group?
def Deprecated : DiagGroup<"deprecated", [DeprecatedDeclarations,
DeprecatedIncrementBool,
- DeprecatedRegister]>,
+ DeprecatedRegister,
+ DeprecatedWritableStr]>,
DiagCategory<"Deprecations">;
def : DiagGroup<"disabled-optimization">;
@@ -290,9 +292,11 @@ def StringPlusChar : DiagGroup<"string-plus-char">;
def StrncatSize : DiagGroup<"strncat-size">;
def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">;
def TautologicalPointerCompare : DiagGroup<"tautological-pointer-compare">;
+def TautologicalOverlapCompare : DiagGroup<"tautological-overlap-compare">;
def TautologicalCompare : DiagGroup<"tautological-compare",
[TautologicalOutOfRangeCompare,
- TautologicalPointerCompare]>;
+ TautologicalPointerCompare,
+ TautologicalOverlapCompare]>;
def HeaderHygiene : DiagGroup<"header-hygiene">;
def DuplicateDeclSpecifier : DiagGroup<"duplicate-decl-specifier">;
def CompareDistinctPointerType : DiagGroup<"compare-distinct-pointer-types">;
@@ -418,8 +422,18 @@ def ZeroLengthArray : DiagGroup<"zero-length-array">;
def GNUZeroLineDirective : DiagGroup<"gnu-zero-line-directive">;
def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments">;
+// This covers both the deprecated case (in C++98)
+// and the extension case (in C++11 onwards).
+def WritableStrings : DiagGroup<"writable-strings", [DeprecatedWritableStr]>;
+
// GCC calls -Wdeprecated-writable-strings -Wwrite-strings.
-def GCCWriteStrings : DiagGroup<"write-strings" , [DeprecatedWritableStr]>;
+//
+// Bizarrely, this warning flag enables -fconst-strings in C. This is
+// GCC-compatible, but really weird.
+//
+// FIXME: Should this affect C++11 (where this is an error,
+// not just deprecated) or not?
+def GCCWriteStrings : DiagGroup<"write-strings" , [WritableStrings]>;
def CharSubscript : DiagGroup<"char-subscripts">;
def LargeByValueCopy : DiagGroup<"large-by-value-copy">;
@@ -473,6 +487,7 @@ def Conversion : DiagGroup<"conversion",
[BoolConversion,
ConstantConversion,
EnumConversion,
+ FloatConversion,
Shorten64To32,
IntConversion,
LiteralConversion,
@@ -656,9 +671,14 @@ def ASM : DiagGroup<"asm", [
// OpenMP warnings.
def SourceUsesOpenMP : DiagGroup<"source-uses-openmp">;
+def OpenMPClauses : DiagGroup<"openmp-clauses">;
// Backend warnings.
def BackendInlineAsm : DiagGroup<"inline-asm">;
def BackendFrameLargerThan : DiagGroup<"frame-larger-than">;
def BackendPlugin : DiagGroup<"backend-plugin">;
def RemarkBackendPlugin : DiagGroup<"remark-backend-plugin">;
+def BackendOptimizationRemark : DiagGroup<"pass">;
+
+// Instrumentation based profiling warnings.
+def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">;
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index f9b845606b..c952e49793 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -154,6 +154,9 @@ public:
/// default.
static bool isDefaultMappingAsError(unsigned DiagID);
+ /// \brief Return true if the specified diagnostic is a Remark.
+ static bool isRemark(unsigned DiagID);
+
/// \brief Determine whether the given built-in diagnostic ID is a Note.
static bool isBuiltinNote(unsigned DiagID);
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index e1fc72f8ae..aef3c585a9 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -316,7 +316,7 @@ def ext_pp_extra_tokens_at_eol : ExtWarn<
def ext_pp_comma_expr : Extension<"comma operator in operand of #if">;
def ext_pp_bad_vaargs_use : Extension<
"__VA_ARGS__ can only appear in the expansion of a C99 variadic macro">;
-def ext_pp_macro_redef : ExtWarn<"%0 macro redefined">;
+def ext_pp_macro_redef : ExtWarn<"%0 macro redefined">, InGroup<MacroRedefined>;
def ext_variadic_macro : Extension<"variadic macros are a C99 feature">,
InGroup<VariadicMacros>;
def warn_cxx98_compat_variadic_macro : Warning<
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 40fab75f8a..6cb7a55db4 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -225,7 +225,7 @@ def err_expected_property_name : Error<"expected property name">;
def err_unexpected_at : Error<"unexpected '@' in program">;
def err_atimport : Error<
-"use of '@import' when modules are disabled, add -fmodules">;
+"use of '@import' when modules are disabled">;
def err_invalid_reference_qualifier_application : Error<
"'%0' qualifier may not be applied to a reference">;
@@ -339,8 +339,10 @@ def err_templated_using_directive : Error<
"cannot template a using directive">;
def err_templated_using_declaration : Error<
"cannot template a using declaration">;
-def err_unexected_colon_in_nested_name_spec : Error<
+def err_unexpected_colon_in_nested_name_spec : Error<
"unexpected ':' in nested name specifier; did you mean '::'?">;
+def err_unexpected_token_in_nested_name_spec : Error<
+ "'%0' cannot be a part of nested name specifier; did you mean ':'?">;
def err_bool_redeclaration : Error<
"redeclaration of C++ built-in type 'bool'">;
def ext_c11_static_assert : Extension<
@@ -524,7 +526,9 @@ def warn_cxx98_compat_attribute : Warning<
"C++11 attribute syntax is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def err_cxx11_attribute_forbids_arguments : Error<
- "attribute '%0' cannot have an argument list">;
+ "attribute %0 cannot have an argument list">;
+def err_attribute_requires_arguments : Error<
+ "parentheses must be omitted if %0 attribute's argument list is empty">;
def err_cxx11_attribute_forbids_ellipsis : Error<
"attribute '%0' cannot be used as an attribute pack">;
def err_cxx11_attribute_repeated : Error<
@@ -771,6 +775,15 @@ def warn_pragma_expected_rparen : Warning<
"missing ')' after '#pragma %0' - ignoring">, InGroup<IgnoredPragmas>;
def warn_pragma_expected_identifier : Warning<
"expected identifier in '#pragma %0' - ignored">, InGroup<IgnoredPragmas>;
+def warn_pragma_expected_section_name : Warning<
+ "expected a string literal for the section name in '#pragma %0' - ignored">,
+ InGroup<IgnoredPragmas>;
+def warn_pragma_expected_section_push_pop_or_name : Warning<
+ "expected push, pop or a string literal for the section name in '#pragma %0' - ignored">,
+ InGroup<IgnoredPragmas>;
+def warn_pragma_expected_section_label_or_name : Warning<
+ "expected a stack label or a string literal for the section name in '#pragma %0' - ignored">,
+ InGroup<IgnoredPragmas>;
def warn_pragma_expected_integer : Warning<
"expected integer between %0 and %1 inclusive in '#pragma %2' - ignored">,
InGroup<IgnoredPragmas>;
@@ -793,6 +806,15 @@ def warn_pragma_align_invalid_option : Warning<
"invalid alignment option in '#pragma %select{align|options align}0' - ignored">,
InGroup<IgnoredPragmas>;
// - #pragma pack
+def warn_pragma_unsupported_action : Warning<
+ "known but unsupported action '%1' for '#pragma %0' - ignored">,
+ InGroup<IgnoredPragmas>;
+def warn_pragma_invalid_specific_action : Warning<
+ "unknown action '%1' for '#pragma %0' - ignored">,
+ InGroup<IgnoredPragmas>;
+def warn_pragma_expected_action_or_r_paren : Warning<
+ "expected action or ')' in '#pragma %0' - ignored">,
+ InGroup<IgnoredPragmas>;
def warn_pragma_invalid_action : Warning<
"unknown action for '#pragma %0' - ignored">,
InGroup<IgnoredPragmas>;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index b138619de3..a81154596b 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -35,7 +35,7 @@ def warn_unsigned_abs : Warning<
"taking the absolute value of unsigned type %0 has no effect">,
InGroup<AbsoluteValue>;
def note_remove_abs : Note<
- "remove the call to %0 since unsigned values cannot be negative">;
+ "remove the call to '%0' since unsigned values cannot be negative">;
def warn_abs_too_small : Warning<
"absolute value function %0 given an argument of type %1 but has parameter "
"of type %2 which may cause truncation of value">, InGroup<AbsoluteValue>;
@@ -521,6 +521,7 @@ def warn_cxx_ms_struct :
Warning<"ms_struct may not produce MSVC-compatible layouts for classes "
"with base classes or virtual functions">,
DefaultError, InGroup<IncompatibleMSStruct>;
+def err_section_conflict : Error<"%0 causes a section type conflict with %1">;
def warn_pragma_unused_undeclared_var : Warning<
"undeclared variable %0 used as an argument for '#pragma unused'">,
@@ -1168,7 +1169,10 @@ def err_incomplete_type : Error<
def warn_cxx98_compat_enum_nested_name_spec : Warning<
"enumeration type in nested name specifier is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
-
+def err_nested_name_spec_is_not_class : Error<
+ "%0 cannot appear before '::' because it is not a class"
+ "%select{ or namespace|, namespace, or scoped enumeration}1; did you mean ':'?">;
+
// C++ class members
def err_storageclass_invalid_for_member : Error<
"storage class specified for a member declaration">;
@@ -2315,7 +2319,7 @@ def warn_impcast_float_precision : Warning<
InGroup<Conversion>, DefaultIgnore;
def warn_impcast_float_integer : Warning<
"implicit conversion turns floating-point number into integer: %0 to %1">,
- InGroup<Conversion>, DefaultIgnore;
+ InGroup<FloatConversion>, DefaultIgnore;
def warn_impcast_integer_sign : Warning<
"implicit conversion changes signedness: %0 to %1">,
InGroup<SignConversion>, DefaultIgnore;
@@ -2547,6 +2551,8 @@ def warn_objc_invalid_bridge : Warning<
"%0 bridges to %1, not %2">, InGroup<ObjCBridge>;
def warn_objc_invalid_bridge_to_cf : Warning<
"%0 cannot bridge to %1">, InGroup<ObjCBridge>;
+def err_objc_invalid_bridge : Error<
+ "under ARC %0 bridges to %1, but it still requires an explicit bridge cast">;
// objc_bridge_related attribute diagnostics.
def err_objc_bridged_related_invalid_class : Error<
@@ -3263,8 +3269,8 @@ def err_template_qualified_declarator_no_match : Error<
"nested name specifier '%0' for declaration does not refer into a class, "
"class template or class template partial specialization">;
def err_specialize_member_of_template : Error<
- "cannot specialize (with 'template<>') a member of an unspecialized "
- "template">;
+ "cannot specialize %select{|(with 'template<>') }0a member of an "
+ "unspecialized template">;
// C++ Class Template Partial Specialization
def err_default_arg_in_partial_spec : Error<
@@ -4634,7 +4640,7 @@ def warn_deprecated_string_literal_conversion : Warning<
InGroup<CXX11CompatDeprecatedWritableStr>;
def ext_deprecated_string_literal_conversion : ExtWarn<
"ISO C++11 does not allow conversion from string literal to %0">,
- InGroup<CXX11CompatDeprecatedWritableStr>, SFINAEFailure;
+ InGroup<WritableStrings>, SFINAEFailure;
def err_realimag_invalid_type : Error<"invalid type %0 to %1 operator">;
def err_typecheck_sclass_fscope : Error<
"illegal storage class on file-scoped variable">;
@@ -4728,8 +4734,9 @@ def warn_lunsigned_always_true_comparison : Warning<
"comparison of unsigned%select{| enum}2 expression %0 is always %1">,
InGroup<TautologicalCompare>;
def warn_out_of_range_compare : Warning<
- "comparison of constant %0 with expression of type %1 is always "
- "%select{false|true}2">, InGroup<TautologicalOutOfRangeCompare>;
+ "comparison of %select{constant %0|true|false}1 with "
+ "%select{expression of type %2|boolean expression}3 is always "
+ "%select{false|true}4">, InGroup<TautologicalOutOfRangeCompare>;
def warn_runsigned_always_true_comparison : Warning<
"comparison of %0 unsigned%select{| enum}2 expression is always %1">,
InGroup<TautologicalCompare>;
@@ -6382,6 +6389,9 @@ def note_ref_subobject_of_member_declared_here : Note<
def warn_comparison_always : Warning<
"%select{self-|array }0comparison always evaluates to %select{false|true|a constant}1">,
InGroup<TautologicalCompare>;
+def warn_tautological_overlap_comparison : Warning<
+ "overlapping comparisons always evaluate to %select{false|true}0">,
+ InGroup<TautologicalOverlapCompare>, DefaultIgnore;
def warn_stringcompare : Warning<
"result of comparison against %select{a string literal|@encode}0 is "
@@ -6920,6 +6930,16 @@ def err_omp_ambiguous_conversion : Error<
"enumeration type">;
def err_omp_required_access : Error<
"%0 variable must be %1">;
+def err_omp_const_variable : Error<
+ "const-qualified variable cannot be %0">;
+def err_omp_linear_incomplete_type : Error<
+ "a linear variable with incomplete type %0">;
+def err_omp_linear_expected_int_or_ptr : Error<
+ "argument of a linear clause should be of integral or pointer "
+ "type, not %0">;
+def warn_omp_linear_step_zero : Warning<
+ "zero linear step (%0 %select{|and other variables in clause }1should probably be const)">,
+ InGroup<OpenMPClauses>;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
@@ -6976,4 +6996,11 @@ def warn_not_a_doxygen_trailing_member_comment : Warning<
"not a Doxygen trailing comment">, InGroup<Documentation>, DefaultIgnore;
} // end of documentation issue category
+let CategoryName = "Instrumentation Issue" in {
+def warn_profile_data_out_of_date : Warning<
+ "profile data may be out of date: of %0 function%s0, %1 %plural{1:has|:have}1"
+ " no data and %2 %plural{1:has|:have}2 mismatched data that will be ignored">,
+ InGroup<ProfileInstrOutOfDate>;
+} // end of instrumentation issue category
+
} // end of sema component.
diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td
index 57ba0a4bcb..db1ca43327 100644
--- a/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -48,7 +48,12 @@ def err_pch_different_branch : Error<
"PCH file built from a different branch (%0) than the compiler (%1)">;
def err_pch_with_compiler_errors : Error<
"PCH file contains compiler errors">;
-
+
+def err_imported_module_not_found : Error<
+ "module '%0' imported by AST file '%1' not found">, DefaultFatal;
+def err_imported_module_modmap_changed : Error<
+ "module '%0' imported by AST file '%1' found in a different module map file"
+ " (%2) than when the importing AST file was built (%3)">, DefaultFatal;
def warn_module_conflict : Warning<
"module '%0' conflicts with already-imported module '%1': %2">,
InGroup<ModuleConflict>;
@@ -78,6 +83,13 @@ def note_module_odr_violation_no_possible_decls : Note<
"definition has no member %0">;
def note_module_odr_violation_possible_decl : Note<
"declaration of %0 does not match">;
+def err_module_odr_violation_different_definitions : Error<
+ "%q0 has different definitions in different modules; "
+ "%select{definition in module '%2' is here|defined here}1">;
+def note_module_odr_violation_different_definitions : Note<
+ "definition in module '%0' is here">;
+def err_module_odr_violation_different_instantiations : Error<
+ "instantiation of %q0 is different in different modules">;
} // let CategoryName
} // let Component
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index 7b214824f4..87c5b7b280 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -96,6 +96,8 @@ LANGOPT(MathErrno , 1, 1, "errno support for math functions")
BENIGN_LANGOPT(HeinousExtensions , 1, 0, "Extensions that we really don't like and may be ripped out at any time")
LANGOPT(Modules , 1, 0, "modules extension to C")
LANGOPT(ModulesDeclUse , 1, 0, "require declaration of module uses")
+LANGOPT(ModulesSearchAll , 1, 1, "search even non-imported modules to find unresolved references")
+LANGOPT(ModulesStrictDeclUse, 1, 0, "require declaration of module uses and all headers to be in modules")
LANGOPT(Optimize , 1, 0, "__OPTIMIZE__ predefined macro")
LANGOPT(OptimizeSize , 1, 0, "__OPTIMIZE_SIZE__ predefined macro")
LANGOPT(Static , 1, 0, "__STATIC__ predefined macro (as opposed to __DYNAMIC__)")
diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h
index 1f7f71d54b..783aa1d57b 100644
--- a/include/clang/Basic/Module.h
+++ b/include/clang/Basic/Module.h
@@ -51,10 +51,21 @@ public:
/// \brief The location of the module definition.
SourceLocation DefinitionLoc;
-
+
/// \brief The parent of this module. This will be NULL for the top-level
/// module.
Module *Parent;
+
+ /// \brief The module map file that (along with the module name) uniquely
+ /// identifies this module.
+ ///
+ /// The particular module that \c Name refers to may depend on how the module
+ /// was found in header search. However, the combination of \c Name and
+ /// \c ModuleMap will be globally unique for top-level modules. In the case of
+ /// inferred modules, \c ModuleMap will contain the module map that allowed
+ /// the inference (e.g. contained 'Module *') rather than the virtual
+ /// inferred module map file.
+ const FileEntry *ModuleMap;
/// \brief The umbrella header or directory.
llvm::PointerUnion<const DirectoryEntry *, const FileEntry *> Umbrella;
@@ -112,8 +123,13 @@ public:
/// will be false to indicate that this (sub)module is not available.
SmallVector<Requirement, 2> Requirements;
- /// \brief Whether this module is available in the current
- /// translation unit.
+ /// \brief Whether this module is missing a feature from \c Requirements.
+ unsigned IsMissingRequirement : 1;
+
+ /// \brief Whether this module is available in the current translation unit.
+ ///
+ /// If the module is missing headers or does not meet all requirements then
+ /// this bit will be 0.
unsigned IsAvailable : 1;
/// \brief Whether this module was loaded from a module file.
@@ -134,6 +150,9 @@ public:
/// imported within such a block).
unsigned IsExternC : 1;
+ /// \brief Whether this is an inferred submodule (module * { ... }).
+ unsigned IsInferred : 1;
+
/// \brief Whether we should infer submodules for this module based on
/// the headers.
///
@@ -264,8 +283,10 @@ public:
std::vector<Conflict> Conflicts;
/// \brief Construct a new module or submodule.
- Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
- bool IsFramework, bool IsExplicit);
+ ///
+ /// For an explanation of \p ModuleMap, see Module::ModuleMap.
+ Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
+ const FileEntry *ModuleMap, bool IsFramework, bool IsExplicit);
~Module();
@@ -294,7 +315,7 @@ public:
/// \brief Determine whether this module is a submodule of the given other
/// module.
- bool isSubModuleOf(Module *Other) const;
+ bool isSubModuleOf(const Module *Other) const;
/// \brief Determine whether this module is a part of a framework,
/// either because it is a framework module or because it is a submodule
@@ -394,6 +415,9 @@ public:
const LangOptions &LangOpts,
const TargetInfo &Target);
+ /// \brief Mark this module and all of its submodules as unavailable.
+ void markUnavailable(bool MissingRequirement = false);
+
/// \brief Find the submodule with the given name.
///
/// \returns The submodule if found, or NULL otherwise.
diff --git a/include/clang/Basic/OnDiskHashTable.h b/include/clang/Basic/OnDiskHashTable.h
deleted file mode 100644
index 8c2cd8d5f3..0000000000
--- a/include/clang/Basic/OnDiskHashTable.h
+++ /dev/null
@@ -1,419 +0,0 @@
-//===--- OnDiskHashTable.h - On-Disk Hash Table Implementation --*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief Defines facilities for reading and writing on-disk hash tables.
-///
-//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_BASIC_ON_DISK_HASH_TABLE_H
-#define LLVM_CLANG_BASIC_ON_DISK_HASH_TABLE_H
-
-#include "clang/Basic/LLVM.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/DataTypes.h"
-#include "llvm/Support/EndianStream.h"
-#include "llvm/Support/Host.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cassert>
-#include <cstdlib>
-
-namespace clang {
-
-namespace io {
-
-typedef uint32_t Offset;
-
-inline void Pad(raw_ostream& Out, unsigned A) {
- using namespace llvm::support;
- Offset off = (Offset) Out.tell();
- for (uint32_t n = llvm::OffsetToAlignment(off, A); n; --n)
- endian::Writer<little>(Out).write<uint8_t>(0);
-}
-
-} // end namespace io
-
-template<typename Info>
-class OnDiskChainedHashTableGenerator {
- unsigned NumBuckets;
- unsigned NumEntries;
- llvm::BumpPtrAllocator BA;
-
- class Item {
- public:
- typename Info::key_type key;
- typename Info::data_type data;
- Item *next;
- const uint32_t hash;
-
- Item(typename Info::key_type_ref k, typename Info::data_type_ref d,
- Info &InfoObj)
- : key(k), data(d), next(0), hash(InfoObj.ComputeHash(k)) {}
- };
-
- class Bucket {
- public:
- io::Offset off;
- Item* head;
- unsigned length;
-
- Bucket() {}
- };
-
- Bucket* Buckets;
-
-private:
- void insert(Bucket* b, size_t size, Item* E) {
- unsigned idx = E->hash & (size - 1);
- Bucket& B = b[idx];
- E->next = B.head;
- ++B.length;
- B.head = E;
- }
-
- void resize(size_t newsize) {
- Bucket* newBuckets = (Bucket*) std::calloc(newsize, sizeof(Bucket));
- // Populate newBuckets with the old entries.
- for (unsigned i = 0; i < NumBuckets; ++i)
- for (Item* E = Buckets[i].head; E ; ) {
- Item* N = E->next;
- E->next = 0;
- insert(newBuckets, newsize, E);
- E = N;
- }
-
- free(Buckets);
- NumBuckets = newsize;
- Buckets = newBuckets;
- }
-
-public:
-
- void insert(typename Info::key_type_ref key,
- typename Info::data_type_ref data) {
- Info InfoObj;
- insert(key, data, InfoObj);
- }
-
- void insert(typename Info::key_type_ref key,
- typename Info::data_type_ref data, Info &InfoObj) {
-
- ++NumEntries;
- if (4*NumEntries >= 3*NumBuckets) resize(NumBuckets*2);
- insert(Buckets, NumBuckets, new (BA.Allocate<Item>()) Item(key, data,
- InfoObj));
- }
-
- io::Offset Emit(raw_ostream &out) {
- Info InfoObj;
- return Emit(out, InfoObj);
- }
-
- io::Offset Emit(raw_ostream &out, Info &InfoObj) {
- using namespace llvm::support;
- endian::Writer<little> LE(out);
-
- // Emit the payload of the table.
- for (unsigned i = 0; i < NumBuckets; ++i) {
- Bucket& B = Buckets[i];
- if (!B.head) continue;
-
- // Store the offset for the data of this bucket.
- B.off = out.tell();
- assert(B.off && "Cannot write a bucket at offset 0. Please add padding.");
-
- // Write out the number of items in the bucket.
- LE.write<uint16_t>(B.length);
- assert(B.length != 0 && "Bucket has a head but zero length?");
-
- // Write out the entries in the bucket.
- for (Item *I = B.head; I ; I = I->next) {
- LE.write<uint32_t>(I->hash);
- const std::pair<unsigned, unsigned>& Len =
- InfoObj.EmitKeyDataLength(out, I->key, I->data);
- InfoObj.EmitKey(out, I->key, Len.first);
- InfoObj.EmitData(out, I->key, I->data, Len.second);
- }
- }
-
- // Emit the hashtable itself.
- io::Pad(out, 4);
- io::Offset TableOff = out.tell();
- LE.write<uint32_t>(NumBuckets);
- LE.write<uint32_t>(NumEntries);
- for (unsigned i = 0; i < NumBuckets; ++i)
- LE.write<uint32_t>(Buckets[i].off);
-
- return TableOff;
- }
-
- OnDiskChainedHashTableGenerator() {
- NumEntries = 0;
- NumBuckets = 64;
- // Note that we do not need to run the constructors of the individual
- // Bucket objects since 'calloc' returns bytes that are all 0.
- Buckets = (Bucket*) std::calloc(NumBuckets, sizeof(Bucket));
- }
-
- ~OnDiskChainedHashTableGenerator() {
- std::free(Buckets);
- }
-};
-
-template<typename Info>
-class OnDiskChainedHashTable {
- const unsigned NumBuckets;
- const unsigned NumEntries;
- const unsigned char* const Buckets;
- const unsigned char* const Base;
- Info InfoObj;
-
-public:
- typedef typename Info::internal_key_type internal_key_type;
- typedef typename Info::external_key_type external_key_type;
- typedef typename Info::data_type data_type;
-
- OnDiskChainedHashTable(unsigned numBuckets, unsigned numEntries,
- const unsigned char* buckets,
- const unsigned char* base,
- const Info &InfoObj = Info())
- : NumBuckets(numBuckets), NumEntries(numEntries),
- Buckets(buckets), Base(base), InfoObj(InfoObj) {
- assert((reinterpret_cast<uintptr_t>(buckets) & 0x3) == 0 &&
- "'buckets' must have a 4-byte alignment");
- }
-
- unsigned getNumBuckets() const { return NumBuckets; }
- unsigned getNumEntries() const { return NumEntries; }
- const unsigned char* getBase() const { return Base; }
- const unsigned char* getBuckets() const { return Buckets; }
-
- bool isEmpty() const { return NumEntries == 0; }
-
- class iterator {
- internal_key_type key;
- const unsigned char* const data;
- const unsigned len;
- Info *InfoObj;
- public:
- iterator() : data(0), len(0) {}
- iterator(const internal_key_type k, const unsigned char* d, unsigned l,
- Info *InfoObj)
- : key(k), data(d), len(l), InfoObj(InfoObj) {}
-
- data_type operator*() const { return InfoObj->ReadData(key, data, len); }
- bool operator==(const iterator& X) const { return X.data == data; }
- bool operator!=(const iterator& X) const { return X.data != data; }
- };
-
- iterator find(const external_key_type& eKey, Info *InfoPtr = 0) {
- if (!InfoPtr)
- InfoPtr = &InfoObj;
-
- using namespace llvm::support;
- const internal_key_type& iKey = InfoObj.GetInternalKey(eKey);
- unsigned key_hash = InfoObj.ComputeHash(iKey);
-
- // Each bucket is just a 32-bit offset into the hash table file.
- unsigned idx = key_hash & (NumBuckets - 1);
- const unsigned char* Bucket = Buckets + sizeof(uint32_t)*idx;
-
- unsigned offset = endian::readNext<uint32_t, little, aligned>(Bucket);
- if (offset == 0) return iterator(); // Empty bucket.
- const unsigned char* Items = Base + offset;
-
- // 'Items' starts with a 16-bit unsigned integer representing the
- // number of items in this bucket.
- unsigned len = endian::readNext<uint16_t, little, unaligned>(Items);
-
- for (unsigned i = 0; i < len; ++i) {
- // Read the hash.
- uint32_t item_hash = endian::readNext<uint32_t, little, unaligned>(Items);
-
- // Determine the length of the key and the data.
- const std::pair<unsigned, unsigned>& L = Info::ReadKeyDataLength(Items);
- unsigned item_len = L.first + L.second;
-
- // Compare the hashes. If they are not the same, skip the entry entirely.
- if (item_hash != key_hash) {
- Items += item_len;
- continue;
- }
-
- // Read the key.
- const internal_key_type& X =
- InfoPtr->ReadKey((const unsigned char* const) Items, L.first);
-
- // If the key doesn't match just skip reading the value.
- if (!InfoPtr->EqualKey(X, iKey)) {
- Items += item_len;
- continue;
- }
-
- // The key matches!
- return iterator(X, Items + L.first, L.second, InfoPtr);
- }
-
- return iterator();
- }
-
- iterator end() const { return iterator(); }
-
- /// \brief Iterates over all of the keys in the table.
- class key_iterator {
- const unsigned char* Ptr;
- unsigned NumItemsInBucketLeft;
- unsigned NumEntriesLeft;
- Info *InfoObj;
- public:
- typedef external_key_type value_type;
-
- key_iterator(const unsigned char* const Ptr, unsigned NumEntries,
- Info *InfoObj)
- : Ptr(Ptr), NumItemsInBucketLeft(0), NumEntriesLeft(NumEntries),
- InfoObj(InfoObj) { }
- key_iterator()
- : Ptr(0), NumItemsInBucketLeft(0), NumEntriesLeft(0), InfoObj(0) { }
-
- friend bool operator==(const key_iterator &X, const key_iterator &Y) {
- return X.NumEntriesLeft == Y.NumEntriesLeft;
- }
- friend bool operator!=(const key_iterator& X, const key_iterator &Y) {
- return X.NumEntriesLeft != Y.NumEntriesLeft;
- }
-
- key_iterator& operator++() { // Preincrement
- using namespace llvm::support;
- if (!NumItemsInBucketLeft) {
- // 'Items' starts with a 16-bit unsigned integer representing the
- // number of items in this bucket.
- NumItemsInBucketLeft =
- endian::readNext<uint16_t, little, unaligned>(Ptr);
- }
- Ptr += 4; // Skip the hash.
- // Determine the length of the key and the data.
- const std::pair<unsigned, unsigned>& L = Info::ReadKeyDataLength(Ptr);
- Ptr += L.first + L.second;
- assert(NumItemsInBucketLeft);
- --NumItemsInBucketLeft;
- assert(NumEntriesLeft);
- --NumEntriesLeft;
- return *this;
- }
- key_iterator operator++(int) { // Postincrement
- key_iterator tmp = *this; ++*this; return tmp;
- }
-
- value_type operator*() const {
- const unsigned char* LocalPtr = Ptr;
- if (!NumItemsInBucketLeft)
- LocalPtr += 2; // number of items in bucket
- LocalPtr += 4; // Skip the hash.
-
- // Determine the length of the key and the data.
- const std::pair<unsigned, unsigned>& L
- = Info::ReadKeyDataLength(LocalPtr);
-
- // Read the key.
- const internal_key_type& Key = InfoObj->ReadKey(LocalPtr, L.first);
- return InfoObj->GetExternalKey(Key);
- }
- };
-
- key_iterator key_begin() {
- return key_iterator(Base + 4, getNumEntries(), &InfoObj);
- }
- key_iterator key_end() { return key_iterator(); }
-
- /// \brief Iterates over all the entries in the table, returning the data.
- class data_iterator {
- const unsigned char* Ptr;
- unsigned NumItemsInBucketLeft;
- unsigned NumEntriesLeft;
- Info *InfoObj;
- public:
- typedef data_type value_type;
-
- data_iterator(const unsigned char* const Ptr, unsigned NumEntries,
- Info *InfoObj)
- : Ptr(Ptr), NumItemsInBucketLeft(0), NumEntriesLeft(NumEntries),
- InfoObj(InfoObj) { }
- data_iterator()
- : Ptr(0), NumItemsInBucketLeft(0), NumEntriesLeft(0), InfoObj(0) { }
-
- bool operator==(const data_iterator& X) const {
- return X.NumEntriesLeft == NumEntriesLeft;
- }
- bool operator!=(const data_iterator& X) const {
- return X.NumEntriesLeft != NumEntriesLeft;
- }
-
- data_iterator& operator++() { // Preincrement
- using namespace llvm::support;
- if (!NumItemsInBucketLeft) {
- // 'Items' starts with a 16-bit unsigned integer representing the
- // number of items in this bucket.
- NumItemsInBucketLeft =
- endian::readNext<uint16_t, little, unaligned>(Ptr);
- }
- Ptr += 4; // Skip the hash.
- // Determine the length of the key and the data.
- const std::pair<unsigned, unsigned>& L = Info::ReadKeyDataLength(Ptr);
- Ptr += L.first + L.second;
- assert(NumItemsInBucketLeft);
- --NumItemsInBucketLeft;
- assert(NumEntriesLeft);
- --NumEntriesLeft;
- return *this;
- }
- data_iterator operator++(int) { // Postincrement
- data_iterator tmp = *this; ++*this; return tmp;
- }
-
- value_type operator*() const {
- const unsigned char* LocalPtr = Ptr;
- if (!NumItemsInBucketLeft)
- LocalPtr += 2; // number of items in bucket
- LocalPtr += 4; // Skip the hash.
-
- // Determine the length of the key and the data.
- const std::pair<unsigned, unsigned>& L =Info::ReadKeyDataLength(LocalPtr);
-
- // Read the key.
- const internal_key_type& Key =
- InfoObj->ReadKey(LocalPtr, L.first);
- return InfoObj->ReadData(Key, LocalPtr + L.first, L.second);
- }
- };
-
- data_iterator data_begin() {
- return data_iterator(Base + 4, getNumEntries(), &InfoObj);
- }
- data_iterator data_end() { return data_iterator(); }
-
- Info &getInfoObj() { return InfoObj; }
-
- static OnDiskChainedHashTable* Create(const unsigned char* buckets,
- const unsigned char* const base,
- const Info &InfoObj = Info()) {
- using namespace llvm::support;
- assert(buckets > base);
- assert((reinterpret_cast<uintptr_t>(buckets) & 0x3) == 0 &&
- "buckets should be 4-byte aligned.");
-
- unsigned numBuckets = endian::readNext<uint32_t, little, aligned>(buckets);
- unsigned numEntries = endian::readNext<uint32_t, little, aligned>(buckets);
- return new OnDiskChainedHashTable<Info>(numBuckets, numEntries, buckets,
- base, InfoObj);
- }
-};
-
-} // end namespace clang
-
-#endif
diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def
index 348f40f416..479ef3df30 100644
--- a/include/clang/Basic/OpenMPKinds.def
+++ b/include/clang/Basic/OpenMPKinds.def
@@ -42,6 +42,7 @@ OPENMP_CLAUSE(default, OMPDefaultClause)
OPENMP_CLAUSE(private, OMPPrivateClause)
OPENMP_CLAUSE(firstprivate, OMPFirstprivateClause)
OPENMP_CLAUSE(shared, OMPSharedClause)
+OPENMP_CLAUSE(linear, OMPLinearClause)
OPENMP_CLAUSE(copyin, OMPCopyinClause)
// Clauses allowed for OpenMP directive 'parallel'.
@@ -55,6 +56,7 @@ OPENMP_PARALLEL_CLAUSE(copyin)
// FIXME: more clauses allowed for directive 'omp simd'.
OPENMP_SIMD_CLAUSE(private)
+OPENMP_SIMD_CLAUSE(linear)
OPENMP_SIMD_CLAUSE(safelen)
// Static attributes for 'default' clause.
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index c2130acbc9..73fd770f72 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -44,6 +44,7 @@
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
+#include "llvm/Support/AlignOf.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -89,6 +90,15 @@ namespace SrcMgr {
DoNotFreeFlag = 0x02
};
+ // Note that the first member of this class is an aligned character buffer
+ // to ensure that this class has an alignment of 8 bytes. This wastes
+ // 8 bytes for every ContentCache object, but each of these corresponds to
+ // a file loaded into memory, so the 8 bytes doesn't seem terribly
+ // important. It is quite awkward to fit this aligner into any other part
+ // of the class due to the lack of portable ways to combine it with other
+ // members.
+ llvm::AlignedCharArray<8, 1> NonceAligner;
+
/// \brief The actual buffer containing the characters from the input
/// file.
///
@@ -136,7 +146,9 @@ namespace SrcMgr {
ContentCache(const FileEntry *Ent = 0)
: Buffer(0, false), OrigEntry(Ent), ContentsEntry(Ent),
SourceLineCache(0), NumLines(0), BufferOverridden(false),
- IsSystemFile(false) {}
+ IsSystemFile(false) {
+ (void)NonceAligner; // Silence warnings about unused member.
+ }
ContentCache(const FileEntry *Ent, const FileEntry *contentEnt)
: Buffer(0, false), OrigEntry(Ent), ContentsEntry(contentEnt),
@@ -224,6 +236,11 @@ namespace SrcMgr {
ContentCache &operator=(const ContentCache& RHS) LLVM_DELETED_FUNCTION;
};
+ // Assert that the \c ContentCache objects will always be 8-byte aligned so
+ // that we can pack 3 bits of integer into pointers to such objects.
+ static_assert(llvm::AlignOf<ContentCache>::Alignment >= 8,
+ "ContentCache must be 8-byte aligned.");
+
/// \brief Information about a FileID, basically just the logical file
/// that it represents and include stack information.
///
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 24a6fa612c..f9f7904cb3 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -283,7 +283,7 @@ public:
unsigned getLongLongAlign() const { return LongLongAlign; }
/// \brief Determine whether the __int128 type is supported on this target.
- bool hasInt128Type() const { return getPointerWidth(0) >= 64; } // FIXME
+ virtual bool hasInt128Type() const { return getPointerWidth(0) >= 64; } // FIXME
/// \brief Return the alignment that is suitable for storing any
/// object with a fundamental alignment requirement.
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 42ebcf8e9e..845a8b096f 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -365,6 +365,7 @@ KEYWORD(typeof , KEYGNU)
// MS Extensions
KEYWORD(__FUNCDNAME__ , KEYMS)
+KEYWORD(__FUNCSIG__ , KEYMS)
KEYWORD(L__FUNCTION__ , KEYMS)
TYPE_TRAIT_1(__is_interface_class, IsInterfaceClass, KEYMS)
TYPE_TRAIT_1(__is_sealed, IsSealed, KEYMS)
@@ -684,6 +685,11 @@ ANNOTATION(pragma_ms_pointers_to_members)
// handles them.
ANNOTATION(pragma_ms_vtordisp)
+// Annotation for all microsoft #pragmas...
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+ANNOTATION(pragma_ms_pragma)
+
// Annotation for #pragma OPENCL EXTENSION...
// The lexer produces these so that they only take effect when the parser
// handles them.
diff --git a/include/clang/CodeGen/CGFunctionInfo.h b/include/clang/CodeGen/CGFunctionInfo.h
index e4a927292b..5cb92816da 100644
--- a/include/clang/CodeGen/CGFunctionInfo.h
+++ b/include/clang/CodeGen/CGFunctionInfo.h
@@ -151,6 +151,10 @@ public:
return PaddingType;
}
+ void setPaddingType(llvm::Type *T) {
+ PaddingType = T;
+ }
+
bool getPaddingInReg() const {
return PaddingInReg;
}
diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td
index d33e6b67f0..a4881e24ff 100644
--- a/include/clang/Driver/CLCompatOptions.td
+++ b/include/clang/Driver/CLCompatOptions.td
@@ -66,6 +66,10 @@ def _SLASH_Gy : CLFlag<"Gy">, HelpText<"Put each function in its own section">,
Alias<ffunction_sections>;
def _SLASH_Gy_ : CLFlag<"Gy-">, HelpText<"Don't put each function in its own section">,
Alias<fno_function_sections>;
+def _SLASH_Gw : CLFlag<"Gw">, HelpText<"Put each data item in its own section">,
+ Alias<fdata_sections>;
+def _SLASH_Gw_ : CLFlag<"Gw-">, HelpText<"Don't put each data item in its own section">,
+ Alias<fno_data_sections>;
def _SLASH_help : CLFlag<"help">, Alias<help>,
HelpText<"Display available options">;
def _SLASH_HELP : CLFlag<"HELP">, Alias<help>;
@@ -121,6 +125,8 @@ def _SLASH_WX : CLFlag<"WX">, HelpText<"Treat warnings as errors">,
def _SLASH_WX_ : CLFlag<"WX-">, HelpText<"Do not treat warnings as errors">,
Alias<W_Joined>, AliasArgs<["no-error"]>;
def _SLASH_w_flag : CLFlag<"w">, HelpText<"Disable all warnings">, Alias<w>;
+def _SLASH_wd4005 : CLFlag<"wd4005">, Alias<W_Joined>,
+ AliasArgs<["no-macro-redefined"]>;
def _SLASH_vd : CLJoined<"vd">, HelpText<"Control vtordisp placement">,
Alias<vtordisp_mode_EQ>;
def _SLASH_Z7 : CLFlag<"Z7">, Alias<gline_tables_only>;
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 33e058fde6..d6b22795e0 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -60,6 +60,7 @@ def I_Group : OptionGroup<"<I group>">, Group<CompileOnly_Group>;
def M_Group : OptionGroup<"<M group>">, Group<CompileOnly_Group>;
def T_Group : OptionGroup<"<T group>">;
def O_Group : OptionGroup<"<O group>">, Group<CompileOnly_Group>;
+def R_Group : OptionGroup<"<R group>">, Group<CompileOnly_Group>;
def W_Group : OptionGroup<"<W group>">, Group<CompileOnly_Group>;
def d_Group : OptionGroup<"<d group>">;
def f_Group : OptionGroup<"<f group>">, Group<CompileOnly_Group>;
@@ -253,7 +254,9 @@ def Qn : Flag<["-"], "Qn">;
def Qunused_arguments : Flag<["-"], "Qunused-arguments">, Flags<[DriverOption, CoreOption]>,
HelpText<"Don't emit warning for unused driver arguments">;
def Q : Flag<["-"], "Q">;
-def R : Flag<["-"], "R">;
+def Rpass_EQ : Joined<["-"], "Rpass=">, Group<R_Group>, Flags<[CC1Option]>,
+ HelpText<"Report transformations performed by optimization passes whose "
+ "name matches the given POSIX regular expression">;
def S : Flag<["-"], "S">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>,
HelpText<"Only run preprocess and compilation steps">;
def Tbss : JoinedOrSeparate<["-"], "Tbss">, Group<T_Group>;
@@ -580,6 +583,9 @@ def fmodules_prune_interval : Joined<["-"], "fmodules-prune-interval=">, Group<i
def fmodules_prune_after : Joined<["-"], "fmodules-prune-after=">, Group<i_Group>,
Flags<[CC1Option]>, MetaVarName<"<seconds>">,
HelpText<"Specify the interval (in seconds) after which a module file will be considered unused">;
+def fmodules_search_all : Flag <["-"], "fmodules-search-all">, Group<f_Group>,
+ Flags<[DriverOption, CC1Option]>,
+ HelpText<"Search even non-imported modules to resolve references">;
def fbuild_session_timestamp : Joined<["-"], "fbuild-session-timestamp=">,
Group<i_Group>, Flags<[CC1Option]>, MetaVarName<"<time since Epoch in seconds>">,
HelpText<"Time when the current build session started">;
@@ -607,6 +613,11 @@ def fmodules_ignore_macro : Joined<["-"], "fmodules-ignore-macro=">, Group<f_Gro
def fmodules_decluse : Flag <["-"], "fmodules-decluse">, Group<f_Group>,
Flags<[DriverOption,CC1Option]>,
HelpText<"Require declaration of modules used within a module">;
+def fmodules_strict_decluse : Flag <["-"], "fmodules-strict-decluse">, Group<f_Group>,
+ Flags<[DriverOption,CC1Option]>,
+ HelpText<"Like -fmodules-decluse but requires all headers to be in modules">;
+def fno_modules_search_all : Flag <["-"], "fno-modules-search-all">, Group<f_Group>,
+ Flags<[DriverOption, CC1Option]>;
def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group<f_Group>, Flags<[CC1Option]>;
def fmudflapth : Flag<["-"], "fmudflapth">, Group<f_Group>;
@@ -666,6 +677,8 @@ def fno_module_maps : Flag <["-"], "fno-module-maps">, Group<f_Group>,
Flags<[DriverOption]>;
def fno_modules_decluse : Flag <["-"], "fno-modules-decluse">, Group<f_Group>,
Flags<[DriverOption]>;
+def fno_modules_strict_decluse : Flag <["-"], "fno-strict-modules-decluse">, Group<f_Group>,
+ Flags<[DriverOption]>;
def fno_ms_extensions : Flag<["-"], "fno-ms-extensions">, Group<f_Group>;
def fno_ms_compatibility : Flag<["-"], "fno-ms-compatibility">, Group<f_Group>;
def fno_delayed_template_parsing : Flag<["-"], "fno-delayed-template-parsing">, Group<f_Group>;
@@ -687,7 +700,8 @@ def fno_spell_checking : Flag<["-"], "fno-spell-checking">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Disable spell-checking">;
def fno_stack_protector : Flag<["-"], "fno-stack-protector">, Group<f_Group>,
HelpText<"Disable the use of stack protectors">;
-def fno_strict_aliasing : Flag<["-"], "fno-strict-aliasing">, Group<f_Group>;
+def fno_strict_aliasing : Flag<["-"], "fno-strict-aliasing">, Group<f_Group>,
+ Flags<[DriverOption, CoreOption]>;
def fstruct_path_tbaa : Flag<["-"], "fstruct-path-tbaa">, Group<f_Group>;
def fno_struct_path_tbaa : Flag<["-"], "fno-struct-path-tbaa">, Group<f_Group>;
def fno_strict_enums : Flag<["-"], "fno-strict-enums">, Group<f_Group>;
@@ -799,7 +813,8 @@ def fno_standalone_debug : Flag<["-"], "fno-standalone-debug">, Group<f_Group>,
HelpText<"Limit debug information produced to reduce size of debug binary">;
def flimit_debug_info : Flag<["-"], "flimit-debug-info">, Alias<fno_standalone_debug>;
def fno_limit_debug_info : Flag<["-"], "fno-limit-debug-info">, Alias<fstandalone_debug>;
-def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group<f_Group>;
+def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group<f_Group>,
+ Flags<[DriverOption, CoreOption]>;
def fstrict_enums : Flag<["-"], "fstrict-enums">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable optimizations based on the strict definition of an enum's "
"value range">;
@@ -977,8 +992,10 @@ def keep__private__externs : Flag<["-"], "keep_private_externs">;
def l : JoinedOrSeparate<["-"], "l">, Flags<[LinkerInput, RenderJoined]>;
def lazy__framework : Separate<["-"], "lazy_framework">, Flags<[LinkerInput]>;
def lazy__library : Separate<["-"], "lazy_library">, Flags<[LinkerInput]>;
-def EL : Flag<["-"], "EL">, Flags<[DriverOption]>;
-def EB : Flag<["-"], "EB">, Flags<[DriverOption]>;
+def mlittle_endian : Flag<["-"], "mlittle-endian">, Flags<[DriverOption]>;
+def EL : Flag<["-"], "EL">, Alias<mlittle_endian>;
+def mbig_endian : Flag<["-"], "mbig-endian">, Flags<[DriverOption]>;
+def EB : Flag<["-"], "EB">, Alias<mbig_endian>;
def m16 : Flag<["-"], "m16">, Group<m_Group>, Flags<[DriverOption, CoreOption]>;
def m32 : Flag<["-"], "m32">, Group<m_Group>, Flags<[DriverOption, CoreOption]>;
def mqdsp6_compat : Flag<["-"], "mqdsp6-compat">, Group<m_Group>, Flags<[DriverOption,CC1Option]>,
diff --git a/include/clang/Edit/Commit.h b/include/clang/Edit/Commit.h
index 626b1dd630..0ff7034ba0 100644
--- a/include/clang/Edit/Commit.h
+++ b/include/clang/Edit/Commit.h
@@ -49,8 +49,7 @@ private:
const LangOptions &LangOpts;
const PPConditionalDirectiveRecord *PPRec;
EditedSource *Editor;
-
- const bool ForceCommitInSystemHeader;
+
bool IsCommitable;
SmallVector<Edit, 8> CachedEdits;
@@ -61,7 +60,7 @@ public:
Commit(const SourceManager &SM, const LangOptions &LangOpts,
const PPConditionalDirectiveRecord *PPRec = 0)
: SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec), Editor(0),
- ForceCommitInSystemHeader(true), IsCommitable(true) { }
+ IsCommitable(true) { }
bool isCommitable() const { return IsCommitable; }
diff --git a/include/clang/Edit/EditedSource.h b/include/clang/Edit/EditedSource.h
index f95b79785f..f9887cc9e8 100644
--- a/include/clang/Edit/EditedSource.h
+++ b/include/clang/Edit/EditedSource.h
@@ -28,7 +28,6 @@ class EditedSource {
const SourceManager &SourceMgr;
const LangOptions &LangOpts;
const PPConditionalDirectiveRecord *PPRec;
- const bool ForceCommitInSystemHeader;
struct FileEdit {
StringRef Text;
@@ -46,10 +45,8 @@ class EditedSource {
public:
EditedSource(const SourceManager &SM, const LangOptions &LangOpts,
- const PPConditionalDirectiveRecord *PPRec = 0,
- const bool FCommitInSystemHeader = true)
+ const PPConditionalDirectiveRecord *PPRec = 0)
: SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec),
- ForceCommitInSystemHeader(FCommitInSystemHeader),
StrAlloc() { }
const SourceManager &getSourceManager() const { return SourceMgr; }
@@ -57,10 +54,6 @@ public:
const PPConditionalDirectiveRecord *getPPCondDirectiveRecord() const {
return PPRec;
}
-
- bool getForceCommitInSystemHeader() const {
- return ForceCommitInSystemHeader;
- }
bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs);
diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h
index cded911edb..a48612105e 100644
--- a/include/clang/Format/Format.h
+++ b/include/clang/Format/Format.h
@@ -120,7 +120,10 @@ struct FormatStyle {
/// \brief The indentation used for namespaces.
NamespaceIndentationKind NamespaceIndentation;
- /// \brief The number of spaces to before trailing line comments.
+ /// \brief The number of spaces before trailing line comments (//-comments).
+ ///
+ /// This does not affect trailing block comments (/**/-comments) as those
+ /// commonly have different usage patterns and a number of special cases.
unsigned SpacesBeforeTrailingComments;
/// \brief If \c false, a function call's or function definition's parameters
@@ -163,12 +166,23 @@ struct FormatStyle {
/// single line.
bool AllowShortLoopsOnASingleLine;
- /// \brief If \c true, <tt>int f() { return 0; }</tt> can be put on a single
- /// line.
- bool AllowShortFunctionsOnASingleLine;
+ /// \brief Different styles for merging short functions containing at most one
+ /// statement.
+ enum ShortFunctionStyle {
+ /// \brief Never merge functions into a single line.
+ SFS_None,
+ /// \brief Only merge functions defined inside a class.
+ SFS_Inline,
+ /// \brief Merge all functions fitting on a single line.
+ SFS_All,
+ };
+
+ /// \brief Dependent on the value, <tt>int f() { return 0; }</tt> can be put
+ /// on a single line.
+ ShortFunctionStyle AllowShortFunctionsOnASingleLine;
/// \brief Add a space after \c @property in Objective-C, i.e. use
- /// <tt>@property (readonly)</tt> instead of <tt>@property(readonly)</tt>.
+ /// <tt>\@property (readonly)</tt> instead of <tt>\@property(readonly)</tt>.
bool ObjCSpaceAfterProperty;
/// \brief Add a space in front of an Objective-C protocol list, i.e. use
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 3a26df3ef3..17675c3037 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -499,7 +499,12 @@ public:
bool hasSema() const { return (bool)TheSema; }
Sema &getSema() const {
assert(TheSema && "ASTUnit does not have a Sema object!");
- return *TheSema;
+ return *TheSema;
+ }
+
+ const LangOptions &getLangOpts() const {
+ assert(LangOpts && " ASTUnit does not have language options");
+ return *LangOpts;
}
const FileManager &getFileManager() const { return *FileMgr; }
@@ -770,15 +775,13 @@ public:
//
// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we
// shouldn't need to specify them at construction time.
- static ASTUnit *LoadFromCompilerInvocation(CompilerInvocation *CI,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
- bool OnlyLocalDecls = false,
- bool CaptureDiagnostics = false,
- bool PrecompilePreamble = false,
- TranslationUnitKind TUKind = TU_Complete,
- bool CacheCodeCompletionResults = false,
- bool IncludeBriefCommentsInCodeCompletion = false,
- bool UserFilesAreVolatile = false);
+ static std::unique_ptr<ASTUnit> LoadFromCompilerInvocation(
+ CompilerInvocation *CI, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ bool OnlyLocalDecls = false, bool CaptureDiagnostics = false,
+ bool PrecompilePreamble = false, TranslationUnitKind TUKind = TU_Complete,
+ bool CacheCodeCompletionResults = false,
+ bool IncludeBriefCommentsInCodeCompletion = false,
+ bool UserFilesAreVolatile = false);
/// LoadFromCommandLine - Create an ASTUnit from a vector of command line
/// arguments, which must specify exactly one source file.
@@ -869,6 +872,10 @@ public:
void makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc, bool Complain) override {}
+ GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
+ { return 0; }
+ bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
+ { return 0; };
};
} // namespace clang
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index da97e5c956..9c8de1b5ce 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -16,6 +16,7 @@
#include <string>
#include <vector>
+#include "llvm/Support/Regex.h"
namespace clang {
@@ -145,6 +146,13 @@ public:
/// Name of the profile file to use as input for -fprofile-instr-use
std::string InstrProfileInput;
+ /// Regular expression to select optimizations for which we should enable
+ /// optimization remarks. Transformation passes whose name matches this
+ /// expression (and support this feature), will emit a diagnostic
+ /// whenever they perform a transformation. This is enabled by the
+ /// -Rpass=regexp flag.
+ std::shared_ptr<llvm::Regex> OptimizationRemarkPattern;
+
public:
// Define accessors/mutators for code generation options of enumeration type.
#define CODEGENOPT(Name, Bits, Default)
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index ee97d9bec3..cefd172faf 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -124,6 +124,9 @@ class CompilerInstance : public ModuleLoader {
/// have finished with this translation unit.
bool BuildGlobalModuleIndex;
+ /// \brief We have a full global module index, with all modules.
+ bool HaveFullGlobalModuleIndex;
+
/// \brief One or more modules failed to build.
bool ModuleBuildFailed;
@@ -148,7 +151,7 @@ class CompilerInstance : public ModuleLoader {
CompilerInstance(const CompilerInstance &) LLVM_DELETED_FUNCTION;
void operator=(const CompilerInstance &) LLVM_DELETED_FUNCTION;
public:
- CompilerInstance();
+ explicit CompilerInstance(bool BuildingModule = false);
~CompilerInstance();
/// @name High-Level Operations
@@ -452,6 +455,7 @@ public:
}
Sema *takeSema() { return TheSema.release(); }
+ void resetAndLeakSema() { BuryPointer(TheSema.release()); }
/// }
/// @name Module Management
@@ -683,6 +687,9 @@ public:
/// }
+ // Create module manager.
+ void createModuleManager();
+
ModuleLoadResult loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
Module::NameVisibilityKind Visibility,
bool IsInclusionDirective) override;
@@ -694,6 +701,9 @@ public:
return ModuleLoader::HadFatalFailure;
}
+ GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override;
+
+ bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override;
};
} // end namespace clang
diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h
index f64773c2c4..7258dbeb2a 100644
--- a/include/clang/Frontend/CompilerInvocation.h
+++ b/include/clang/Frontend/CompilerInvocation.h
@@ -204,6 +204,14 @@ public:
/// @}
};
+namespace vfs {
+ class FileSystem;
+}
+
+IntrusiveRefCntPtr<vfs::FileSystem>
+createVFSFromCompilerInvocation(const CompilerInvocation &CI,
+ DiagnosticsEngine &Diags);
+
} // end namespace clang
#endif
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index a5db2523d2..0e2664ccb4 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -17,6 +17,7 @@
namespace clang {
class Module;
+class FileEntry;
//===----------------------------------------------------------------------===//
// Custom Consumer Actions
@@ -93,6 +94,7 @@ public:
class GenerateModuleAction : public ASTFrontendAction {
clang::Module *Module;
+ const FileEntry *ModuleMapForUniquing;
bool IsSystem;
protected:
@@ -106,8 +108,10 @@ protected:
bool hasASTFileSupport() const override { return false; }
public:
- explicit GenerateModuleAction(bool IsSystem = false)
- : ASTFrontendAction(), IsSystem(IsSystem) { }
+ GenerateModuleAction(const FileEntry *ModuleMap = nullptr,
+ bool IsSystem = false)
+ : ASTFrontendAction(), ModuleMapForUniquing(ModuleMap), IsSystem(IsSystem)
+ { }
bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename) override;
@@ -115,11 +119,11 @@ public:
/// create the PCHGenerator instance returned by CreateASTConsumer.
///
/// \returns true if an error occurred, false otherwise.
- static bool ComputeASTConsumerArguments(CompilerInstance &CI,
- StringRef InFile,
- std::string &Sysroot,
- std::string &OutputFile,
- raw_ostream *&OS);
+ bool ComputeASTConsumerArguments(CompilerInstance &CI,
+ StringRef InFile,
+ std::string &Sysroot,
+ std::string &OutputFile,
+ raw_ostream *&OS);
};
class SyntaxOnlyAction : public ASTFrontendAction {
diff --git a/include/clang/Frontend/VerifyDiagnosticConsumer.h b/include/clang/Frontend/VerifyDiagnosticConsumer.h
index 39678ef44b..fb026bbc2b 100644
--- a/include/clang/Frontend/VerifyDiagnosticConsumer.h
+++ b/include/clang/Frontend/VerifyDiagnosticConsumer.h
@@ -186,11 +186,13 @@ public:
DirectiveList Warnings;
DirectiveList Notes;
- ~ExpectedData() {
+ void Reset() {
llvm::DeleteContainerPointers(Errors);
llvm::DeleteContainerPointers(Warnings);
llvm::DeleteContainerPointers(Notes);
}
+
+ ~ExpectedData() { Reset(); }
};
enum DirectiveStatus {
diff --git a/include/clang/Index/CommentToXML.h b/include/clang/Index/CommentToXML.h
index 8444b14534..bb7b71ad41 100644
--- a/include/clang/Index/CommentToXML.h
+++ b/include/clang/Index/CommentToXML.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_INDEX_COMMENTTOXML_H
#include "clang/Basic/LLVM.h"
+#include <memory>
namespace clang {
class ASTContext;
@@ -24,11 +25,12 @@ namespace index {
class SimpleFormatContext;
class CommentToXMLConverter {
- SimpleFormatContext *FormatContext;
+ std::unique_ptr<SimpleFormatContext> FormatContext;
unsigned FormatInMemoryUniqueId;
public:
- CommentToXMLConverter() : FormatContext(0), FormatInMemoryUniqueId(0) {}
+ CommentToXMLConverter();
+ ~CommentToXMLConverter();
void convertCommentToHTML(const comments::FullComment *FC,
SmallVectorImpl<char> &HTML,
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index c3af6335a0..a62a710d78 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -493,9 +493,12 @@ public:
///
/// \param ModuleName The module whose module file name will be returned.
///
+ /// \param ModuleMapPath A path that when combined with \c ModuleName
+ /// uniquely identifies this module. See Module::ModuleMap.
+ ///
/// \returns The name of the module file that corresponds to this module,
/// or an empty string if this module does not correspond to any module file.
- std::string getModuleFileName(StringRef ModuleName);
+ std::string getModuleFileName(StringRef ModuleName, StringRef ModuleMapPath);
/// \brief Lookup a module Search for a module with the given name.
///
@@ -508,7 +511,6 @@ public:
/// \returns The module with the given name.
Module *lookupModule(StringRef ModuleName, bool AllowSearch = true);
-
/// \brief Try to find a module map file in the given directory, returning
/// \c nullptr if none is found.
const FileEntry *lookupModuleMapFile(const DirectoryEntry *Dir,
diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h
index 1580d1b693..cfbb376c16 100644
--- a/include/clang/Lex/MacroInfo.h
+++ b/include/clang/Lex/MacroInfo.h
@@ -104,6 +104,9 @@ private:
/// \brief Whether this macro info was loaded from an AST file.
unsigned FromASTFile : 1;
+ /// \brief Whether this macro was used as header guard.
+ bool UsedForHeaderGuard : 1;
+
~MacroInfo() {
assert(ArgumentList == 0 && "Didn't call destroy before dtor!");
}
@@ -282,6 +285,11 @@ public:
/// a precompiled header or module) rather than having been parsed.
bool isFromASTFile() const { return FromASTFile; }
+ /// \brief Determine whether this macro was used for a header guard.
+ bool isUsedForHeaderGuard() const { return UsedForHeaderGuard; }
+
+ void setUsedForHeaderGuard(bool Val) { UsedForHeaderGuard = Val; }
+
/// \brief Retrieve the global ID of the module that owns this particular
/// macro info.
unsigned getOwningModuleID() const {
diff --git a/include/clang/Lex/ModuleLoader.h b/include/clang/Lex/ModuleLoader.h
index 254ab36fe9..7869799c2c 100644
--- a/include/clang/Lex/ModuleLoader.h
+++ b/include/clang/Lex/ModuleLoader.h
@@ -21,6 +21,7 @@
namespace clang {
+class GlobalModuleIndex;
class IdentifierInfo;
class Module;
@@ -53,11 +54,24 @@ public:
/// for resolving a module name (e.g., "std") to an actual module file, and
/// then loading that module.
class ModuleLoader {
+ // Building a module if true.
+ bool BuildingModule;
public:
- ModuleLoader() : HadFatalFailure(false) {}
+ explicit ModuleLoader(bool BuildingModule = false) :
+ BuildingModule(BuildingModule),
+ HadFatalFailure(false) {}
virtual ~ModuleLoader();
+ /// \brief Returns true if this instance is building a module.
+ bool buildingModule() const {
+ return BuildingModule;
+ }
+ /// \brief Flag indicating whether this instance is building a module.
+ void setBuildingModule(bool BuildingModuleFlag) {
+ BuildingModule = BuildingModuleFlag;
+ }
+
/// \brief Attempt to load the given module.
///
/// This routine attempts to load the module described by the given
@@ -88,6 +102,26 @@ public:
SourceLocation ImportLoc,
bool Complain) = 0;
+ /// \brief Load, create, or return global module.
+ /// This function returns an existing global module index, if one
+ /// had already been loaded or created, or loads one if it
+ /// exists, or creates one if it doesn't exist.
+ /// Also, importantly, if the index doesn't cover all the modules
+ /// in the module map, it will be update to do so here, because
+ /// of its use in searching for needed module imports and
+ /// associated fixit messages.
+ /// \param TriggerLoc The location for what triggered the load.
+ /// \returns Returns null if load failed.
+ virtual GlobalModuleIndex *loadGlobalModuleIndex(
+ SourceLocation TriggerLoc) = 0;
+
+ /// Check global module index for missing imports.
+ /// \param Name The symbol name to look for.
+ /// \param TriggerLoc The location for what triggered the load.
+ /// \returns Returns true if any modules with that symbol found.
+ virtual bool lookupMissingImports(StringRef Name,
+ SourceLocation TriggerLoc) = 0;
+
bool HadFatalFailure;
};
diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h
index 1cd6d385b6..dbd9fd1c0c 100644
--- a/include/clang/Lex/ModuleMap.h
+++ b/include/clang/Lex/ModuleMap.h
@@ -131,6 +131,10 @@ private:
/// \brief Whether the modules we infer are [system] modules.
unsigned InferSystemModules : 1;
+ /// \brief If \c InferModules is non-zero, the module map file that allowed
+ /// inferred modules. Otherwise, nullptr.
+ const FileEntry *ModuleMapFile;
+
/// \brief The names of modules that cannot be inferred within this
/// directory.
SmallVector<std::string, 2> ExcludedModules;
@@ -182,6 +186,15 @@ private:
/// associated with a specific module (e.g. in /usr/include).
HeadersMap::iterator findKnownHeader(const FileEntry *File);
+ /// \brief Searches for a module whose umbrella directory contains \p File.
+ ///
+ /// \param File The header to search for.
+ ///
+ /// \param IntermediateDirs On success, contains the set of directories
+ /// searched before finding \p File.
+ KnownHeader findHeaderInUmbrellaDirs(const FileEntry *File,
+ SmallVectorImpl<const DirectoryEntry *> &IntermediateDirs);
+
public:
/// \brief Construct a new module map.
///
@@ -242,6 +255,11 @@ public:
/// marked 'unavailable'.
bool isHeaderInUnavailableModule(const FileEntry *Header) const;
+ /// \brief Determine whether the given header is unavailable as part
+ /// of the specified module.
+ bool isHeaderUnavailableInModule(const FileEntry *Header,
+ const Module *RequestingModule) const;
+
/// \brief Retrieve a module with the given name.
///
/// \param Name The name of the module to look up.
@@ -279,13 +297,17 @@ public:
/// \param Parent The module that will act as the parent of this submodule,
/// or NULL to indicate that this is a top-level module.
///
+ /// \param ModuleMap The module map that defines or allows the inference of
+ /// this module.
+ ///
/// \param IsFramework Whether this is a framework module.
///
/// \param IsExplicit Whether this is an explicit submodule.
///
/// \returns The found or newly-created module, along with a boolean value
/// that will be true if the module is newly-created.
- std::pair<Module *, bool> findOrCreateModule(StringRef Name, Module *Parent,
+ std::pair<Module *, bool> findOrCreateModule(StringRef Name, Module *Parent,
+ const FileEntry *ModuleMap,
bool IsFramework,
bool IsExplicit);
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 54dee61493..83af8fb3ca 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -125,6 +125,7 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
IdentifierInfo *Ident__has_include; // __has_include
IdentifierInfo *Ident__has_include_next; // __has_include_next
IdentifierInfo *Ident__has_warning; // __has_warning
+ IdentifierInfo *Ident__is_identifier; // __is_identifier
IdentifierInfo *Ident__building_module; // __building_module
IdentifierInfo *Ident__MODULE__; // __MODULE__
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 44f7cb1e05..5c72b91bde 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -154,6 +154,12 @@ class Parser : public CodeCompletionHandler {
std::unique_ptr<PragmaHandler> MSDetectMismatchHandler;
std::unique_ptr<PragmaHandler> MSPointersToMembers;
std::unique_ptr<PragmaHandler> MSVtorDisp;
+ std::unique_ptr<PragmaHandler> MSInitSeg;
+ std::unique_ptr<PragmaHandler> MSDataSeg;
+ std::unique_ptr<PragmaHandler> MSBSSSeg;
+ std::unique_ptr<PragmaHandler> MSConstSeg;
+ std::unique_ptr<PragmaHandler> MSCodeSeg;
+ std::unique_ptr<PragmaHandler> MSSection;
std::unique_ptr<CommentHandler> CommentSemaHandler;
@@ -475,6 +481,14 @@ private:
void HandlePragmaMSVtorDisp();
+ void HandlePragmaMSPragma();
+ unsigned HandlePragmaMSSection(llvm::StringRef PragmaName,
+ SourceLocation PragmaLocation);
+ unsigned HandlePragmaMSSegment(llvm::StringRef PragmaName,
+ SourceLocation PragmaLocation);
+ unsigned HandlePragmaMSInitSeg(llvm::StringRef PragmaName,
+ SourceLocation PragmaLocation);
+
/// \brief Handle the annotation token produced for
/// #pragma align...
void HandlePragmaAlign();
@@ -1998,13 +2012,13 @@ private:
/// \brief Parses syntax-generic attribute arguments for attributes which are
/// known to the implementation, and adds them to the given ParsedAttributes
- /// list with the given attribute syntax.
- void ParseAttributeArgsCommon(IdentifierInfo *AttrName,
- SourceLocation AttrNameLoc,
- ParsedAttributes &Attrs, SourceLocation *EndLoc,
- IdentifierInfo *ScopeName,
- SourceLocation ScopeLoc,
- AttributeList::Syntax Syntax);
+ /// list with the given attribute syntax. Returns the number of arguments
+ /// parsed for the attribute.
+ unsigned
+ ParseAttributeArgsCommon(IdentifierInfo *AttrName, SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs, SourceLocation *EndLoc,
+ IdentifierInfo *ScopeName, SourceLocation ScopeLoc,
+ AttributeList::Syntax Syntax);
void MaybeParseGNUAttributes(Declarator &D,
LateParsedAttrList *LateAttrs = 0) {
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 2cd10da718..948fb9cbfd 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -1414,8 +1414,8 @@ struct DeclaratorChunk {
/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
/// "TheDeclarator" is the declarator that this will be added to.
- static DeclaratorChunk getFunction(bool hasProto,
- bool isAmbiguous,
+ static DeclaratorChunk getFunction(bool HasProto,
+ bool IsAmbiguous,
SourceLocation LParenLoc,
ParamInfo *Params, unsigned NumParams,
SourceLocation EllipsisLoc,
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index 7086b723d4..83d8677d9b 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -684,6 +684,18 @@ namespace clang {
/// OverloadCandidateSet - A set of overload candidates, used in C++
/// overload resolution (C++ 13.3).
class OverloadCandidateSet {
+ public:
+ enum CandidateSetKind {
+ /// Normal lookup.
+ CSK_Normal,
+ /// Lookup for candidates for a call using operator syntax. Candidates
+ /// that have no parameters of class type will be skipped unless there
+ /// is a parameter of (reference to) enum type and the corresponding
+ /// argument is of the same enum type.
+ CSK_Operator
+ };
+
+ private:
SmallVector<OverloadCandidate, 16> Candidates;
llvm::SmallPtrSet<Decl *, 16> Functions;
@@ -692,6 +704,7 @@ namespace clang {
llvm::BumpPtrAllocator ConversionSequenceAllocator;
SourceLocation Loc;
+ CandidateSetKind Kind;
unsigned NumInlineSequences;
char InlineSpace[16 * sizeof(ImplicitConversionSequence)];
@@ -702,10 +715,12 @@ namespace clang {
void destroyCandidates();
public:
- OverloadCandidateSet(SourceLocation Loc) : Loc(Loc), NumInlineSequences(0){}
+ OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK)
+ : Loc(Loc), Kind(CSK), NumInlineSequences(0) {}
~OverloadCandidateSet() { destroyCandidates(); }
SourceLocation getLocation() const { return Loc; }
+ CandidateSetKind getKind() const { return Kind; }
/// \brief Determine when this overload candidate will be new to the
/// overload set.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index ea9344d483..4d4fd360a3 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -274,6 +274,15 @@ public:
PVDK_Reset ///< #pragma vtordisp()
};
+ enum PragmaMsStackAction {
+ PSK_Reset, // #pragma ()
+ PSK_Set, // #pragma ("name")
+ PSK_Push, // #pragma (push[, id])
+ PSK_Push_Set, // #pragma (push[, id], "name")
+ PSK_Pop, // #pragma (pop[, id])
+ PSK_Pop_Set, // #pragma (pop[, id], "name")
+ };
+
/// \brief Whether to insert vtordisps prior to virtual bases in the Microsoft
/// C++ ABI. Possible values are 0, 1, and 2, which mean:
///
@@ -289,6 +298,35 @@ public:
/// \brief Source location for newly created implicit MSInheritanceAttrs
SourceLocation ImplicitMSInheritanceAttrLoc;
+ template<typename ValueType>
+ struct PragmaStack {
+ struct Slot {
+ llvm::StringRef StackSlotLabel;
+ ValueType Value;
+ SourceLocation PragmaLocation;
+ Slot(llvm::StringRef StackSlotLabel,
+ ValueType Value,
+ SourceLocation PragmaLocation)
+ : StackSlotLabel(StackSlotLabel), Value(Value),
+ PragmaLocation(PragmaLocation) {}
+ };
+ void Act(SourceLocation PragmaLocation,
+ PragmaMsStackAction Action,
+ llvm::StringRef StackSlotLabel,
+ ValueType Value);
+ explicit PragmaStack(const ValueType &Value)
+ : CurrentValue(Value) {}
+ SmallVector<Slot, 2> Stack;
+ ValueType CurrentValue;
+ SourceLocation CurrentPragmaLocation;
+ };
+ // FIXME: We should serialize / deserialize these if they occur in a PCH (but
+ // we shouldn't do so if they're in a module).
+ PragmaStack<StringLiteral *> DataSegStack;
+ PragmaStack<StringLiteral *> BSSSegStack;
+ PragmaStack<StringLiteral *> ConstSegStack;
+ PragmaStack<StringLiteral *> CodeSegStack;
+
/// VisContext - Manages the stack for \#pragma GCC visibility.
void *VisContext; // Really a "PragmaVisStack*"
@@ -2239,7 +2277,7 @@ public:
SourceLocation OpLoc, ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet);
void AddArgumentDependentLookupCandidates(DeclarationName Name,
- bool Operator, SourceLocation Loc,
+ SourceLocation Loc,
ArrayRef<Expr *> Args,
TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
@@ -2526,6 +2564,9 @@ public:
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
QualType T1, QualType T2,
UnresolvedSetImpl &Functions);
+ void addOverloadedOperatorToUnresolvedSet(UnresolvedSetImpl &Functions,
+ DeclAccessPair Operator,
+ QualType T1, QualType T2);
LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation IdentLoc,
SourceLocation GnuLabelLoc = SourceLocation());
@@ -2550,10 +2591,8 @@ public:
bool AllowStringTemplate);
bool isKnownName(StringRef name);
- void ArgumentDependentLookup(DeclarationName Name, bool Operator,
- SourceLocation Loc,
- ArrayRef<Expr *> Args,
- ADLResult &Functions);
+ void ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
+ ArrayRef<Expr *> Args, ADLResult &Functions);
void LookupVisibleDecls(Scope *S, LookupNameKind Kind,
VisibleDeclConsumer &Consumer,
@@ -2562,10 +2601,16 @@ public:
VisibleDeclConsumer &Consumer,
bool IncludeGlobalScope = true);
+ enum CorrectTypoKind {
+ CTK_NonError, // CorrectTypo used in a non error recovery situation.
+ CTK_ErrorRecovery // CorrectTypo used in normal error recovery.
+ };
+
TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo,
Sema::LookupNameKind LookupKind,
Scope *S, CXXScopeSpec *SS,
CorrectionCandidateCallback &CCC,
+ CorrectTypoKind Mode,
DeclContext *MemberContext = 0,
bool EnteringContext = false,
const ObjCObjectPointerType *OPT = 0,
@@ -4386,7 +4431,8 @@ public:
bool EnteringContext,
CXXScopeSpec &SS,
NamedDecl *ScopeLookupResult,
- bool ErrorRecoveryLookup);
+ bool ErrorRecoveryLookup,
+ bool *IsCorrectedToColon = 0);
/// \brief The parser has parsed a nested-name-specifier 'identifier::'.
///
@@ -4409,6 +4455,13 @@ public:
/// output parameter (containing the full nested-name-specifier,
/// including this new type).
///
+ /// \param ErrorRecoveryLookup If true, then this method is called to improve
+ /// error recovery. In this case do not emit error message.
+ ///
+ /// \param IsCorrectedToColon If not null, suggestions to replace '::' -> ':'
+ /// are allowed. The bool value pointed by this parameter is set to 'true'
+ /// if the identifier is treated as if it was followed by ':', not '::'.
+ ///
/// \returns true if an error occurred, false otherwise.
bool ActOnCXXNestedNameSpecifier(Scope *S,
IdentifierInfo &Identifier,
@@ -4416,7 +4469,9 @@ public:
SourceLocation CCLoc,
ParsedType ObjectType,
bool EnteringContext,
- CXXScopeSpec &SS);
+ CXXScopeSpec &SS,
+ bool ErrorRecoveryLookup = false,
+ bool *IsCorrectedToColon = 0);
ExprResult ActOnDecltypeExpression(Expr *E);
@@ -5148,7 +5203,8 @@ public:
TemplateParamListContext TPC);
TemplateParameterList *MatchTemplateParametersToScopeSpecifier(
SourceLocation DeclStartLoc, SourceLocation DeclLoc,
- const CXXScopeSpec &SS, ArrayRef<TemplateParameterList *> ParamLists,
+ const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId,
+ ArrayRef<TemplateParameterList *> ParamLists,
bool IsFriend, bool &IsExplicitSpecialization, bool &Invalid);
DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
@@ -5230,12 +5286,7 @@ public:
ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc,
SourceLocation ModulePrivateLoc,
- CXXScopeSpec &SS,
- TemplateTy Template,
- SourceLocation TemplateNameLoc,
- SourceLocation LAngleLoc,
- ASTTemplateArgsPtr TemplateArgs,
- SourceLocation RAngleLoc,
+ TemplateIdAnnotation &TemplateId,
AttributeList *Attr,
MultiTemplateParamsArg TemplateParameterLists);
@@ -7031,6 +7082,54 @@ public:
void ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind, SourceLocation PragmaLoc,
MSVtorDispAttr::Mode Value);
+ enum PragmaSectionKind {
+ PSK_DataSeg,
+ PSK_BSSSeg,
+ PSK_ConstSeg,
+ PSK_CodeSeg,
+ };
+
+ enum PragmaSectionFlag : unsigned {
+ PSF_None = 0,
+ PSF_Read = 0x1,
+ PSF_Write = 0x2,
+ PSF_Execute = 0x4,
+ PSF_Implicit = 0x8,
+ PSF_Invalid = 0x80000000U,
+ };
+
+ struct SectionInfo {
+ DeclaratorDecl *Decl;
+ SourceLocation PragmaSectionLocation;
+ int SectionFlags;
+ SectionInfo() {}
+ SectionInfo(DeclaratorDecl *Decl,
+ SourceLocation PragmaSectionLocation,
+ int SectionFlags)
+ : Decl(Decl),
+ PragmaSectionLocation(PragmaSectionLocation),
+ SectionFlags(SectionFlags) {}
+ };
+
+ llvm::StringMap<SectionInfo> SectionInfos;
+ bool UnifySection(const StringRef &SectionName,
+ int SectionFlags,
+ DeclaratorDecl *TheDecl);
+ bool UnifySection(const StringRef &SectionName,
+ int SectionFlags,
+ SourceLocation PragmaSectionLocation);
+
+ /// \brief Called on well formed \#pragma bss_seg/data_seg/const_seg/code_seg.
+ void ActOnPragmaMSSeg(SourceLocation PragmaLocation,
+ PragmaMsStackAction Action,
+ llvm::StringRef StackSlotLabel,
+ StringLiteral *SegmentName,
+ llvm::StringRef PragmaName);
+
+ /// \brief Called on well formed \#pragma section().
+ void ActOnPragmaMSSection(SourceLocation PragmaLocation,
+ int SectionFlags, StringLiteral *SegmentName);
+
/// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch
void ActOnPragmaDetectMismatch(StringRef Name, StringRef Value);
@@ -7193,8 +7292,10 @@ public:
OMPClause *ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
ArrayRef<Expr *> Vars,
+ Expr *TailExpr,
SourceLocation StartLoc,
SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
SourceLocation EndLoc);
/// \brief Called on well-formed 'private' clause.
OMPClause *ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
@@ -7211,6 +7312,13 @@ public:
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
+ /// \brief Called on well-formed 'linear' clause.
+ OMPClause *ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList,
+ Expr *Step,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation EndLoc);
/// \brief Called on well-formed 'copyin' clause.
OMPClause *ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
@@ -7970,14 +8078,14 @@ public:
private:
bool SemaBuiltinPrefetch(CallExpr *TheCall);
- bool SemaBuiltinMMPrefetch(CallExpr *TheCall);
- bool SemaBuiltinObjectSize(CallExpr *TheCall);
bool SemaBuiltinLongjmp(CallExpr *TheCall);
ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult);
ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult,
AtomicExpr::AtomicOp Op);
bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
llvm::APSInt &Result);
+ bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum,
+ int Low, int High);
public:
enum FormatStringType {
diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h
index 16d732831a..2ef8d84fad 100644
--- a/include/clang/Sema/TypoCorrection.h
+++ b/include/clang/Sema/TypoCorrection.h
@@ -306,15 +306,15 @@ class FunctionCallFilterCCC : public CorrectionCandidateCallback {
public:
FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
bool HasExplicitTemplateArgs,
- bool AllowNonStaticMethods = true);
+ MemberExpr *ME = 0);
bool ValidateCandidate(const TypoCorrection &candidate) override;
private:
unsigned NumArgs;
bool HasExplicitTemplateArgs;
- bool AllowNonStaticMethods;
DeclContext *CurContext;
+ MemberExpr *MemberFn;
};
// @brief Callback class that effectively disabled typo correction
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 35765b67f0..89435f3afe 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -281,7 +281,14 @@ namespace clang {
HEADER_SEARCH_OPTIONS = 11,
/// \brief Record code for the preprocessor options table.
- PREPROCESSOR_OPTIONS = 12
+ PREPROCESSOR_OPTIONS = 12,
+
+ /// \brief Record code for the module name.
+ MODULE_NAME = 13,
+
+ /// \brief Record code for the module map file that was used to build this
+ /// AST file.
+ MODULE_MAP_FILE = 14
};
/// \brief Record types that occur within the input-files block
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index b0fde2b266..0d2bfc6797 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -109,6 +109,9 @@ public:
return FullVersion != getClangFullRepositoryVersion();
}
+ virtual void ReadModuleName(StringRef ModuleName) {}
+ virtual void ReadModuleMapFile(StringRef ModuleMapPath) {}
+
/// \brief Receives the language options.
///
/// \returns true to indicate the options are invalid or false otherwise.
@@ -203,6 +206,8 @@ public:
: First(First), Second(Second) { }
bool ReadFullVersionInformation(StringRef FullVersion) override;
+ void ReadModuleName(StringRef ModuleName) override;
+ void ReadModuleMapFile(StringRef ModuleMapPath) override;
bool ReadLanguageOptions(const LangOptions &LangOpts, bool Complain) override;
bool ReadTargetOptions(const TargetOptions &TargetOpts,
bool Complain) override;
@@ -254,7 +259,7 @@ class ReadMethodPoolVisitor;
namespace reader {
class ASTIdentifierLookupTrait;
/// \brief The on-disk hash table used for the DeclContext's Name lookup table.
- typedef OnDiskChainedHashTable<ASTDeclContextNameLookupTrait>
+ typedef llvm::OnDiskIterableChainedHashTable<ASTDeclContextNameLookupTrait>
ASTDeclContextNameLookupTable;
}
@@ -409,6 +414,11 @@ private:
/// in the chain.
DeclUpdateOffsetsMap DeclUpdateOffsets;
+ /// \brief Declaration updates for already-loaded declarations that we need
+ /// to apply once we finish processing an import.
+ llvm::SmallVector<std::pair<serialization::GlobalDeclID, Decl*>, 16>
+ PendingUpdateRecords;
+
struct ReplacedDeclInfo {
ModuleFile *Mod;
uint64_t Offset;
@@ -951,6 +961,13 @@ private:
/// once recursing loading has been completed.
llvm::SmallVector<NamedDecl *, 16> PendingOdrMergeChecks;
+ /// \brief Record definitions in which we found an ODR violation.
+ llvm::SmallDenseMap<CXXRecordDecl*, llvm::SmallVector<CXXRecordDecl*, 1>, 2>
+ PendingOdrMergeFailures;
+
+ /// \brief DeclContexts in which we have diagnosed an ODR violation.
+ llvm::SmallPtrSet<DeclContext*, 2> DiagnosedOdrMergeFailures;
+
/// \brief The set of Objective-C categories that have been deserialized
/// since the last time the declaration chains were linked.
llvm::SmallPtrSet<ObjCCategoryDecl *, 16> CategoriesDeserialized;
@@ -959,7 +976,14 @@ private:
/// loaded, for which we will need to check for categories whenever a new
/// module is loaded.
SmallVector<ObjCInterfaceDecl *, 16> ObjCClassesLoaded;
-
+
+ /// \brief A mapping from a primary context for a declaration chain to the
+ /// other declarations of that entity that also have name lookup tables.
+ /// Used when we merge together two class definitions that have different
+ /// sets of declared special member functions.
+ llvm::DenseMap<const DeclContext*, SmallVector<const DeclContext*, 2>>
+ MergedLookups;
+
typedef llvm::DenseMap<Decl *, SmallVector<serialization::DeclID, 2> >
MergedDeclsMap;
@@ -1079,13 +1103,15 @@ private:
unsigned ClientLoadCapabilities);
ASTReadResult ReadControlBlock(ModuleFile &F,
SmallVectorImpl<ImportedModule> &Loaded,
+ const ModuleFile *ImportedBy,
unsigned ClientLoadCapabilities);
- bool ReadASTBlock(ModuleFile &F);
+ ASTReadResult ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities);
bool ParseLineTable(ModuleFile &F, SmallVectorImpl<uint64_t> &Record);
bool ReadSourceManagerBlock(ModuleFile &F);
llvm::BitstreamCursor &SLocCursorForID(int ID);
SourceLocation getImportLocation(ModuleFile *F);
- bool ReadSubmoduleBlock(ModuleFile &F);
+ ASTReadResult ReadSubmoduleBlock(ModuleFile &F,
+ unsigned ClientLoadCapabilities);
static bool ParseLanguageOptions(const RecordData &Record, bool Complain,
ASTReaderListener &Listener);
static bool ParseTargetOptions(const RecordData &Record, bool Complain,
@@ -1358,6 +1384,12 @@ public:
/// \brief Determine whether this AST reader has a global index.
bool hasGlobalIndex() const { return (bool)GlobalIndex; }
+ /// \brief Return global module index.
+ GlobalModuleIndex *getGlobalIndex() { return GlobalIndex.get(); }
+
+ /// \brief Reset reader for a reload try.
+ void resetForReload() { TriedLoadingGlobalIndex = false; }
+
/// \brief Attempts to load the global index.
///
/// \returns true if loading the global index has failed for any reason.
@@ -1545,7 +1577,11 @@ public:
/// \brief Retrieve the module file that owns the given declaration, or NULL
/// if the declaration is not from a module file.
ModuleFile *getOwningModuleFile(const Decl *D);
-
+
+ /// \brief Get the best name we know for the module that owns the given
+ /// declaration, or an empty string if the declaration is not from a module.
+ std::string getOwningModuleNameForDiagnostic(const Decl *D);
+
/// \brief Returns the source location for the decl \p ID.
SourceLocation getSourceLocationForDeclID(serialization::GlobalDeclID ID);
@@ -1554,6 +1590,10 @@ public:
Decl *GetDecl(serialization::DeclID ID);
Decl *GetExternalDecl(uint32_t ID) override;
+ /// \brief Resolve a declaration ID into a declaration. Return 0 if it's not
+ /// been loaded yet.
+ Decl *GetExistingDecl(serialization::DeclID ID);
+
/// \brief Reads a declaration with the given local ID in the given module.
Decl *GetLocalDecl(ModuleFile &F, uint32_t LocalID) {
return GetDecl(getGlobalDeclID(F, LocalID));
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index 4d93c1e5c9..43228efcba 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -676,9 +676,7 @@ public:
void AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record);
/// \brief Mark a declaration context as needing an update.
- void AddUpdatedDeclContext(const DeclContext *DC) {
- UpdatedDeclContexts.insert(DC);
- }
+ void AddUpdatedDeclContext(const DeclContext *DC);
void RewriteDecl(const Decl *D) {
DeclsToRewrite.insert(D);
diff --git a/include/clang/Serialization/GlobalModuleIndex.h b/include/clang/Serialization/GlobalModuleIndex.h
index 0d9835a155..1f0d7523ec 100644
--- a/include/clang/Serialization/GlobalModuleIndex.h
+++ b/include/clang/Serialization/GlobalModuleIndex.h
@@ -186,6 +186,9 @@ public:
/// \brief Print statistics to standard error.
void printStats();
+ /// \brief Print debugging view to standard error.
+ void dump();
+
/// \brief Write a global index into the given
///
/// \param FileMgr The file manager to use to load module files.
diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h
index 469785de7c..4952039055 100644
--- a/include/clang/Serialization/Module.h
+++ b/include/clang/Serialization/Module.h
@@ -23,12 +23,16 @@
#include <memory>
#include <string>
+namespace llvm {
+template <typename Info> class OnDiskChainedHashTable;
+template <typename Info> class OnDiskIterableChainedHashTable;
+}
+
namespace clang {
class FileEntry;
class DeclContext;
class Module;
-template<typename Info> class OnDiskChainedHashTable;
namespace serialization {
@@ -49,7 +53,7 @@ struct DeclContextInfo {
DeclContextInfo()
: NameLookupTableData(), LexicalDecls(), NumLexicalDecls() {}
- OnDiskChainedHashTable<reader::ASTDeclContextNameLookupTrait>
+ llvm::OnDiskIterableChainedHashTable<reader::ASTDeclContextNameLookupTrait>
*NameLookupTableData; // an ASTDeclContextNameLookupTable.
const KindDeclIDPair *LexicalDecls;
unsigned NumLexicalDecls;
@@ -115,6 +119,9 @@ public:
/// \brief The file name of the module file.
std::string FileName;
+ /// \brief The name of the module.
+ std::string ModuleName;
+
std::string getTimestampFilename() const {
return FileName + ".timestamp";
}
@@ -136,6 +143,8 @@ public:
/// allow resolving headers even after headers+PCH was moved to a new path.
std::string OriginalDir;
+ std::string ModuleMapPath;
+
/// \brief Whether this precompiled header is a relocatable PCH file.
bool RelocatablePCH;
diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h
index 097a7a8a0b..a0d6cb789c 100644
--- a/include/clang/Tooling/Tooling.h
+++ b/include/clang/Tooling/Tooling.h
@@ -39,6 +39,7 @@
#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Twine.h"
+#include <memory>
#include <string>
#include <vector>
@@ -96,7 +97,7 @@ public:
/// FrontendActionFactory *Factory =
/// newFrontendActionFactory<clang::SyntaxOnlyAction>();
template <typename T>
-FrontendActionFactory *newFrontendActionFactory();
+std::unique_ptr<FrontendActionFactory> newFrontendActionFactory();
/// \brief Callbacks called before and after each source file processed by a
/// FrontendAction created by the FrontedActionFactory returned by \c
@@ -125,10 +126,10 @@ public:
/// struct ProvidesASTConsumers {
/// clang::ASTConsumer *newASTConsumer();
/// } Factory;
-/// FrontendActionFactory *FactoryAdapter =
-/// newFrontendActionFactory(&Factory);
+/// std::unique_ptr<FrontendActionFactory> FactoryAdapter(
+/// newFrontendActionFactory(&Factory));
template <typename FactoryT>
-inline FrontendActionFactory *newFrontendActionFactory(
+inline std::unique_ptr<FrontendActionFactory> newFrontendActionFactory(
FactoryT *ConsumerFactory, SourceFileCallbacks *Callbacks = NULL);
/// \brief Runs (and deletes) the tool on 'Code' with the -fsyntax-only flag.
@@ -160,8 +161,8 @@ bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
/// \param FileName The file name which 'Code' will be mapped as.
///
/// \return The resulting AST or null if an error occurred.
-ASTUnit *buildASTFromCode(const Twine &Code,
- const Twine &FileName = "input.cc");
+std::unique_ptr<ASTUnit> buildASTFromCode(const Twine &Code,
+ const Twine &FileName = "input.cc");
/// \brief Builds an AST for 'Code' with additional flags.
///
@@ -170,9 +171,10 @@ ASTUnit *buildASTFromCode(const Twine &Code,
/// \param FileName The file name which 'Code' will be mapped as.
///
/// \return The resulting AST or null if an error occurred.
-ASTUnit *buildASTFromCodeWithArgs(const Twine &Code,
- const std::vector<std::string> &Args,
- const Twine &FileName = "input.cc");
+std::unique_ptr<ASTUnit>
+buildASTFromCodeWithArgs(const Twine &Code,
+ const std::vector<std::string> &Args,
+ const Twine &FileName = "input.cc");
/// \brief Utility to run a FrontendAction in a single clang invocation.
class ToolInvocation {
@@ -282,7 +284,7 @@ class ClangTool {
/// \brief Create an AST for each file specified in the command line and
/// append them to ASTs.
- int buildASTs(std::vector<ASTUnit *> &ASTs);
+ int buildASTs(std::vector<std::unique_ptr<ASTUnit>> &ASTs);
/// \brief Returns the file manager used in the tool.
///
@@ -303,17 +305,18 @@ class ClangTool {
};
template <typename T>
-FrontendActionFactory *newFrontendActionFactory() {
+std::unique_ptr<FrontendActionFactory> newFrontendActionFactory() {
class SimpleFrontendActionFactory : public FrontendActionFactory {
public:
clang::FrontendAction *create() override { return new T; }
};
- return new SimpleFrontendActionFactory;
+ return std::unique_ptr<FrontendActionFactory>(
+ new SimpleFrontendActionFactory);
}
template <typename FactoryT>
-inline FrontendActionFactory *newFrontendActionFactory(
+inline std::unique_ptr<FrontendActionFactory> newFrontendActionFactory(
FactoryT *ConsumerFactory, SourceFileCallbacks *Callbacks) {
class FrontendActionFactoryAdapter : public FrontendActionFactory {
public:
@@ -360,7 +363,8 @@ inline FrontendActionFactory *newFrontendActionFactory(
SourceFileCallbacks *Callbacks;
};
- return new FrontendActionFactoryAdapter(ConsumerFactory, Callbacks);
+ return std::unique_ptr<FrontendActionFactory>(
+ new FrontendActionFactoryAdapter(ConsumerFactory, Callbacks));
}
/// \brief Returns the absolute path of \c File, by prepending it with
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index 3ae6724edc..11837f79d6 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -124,7 +124,7 @@ protected:
NSAPIObj.reset(new NSAPI(Context));
Editor.reset(new edit::EditedSource(Context.getSourceManager(),
Context.getLangOpts(),
- PPRec, false));
+ PPRec));
}
bool HandleTopLevelDecl(DeclGroupRef DG) override {
@@ -1698,34 +1698,6 @@ private:
}
-static bool
-IsReallyASystemHeader(ASTContext &Ctx, const FileEntry *file, FileID FID) {
- bool Invalid = false;
- const SrcMgr::SLocEntry &SEntry =
- Ctx.getSourceManager().getSLocEntry(FID, &Invalid);
- if (!Invalid && SEntry.isFile()) {
- const SrcMgr::FileInfo &FI = SEntry.getFile();
- if (!FI.hasLineDirectives()) {
- if (FI.getFileCharacteristic() == SrcMgr::C_ExternCSystem)
- return true;
- if (FI.getFileCharacteristic() == SrcMgr::C_System) {
- // This file is in a system header directory. Continue committing
- // change only if it's a user-specified system directory because user
- // put a .system_framework file in the framework directory.
- StringRef Directory(file->getDir()->getName());
- size_t Ix = Directory.rfind(".framework");
- if (Ix == StringRef::npos)
- return true;
- std::string PatchToSystemFramework = Directory.slice(0, Ix+sizeof(".framework"));
- PatchToSystemFramework += ".system_framework";
- if (!llvm::sys::fs::exists(PatchToSystemFramework.data()))
- return true;
- }
- }
- }
- return false;
-}
-
void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
@@ -1847,8 +1819,6 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
RewriteBuffer &buf = I->second;
const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
assert(file);
- if (IsReallyASystemHeader(Ctx, file, FID))
- continue;
SmallString<512> newText;
llvm::raw_svector_ostream vecOS(newText);
buf.write(vecOS);
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 3ed2a9ff1c..84abda2dea 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -422,6 +422,8 @@ comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC,
ThisDeclInfo->IsFilled = false;
ThisDeclInfo->fill();
ThisDeclInfo->CommentDecl = FC->getDecl();
+ if (!ThisDeclInfo->TemplateParameters)
+ ThisDeclInfo->TemplateParameters = FC->getDeclInfo()->TemplateParameters;
comments::FullComment *CFC =
new (*this) comments::FullComment(FC->getBlocks(),
ThisDeclInfo);
@@ -1322,7 +1324,9 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const {
Align = std::max(Align, Target->getLargeArrayAlign());
}
- // Walk through any array types while we're at it.
+ // Keep track of extra alignment requirements on the array itself, then
+ // work with the element type.
+ Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr()));
T = getBaseElementType(arrayType);
}
Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr()));
@@ -3559,12 +3563,28 @@ bool ASTContext::QIdProtocolsAdoptObjCObjectProtocols(QualType QT,
CollectInheritedProtocols(IDecl, InheritedProtocols);
if (InheritedProtocols.empty())
return false;
-
+ // Check that if every protocol in list of id<plist> conforms to a protcol
+ // of IDecl's, then bridge casting is ok.
+ bool Conforms = false;
+ for (auto *Proto : OPT->quals()) {
+ Conforms = false;
+ for (auto *PI : InheritedProtocols) {
+ if (ProtocolCompatibleWithProtocol(Proto, PI)) {
+ Conforms = true;
+ break;
+ }
+ }
+ if (!Conforms)
+ break;
+ }
+ if (Conforms)
+ return true;
+
for (auto *PI : InheritedProtocols) {
// If both the right and left sides have qualifiers.
bool Adopts = false;
for (auto *Proto : OPT->quals()) {
- // return 'true' if '*PI' is in the inheritance hierarchy of Proto
+ // return 'true' if 'PI' is in the inheritance hierarchy of Proto
if ((Adopts = ProtocolCompatibleWithProtocol(PI, Proto)))
break;
}
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 7c6bec4503..539e666a48 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -228,6 +228,20 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
return S;
}
}
+
+ // Give some additional info on vector types. These are either not desugared
+ // or displaying complex __attribute__ expressions so add details of the
+ // type and element count.
+ if (Ty->isVectorType()) {
+ const VectorType *VTy = Ty->getAs<VectorType>();
+ std::string DecoratedString;
+ llvm::raw_string_ostream OS(DecoratedString);
+ const char *Values = VTy->getNumElements() > 1 ? "values" : "value";
+ OS << "'" << S << "' (vector of " << VTy->getNumElements() << " '"
+ << VTy->getElementType().getAsString(Context.getPrintingPolicy())
+ << "' " << Values << ")";
+ return OS.str();
+ }
}
S = "'" + S + "'";
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index dcfba3e339..39019792ee 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -1684,6 +1684,7 @@ void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) {
case PredefinedExpr::FuncDName: OS << " __FUNCDNAME__"; break;
case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
+ case PredefinedExpr::FuncSig: OS << " __FUNCSIG__"; break;
}
}
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index e51f8781c1..5a0bf37739 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -467,6 +467,11 @@ void Sema::actOnHTMLStartTagFinish(
SourceLocation GreaterLoc,
bool IsSelfClosing) {
Tag->setAttrs(Attrs);
+ for (const auto &Attr : Attrs) {
+ if (!isHTMLAttributeSafeToPassThrough(Attr.Name))
+ Tag->setUnsafeToPassThrough();
+ }
+
Tag->setGreaterLoc(GreaterLoc);
if (IsSelfClosing)
Tag->setSelfClosing();
@@ -482,6 +487,7 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
if (isHTMLEndTagForbidden(TagName)) {
Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
<< TagName << HET->getSourceRange();
+ HET->setUnsafeToPassThrough();
return HET;
}
@@ -497,14 +503,19 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
if (!FoundOpen) {
Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
<< HET->getSourceRange();
+ HET->setUnsafeToPassThrough();
return HET;
}
while (!HTMLOpenTags.empty()) {
- const HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
+ HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
StringRef LastNotClosedTagName = HST->getTagName();
- if (LastNotClosedTagName == TagName)
+ if (LastNotClosedTagName == TagName) {
+ // If the start tag is unsafe, end tag is unsafe as well.
+ if (!HST->isSafeToPassThrough())
+ HET->setUnsafeToPassThrough();
break;
+ }
if (isHTMLEndTagOptional(LastNotClosedTagName))
continue;
@@ -518,16 +529,18 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
HET->getLocation(),
&CloseLineInvalid);
- if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine)
+ if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
<< HST->getTagName() << HET->getTagName()
<< HST->getSourceRange() << HET->getSourceRange();
- else {
+ HST->setUnsafeToPassThrough();
+ } else {
Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
<< HST->getTagName() << HET->getTagName()
<< HST->getSourceRange();
Diag(HET->getLocation(), diag::note_doc_html_end_tag)
<< HET->getSourceRange();
+ HST->setUnsafeToPassThrough();
}
}
@@ -538,6 +551,18 @@ FullComment *Sema::actOnFullComment(
ArrayRef<BlockContentComment *> Blocks) {
FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
resolveParamCommandIndexes(FC);
+
+ // Complain about HTML tags that are not closed.
+ while (!HTMLOpenTags.empty()) {
+ HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
+ if (isHTMLEndTagOptional(HST->getTagName()))
+ continue;
+
+ Diag(HST->getLocation(), diag::warn_doc_html_missing_end_tag)
+ << HST->getTagName() << HST->getSourceRange();
+ HST->setUnsafeToPassThrough();
+ }
+
return FC;
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 15410f0e9b..ede419689f 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -227,23 +227,21 @@ getLVForType(const Type &T, LVComputationKind computation) {
/// template parameter list. For visibility purposes, template
/// parameters are part of the signature of a template.
static LinkageInfo
-getLVForTemplateParameterList(const TemplateParameterList *params,
+getLVForTemplateParameterList(const TemplateParameterList *Params,
LVComputationKind computation) {
LinkageInfo LV;
- for (TemplateParameterList::const_iterator P = params->begin(),
- PEnd = params->end();
- P != PEnd; ++P) {
-
+ for (const NamedDecl *P : *Params) {
// Template type parameters are the most common and never
// contribute to visibility, pack or not.
- if (isa<TemplateTypeParmDecl>(*P))
+ if (isa<TemplateTypeParmDecl>(P))
continue;
// Non-type template parameters can be restricted by the value type, e.g.
// template <enum X> class A { ... };
// We have to be careful here, though, because we can be dealing with
// dependent types.
- if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
+ if (const NonTypeTemplateParmDecl *NTTP =
+ dyn_cast<NonTypeTemplateParmDecl>(P)) {
// Handle the non-pack case first.
if (!NTTP->isExpandedParameterPack()) {
if (!NTTP->getType()->isDependentType()) {
@@ -263,7 +261,7 @@ getLVForTemplateParameterList(const TemplateParameterList *params,
// Template template parameters can be restricted by their
// template parameters, recursively.
- TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P);
+ const TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(P);
// Handle the non-pack case first.
if (!TTP->isExpandedParameterPack()) {
@@ -303,43 +301,41 @@ static const Decl *getOutermostFuncOrBlockContext(const Decl *D) {
///
/// Note that we don't take an LVComputationKind because we always
/// want to honor the visibility of template arguments in the same way.
-static LinkageInfo
-getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args,
- LVComputationKind computation) {
+static LinkageInfo getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args,
+ LVComputationKind computation) {
LinkageInfo LV;
- for (unsigned i = 0, e = args.size(); i != e; ++i) {
- const TemplateArgument &arg = args[i];
- switch (arg.getKind()) {
+ for (const TemplateArgument &Arg : Args) {
+ switch (Arg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Expression:
continue;
case TemplateArgument::Type:
- LV.merge(getLVForType(*arg.getAsType(), computation));
+ LV.merge(getLVForType(*Arg.getAsType(), computation));
continue;
case TemplateArgument::Declaration:
- if (NamedDecl *ND = dyn_cast<NamedDecl>(arg.getAsDecl())) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(Arg.getAsDecl())) {
assert(!usesTypeVisibility(ND));
LV.merge(getLVForDecl(ND, computation));
}
continue;
case TemplateArgument::NullPtr:
- LV.merge(arg.getNullPtrType()->getLinkageAndVisibility());
+ LV.merge(Arg.getNullPtrType()->getLinkageAndVisibility());
continue;
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
- if (TemplateDecl *Template
- = arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl())
+ if (TemplateDecl *Template =
+ Arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl())
LV.merge(getLVForDecl(Template, computation));
continue;
case TemplateArgument::Pack:
- LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray(), computation));
+ LV.merge(getLVForTemplateArgumentList(Arg.getPackAsArray(), computation));
continue;
}
llvm_unreachable("bad template argument kind");
@@ -3206,8 +3202,10 @@ TagDecl *TagDecl::getCanonicalDecl() { return getFirstDecl(); }
void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) {
NamedDeclOrQualifier = TDD;
- if (TypeForDecl)
- assert(TypeForDecl->isLinkageValid());
+ if (const Type *T = getTypeForDecl()) {
+ (void)T;
+ assert(T->isLinkageValid());
+ }
assert(isLinkageValid());
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 1de1fe21de..f15639130a 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -837,7 +837,7 @@ static bool isLinkageSpecContext(const DeclContext *DC,
while (DC->getDeclKind() != Decl::TranslationUnit) {
if (DC->getDeclKind() == Decl::LinkageSpec)
return cast<LinkageSpecDecl>(DC)->getLanguage() == ID;
- DC = DC->getParent();
+ DC = DC->getLexicalParent();
}
return false;
}
@@ -900,18 +900,17 @@ DeclContext *DeclContext::getPrimaryContext() {
// If this is a tag type that has a definition or is currently
// being defined, that definition is our primary context.
TagDecl *Tag = cast<TagDecl>(this);
- assert(isa<TagType>(Tag->TypeForDecl) ||
- isa<InjectedClassNameType>(Tag->TypeForDecl));
if (TagDecl *Def = Tag->getDefinition())
return Def;
- if (!isa<InjectedClassNameType>(Tag->TypeForDecl)) {
- const TagType *TagTy = cast<TagType>(Tag->TypeForDecl);
- if (TagTy->isBeingDefined())
- // FIXME: is it necessarily being defined in the decl
- // that owns the type?
- return TagTy->getDecl();
+ if (const TagType *TagTy = dyn_cast<TagType>(Tag->getTypeForDecl())) {
+ // Note, TagType::getDecl returns the (partial) definition one exists.
+ TagDecl *PossiblePartialDef = TagTy->getDecl();
+ if (PossiblePartialDef->isBeingDefined())
+ return PossiblePartialDef;
+ } else {
+ assert(isa<InjectedClassNameType>(Tag->getTypeForDecl()));
}
return Tag;
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index c53dba3bfd..aedb097bee 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -364,6 +364,12 @@ static bool isIntroducingInitializers(const ObjCInterfaceDecl *D) {
return true;
}
}
+ if (const auto *ImplD = D->getImplementation()) {
+ for (const auto *MD : ImplD->instance_methods()) {
+ if (MD->getMethodFamily() == OMF_init && !MD->isOverriding())
+ return true;
+ }
+ }
return false;
}
@@ -379,11 +385,21 @@ bool ObjCInterfaceDecl::inheritsDesignatedInitializers() const {
// misleading warnings.
if (isIntroducingInitializers(this)) {
data().InheritedDesignatedInitializers = DefinitionData::IDI_NotInherited;
- return false;
} else {
- data().InheritedDesignatedInitializers = DefinitionData::IDI_Inherited;
- return true;
+ if (auto SuperD = getSuperClass()) {
+ data().InheritedDesignatedInitializers =
+ SuperD->declaresOrInheritsDesignatedInitializers() ?
+ DefinitionData::IDI_Inherited :
+ DefinitionData::IDI_NotInherited;
+ } else {
+ data().InheritedDesignatedInitializers =
+ DefinitionData::IDI_NotInherited;
+ }
}
+ assert(data().InheritedDesignatedInitializers
+ != DefinitionData::IDI_Unknown);
+ return data().InheritedDesignatedInitializers ==
+ DefinitionData::IDI_Inherited;
}
}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index fc73e6f412..408e8548b1 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -472,7 +472,7 @@ TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC,
TemplateTypeParmDecl *TTPDecl =
new (C, DC) TemplateTypeParmDecl(DC, KeyLoc, NameLoc, Id, Typename);
QualType TTPType = C.getTemplateTypeParmType(D, P, ParameterPack, TTPDecl);
- TTPDecl->TypeForDecl = TTPType.getTypePtr();
+ TTPDecl->setTypeForDecl(TTPType.getTypePtr());
return TTPDecl;
}
@@ -497,15 +497,15 @@ SourceRange TemplateTypeParmDecl::getSourceRange() const {
}
unsigned TemplateTypeParmDecl::getDepth() const {
- return TypeForDecl->getAs<TemplateTypeParmType>()->getDepth();
+ return getTypeForDecl()->getAs<TemplateTypeParmType>()->getDepth();
}
unsigned TemplateTypeParmDecl::getIndex() const {
- return TypeForDecl->getAs<TemplateTypeParmType>()->getIndex();
+ return getTypeForDecl()->getAs<TemplateTypeParmType>()->getIndex();
}
bool TemplateTypeParmDecl::isParameterPack() const {
- return TypeForDecl->getAs<TemplateTypeParmType>()->isParameterPack();
+ return getTypeForDecl()->getAs<TemplateTypeParmType>()->isParameterPack();
}
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 2f5f14f38e..4ddd0a239a 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -121,6 +121,8 @@ bool Expr::isKnownToHaveBooleanValue() const {
switch (UO->getOpcode()) {
case UO_Plus:
return UO->getSubExpr()->isKnownToHaveBooleanValue();
+ case UO_LNot:
+ return true;
default:
return false;
}
@@ -476,7 +478,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
return "";
}
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
- if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual)
+ if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual && IT != FuncSig)
return FD->getNameAsString();
SmallString<256> Name;
@@ -492,7 +494,6 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
PrintingPolicy Policy(Context.getLangOpts());
std::string Proto;
llvm::raw_string_ostream POut(Proto);
- FD->printQualifiedName(POut, Policy);
const FunctionDecl *Decl = FD;
if (const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern())
@@ -502,6 +503,19 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
if (FD->hasWrittenPrototype())
FT = dyn_cast<FunctionProtoType>(AFT);
+ if (IT == FuncSig) {
+ switch (FT->getCallConv()) {
+ case CC_C: POut << "__cdecl "; break;
+ case CC_X86StdCall: POut << "__stdcall "; break;
+ case CC_X86FastCall: POut << "__fastcall "; break;
+ case CC_X86ThisCall: POut << "__thiscall "; break;
+ // Only bother printing the conventions that MSVC knows about.
+ default: break;
+ }
+ }
+
+ FD->printQualifiedName(POut, Policy);
+
POut << "(";
if (FT) {
for (unsigned i = 0, e = Decl->getNumParams(); i != e; ++i) {
@@ -2386,6 +2400,27 @@ Expr *Expr::IgnoreParenCasts() {
}
}
+Expr *Expr::IgnoreCasts() {
+ Expr *E = this;
+ while (true) {
+ if (CastExpr *P = dyn_cast<CastExpr>(E)) {
+ E = P->getSubExpr();
+ continue;
+ }
+ if (MaterializeTemporaryExpr *Materialize
+ = dyn_cast<MaterializeTemporaryExpr>(E)) {
+ E = Materialize->GetTemporaryExpr();
+ continue;
+ }
+ if (SubstNonTypeTemplateParmExpr *NTTP
+ = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
+ E = NTTP->getReplacement();
+ continue;
+ }
+ return E;
+ }
+}
+
/// IgnoreParenLValueCasts - Ignore parentheses and lvalue-to-rvalue
/// casts. This is intended purely as a temporary workaround for code
/// that hasn't yet been rewritten to do the right thing about those
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 9c69080652..16c5a5214d 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -968,7 +968,7 @@ namespace {
// any object: we won't use such a designator for anything.
if (!Info.getLangOpts().CPlusPlus11)
Designator.setInvalid();
- return checkNullPointer(Info, E, CSK) &&
+ return (CSK == CSK_ArrayToPointer || checkNullPointer(Info, E, CSK)) &&
Designator.checkSubobject(Info, E, CSK);
}
@@ -986,7 +986,7 @@ namespace {
Designator.addComplexUnchecked(EltTy, Imag);
}
void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) {
- if (checkNullPointer(Info, E, CSK_ArrayIndex))
+ if (N && checkNullPointer(Info, E, CSK_ArrayIndex))
Designator.adjustIndex(Info, E, N);
}
};
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 27ba2bef67..0e332a6f2d 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -456,6 +456,25 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
if (!Context.shouldMangleDeclName(FD))
return;
+ if (FD->hasAttr<EnableIfAttr>()) {
+ FunctionTypeDepthState Saved = FunctionTypeDepth.push();
+ Out << "Ua9enable_ifI";
+ // FIXME: specific_attr_iterator iterates in reverse order. Fix that and use
+ // it here.
+ for (AttrVec::const_reverse_iterator I = FD->getAttrs().rbegin(),
+ E = FD->getAttrs().rend();
+ I != E; ++I) {
+ EnableIfAttr *EIA = dyn_cast<EnableIfAttr>(*I);
+ if (!EIA)
+ continue;
+ Out << 'X';
+ mangleExpression(EIA->getCond());
+ Out << 'E';
+ }
+ Out << 'E';
+ FunctionTypeDepth.pop(Saved);
+ }
+
// Whether the mangling of a function type includes the return type depends on
// the context and the nature of the function. The rules for deciding whether
// the return type is included are:
@@ -2359,10 +2378,37 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
}
void CXXNameMangler::mangleType(const DependentNameType *T) {
+ // Proposal by cxx-abi-dev, 2014-03-26
+ // <class-enum-type> ::= <name> # non-dependent or dependent type name or
+ // # dependent elaborated type specifier using
+ // # 'typename'
+ // ::= Ts <name> # dependent elaborated type specifier using
+ // # 'struct' or 'class'
+ // ::= Tu <name> # dependent elaborated type specifier using
+ // # 'union'
+ // ::= Te <name> # dependent elaborated type specifier using
+ // # 'enum'
+ switch (T->getKeyword()) {
+ case ETK_Typename:
+ break;
+ case ETK_Struct:
+ case ETK_Class:
+ case ETK_Interface:
+ Out << "Ts";
+ break;
+ case ETK_Union:
+ Out << "Tu";
+ break;
+ case ETK_Enum:
+ Out << "Te";
+ break;
+ default:
+ llvm_unreachable("unexpected keyword for dependent type name");
+ }
// Typename types are always nested
Out << 'N';
manglePrefix(T->getQualifier());
- mangleSourceName(T->getIdentifier());
+ mangleSourceName(T->getIdentifier());
Out << 'E';
}
@@ -3428,7 +3474,7 @@ bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
// <seq-id> is encoded in base-36, using digits and upper case letters.
char Buffer[10];
- char *BufferPtr = llvm::array_endof(Buffer);
+ char *BufferPtr = std::end(Buffer);
if (SeqID == 0) *--BufferPtr = '0';
@@ -3441,9 +3487,7 @@ bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
SeqID /= 36;
}
- Out << 'S'
- << StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr)
- << '_';
+ Out << 'S' << StringRef(BufferPtr, std::end(Buffer) - BufferPtr) << '_';
}
return true;
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 061fc13c08..edea497d99 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -88,7 +88,7 @@ static bool isLambda(const NamedDecl *ND) {
class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
typedef std::pair<const DeclContext *, IdentifierInfo *> DiscriminatorKeyTy;
llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
- llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
+ llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier;
llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds;
public:
@@ -97,7 +97,8 @@ public:
bool shouldMangleCXXName(const NamedDecl *D) override;
bool shouldMangleStringLiteral(const StringLiteral *SL) override;
void mangleCXXName(const NamedDecl *D, raw_ostream &Out) override;
- void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD, raw_ostream &) override;
+ void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
+ raw_ostream &) override;
void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk,
raw_ostream &) override;
void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
@@ -181,7 +182,7 @@ class MicrosoftCXXNameMangler {
BackRefMap NameBackReferences;
bool UseNameBackReferences;
- typedef llvm::DenseMap<void*, unsigned> ArgBackRefMap;
+ typedef llvm::DenseMap<void *, unsigned> ArgBackRefMap;
ArgBackRefMap TypeBackReferences;
ASTContext &getASTContext() const { return Context.getASTContext(); }
@@ -194,19 +195,17 @@ public:
enum QualifierMangleMode { QMM_Drop, QMM_Mangle, QMM_Escape, QMM_Result };
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_)
- : Context(C), Out(Out_),
- Structor(0), StructorType(-1),
- UseNameBackReferences(true),
- PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
- 64) { }
+ : Context(C), Out(Out_), Structor(0), StructorType(-1),
+ UseNameBackReferences(true),
+ PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
+ 64) {}
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
const CXXDestructorDecl *D, CXXDtorType Type)
- : Context(C), Out(Out_),
- Structor(getStructor(D)), StructorType(Type),
- UseNameBackReferences(true),
- PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
- 64) { }
+ : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
+ UseNameBackReferences(true),
+ PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
+ 64) {}
raw_ostream &getStream() const { return Out; }
@@ -237,12 +236,14 @@ private:
void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
void mangleCXXDtorType(CXXDtorType T);
void mangleQualifiers(Qualifiers Quals, bool IsMember);
+ void mangleRefQualifier(RefQualifierKind RefQualifier);
void manglePointerCVQualifiers(Qualifiers Quals);
void manglePointerExtQualifiers(Qualifiers Quals, const Type *PointeeType);
void mangleUnscopedTemplateName(const TemplateDecl *ND);
- void mangleTemplateInstantiationName(const TemplateDecl *TD,
- const TemplateArgumentList &TemplateArgs);
+ void
+ mangleTemplateInstantiationName(const TemplateDecl *TD,
+ const TemplateArgumentList &TemplateArgs);
void mangleObjCMethodName(const ObjCMethodDecl *MD);
void mangleArgumentType(QualType T, SourceRange Range);
@@ -332,8 +333,7 @@ MicrosoftMangleContextImpl::shouldMangleStringLiteral(const StringLiteral *SL) {
// literals.
}
-void MicrosoftCXXNameMangler::mangle(const NamedDecl *D,
- StringRef Prefix) {
+void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) {
// MSVC doesn't mangle C++ names the same way it mangles extern "C" names.
// Therefore it's really important that we don't decorate the
// name with leading underscores or leading/trailing at signs. So, by
@@ -351,10 +351,9 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D,
// TODO: Fields? Can MSVC even mangle them?
// Issue a diagnostic for now.
DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this declaration yet");
- Diags.Report(D->getLocation(), DiagID)
- << D->getSourceRange();
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error, "cannot mangle this declaration yet");
+ Diags.Report(D->getLocation(), DiagID) << D->getSourceRange();
}
}
@@ -470,6 +469,9 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD,
mangleNumber(FieldOffset);
+ // The C++ standard doesn't allow base-to-derived member pointer conversions
+ // in template parameter contexts, so the vbptr offset of data member pointers
+ // is always zero.
if (MSInheritanceAttr::hasVBPtrOffsetField(IM))
mangleNumber(0);
if (MSInheritanceAttr::hasVBTableOffsetField(IM))
@@ -509,6 +511,7 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
// thunk.
uint64_t NVOffset = 0;
uint64_t VBTableOffset = 0;
+ uint64_t VBPtrOffset = 0;
if (MD->isVirtual()) {
MicrosoftVTableContext *VTContext =
cast<MicrosoftVTableContext>(getASTContext().getVTableContext());
@@ -518,11 +521,8 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
NVOffset = ML.VFPtrOffset.getQuantity();
VBTableOffset = ML.VBTableIndex * 4;
if (ML.VBase) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(
- DiagnosticsEngine::Error,
- "cannot mangle pointers to member functions from virtual bases");
- Diags.Report(MD->getLocation(), DiagID);
+ const ASTRecordLayout &Layout = getASTContext().getASTRecordLayout(RD);
+ VBPtrOffset = Layout.getVBPtrOffset().getQuantity();
}
} else {
mangleName(MD);
@@ -532,7 +532,7 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD,
if (MSInheritanceAttr::hasNVOffsetField(/*IsMemberFunction=*/true, IM))
mangleNumber(NVOffset);
if (MSInheritanceAttr::hasVBPtrOffsetField(IM))
- mangleNumber(0);
+ mangleNumber(VBPtrOffset);
if (MSInheritanceAttr::hasVBTableOffsetField(IM))
mangleNumber(VBTableOffset);
}
@@ -599,7 +599,7 @@ void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) {
static const TemplateDecl *
isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
// Check if we have a function template.
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
if (const TemplateDecl *TD = FD->getPrimaryTemplate()) {
TemplateArgs = FD->getTemplateSpecializationArgs();
return TD;
@@ -608,7 +608,7 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
// Check if we have a class template.
if (const ClassTemplateSpecializationDecl *Spec =
- dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+ dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
TemplateArgs = &Spec->getTemplateArgs();
return Spec->getSpecializedTemplate();
}
@@ -623,9 +623,8 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
return 0;
}
-void
-MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
- DeclarationName Name) {
+void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
+ DeclarationName Name) {
// <unqualified-name> ::= <operator-name>
// ::= <ctor-dtor-name>
// ::= <source-name>
@@ -1018,8 +1017,7 @@ void MicrosoftCXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
}
void MicrosoftCXXNameMangler::mangleTemplateInstantiationName(
- const TemplateDecl *TD,
- const TemplateArgumentList &TemplateArgs) {
+ const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs) {
// <template-name> ::= <unscoped-template-name> <template-args>
// ::= <substitution>
// Always start with the unqualified name.
@@ -1045,9 +1043,8 @@ MicrosoftCXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *TD) {
mangleUnqualifiedName(TD);
}
-void
-MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value,
- bool IsBoolean) {
+void MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value,
+ bool IsBoolean) {
// <integer-literal> ::= $0 <number>
Out << "$0";
// Make sure booleans are encoded as 0/1.
@@ -1057,8 +1054,7 @@ MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value,
mangleNumber(Value.getSExtValue());
}
-void
-MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
+void MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
// See if this is a constant expression.
llvm::APSInt Value;
if (E->isIntegerConstantExpr(Value, Context.getASTContext())) {
@@ -1095,10 +1091,10 @@ MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
// As bad as this diagnostic is, it's better than crashing.
DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot yet mangle expression type %0");
- Diags.Report(E->getExprLoc(), DiagID)
- << E->getStmtClassName() << E->getSourceRange();
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error, "cannot yet mangle expression type %0");
+ Diags.Report(E->getExprLoc(), DiagID) << E->getStmtClassName()
+ << E->getSourceRange();
}
void MicrosoftCXXNameMangler::mangleTemplateArgs(
@@ -1169,9 +1165,8 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
break;
case TemplateArgument::Pack:
// Unlike Itanium, there is no character code to indicate an argument pack.
- for (TemplateArgument::pack_iterator I = TA.pack_begin(), E = TA.pack_end();
- I != E; ++I)
- mangleTemplateArg(TD, *I);
+ for (const TemplateArgument &PA : TA.getPackAsArray())
+ mangleTemplateArg(TD, PA);
break;
case TemplateArgument::Template:
mangleType(cast<TagDecl>(
@@ -1263,6 +1258,24 @@ void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals,
}
void
+MicrosoftCXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) {
+ // <ref-qualifier> ::= G # lvalue reference
+ // ::= H # rvalue-reference
+ switch (RefQualifier) {
+ case RQ_None:
+ break;
+
+ case RQ_LValue:
+ Out << 'G';
+ break;
+
+ case RQ_RValue:
+ Out << 'H';
+ break;
+ }
+}
+
+void
MicrosoftCXXNameMangler::manglePointerExtQualifiers(Qualifiers Quals,
const Type *PointeeType) {
bool HasRestrict = Quals.hasRestrict();
@@ -1525,6 +1538,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
if (IsInstMethod) {
Qualifiers Quals = Qualifiers::fromCVRMask(Proto->getTypeQuals());
manglePointerExtQualifiers(Quals, 0);
+ mangleRefQualifier(Proto->getRefQualifier());
mangleQualifiers(Quals, false);
}
@@ -1566,7 +1580,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
Out << 'X';
} else {
// Happens for function pointer type arguments for example.
- for (const auto &Arg : Proto->param_types())
+ for (const QualType Arg : Proto->param_types())
mangleArgumentType(Arg, Range);
// <builtin-type> ::= Z # ellipsis
if (Proto->isVariadic())
@@ -1749,7 +1763,7 @@ void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) {
SmallVector<llvm::APInt, 3> Dimensions;
for (;;) {
if (const ConstantArrayType *CAT =
- getASTContext().getAsConstantArrayType(ElementTy)) {
+ getASTContext().getAsConstantArrayType(ElementTy)) {
Dimensions.push_back(CAT->getSize());
ElementTy = CAT->getElementType();
} else if (ElementTy->isVariableArrayType()) {
@@ -1772,7 +1786,7 @@ void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) {
<< DSAT->getBracketsRange();
return;
} else if (const IncompleteArrayType *IAT =
- getASTContext().getAsIncompleteArrayType(ElementTy)) {
+ getASTContext().getAsIncompleteArrayType(ElementTy)) {
Dimensions.push_back(llvm::APInt(32, 0));
ElementTy = IAT->getElementType();
}
@@ -1781,8 +1795,8 @@ void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) {
Out << 'Y';
// <dimension-count> ::= <number> # number of extra dimensions
mangleNumber(Dimensions.size());
- for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim)
- mangleNumber(Dimensions[Dim].getLimitedValue());
+ for (const llvm::APInt &Dimension : Dimensions)
+ mangleNumber(Dimension.getLimitedValue());
mangleType(ElementTy, SourceRange(), QMM_Escape);
}
@@ -2193,11 +2207,8 @@ void MicrosoftMangleContextImpl::mangleCXXVFTable(
Mangler.getStream() << "\01??_7";
Mangler.mangleName(Derived);
Mangler.getStream() << "6B"; // '6' for vftable, 'B' for const.
- for (ArrayRef<const CXXRecordDecl *>::iterator I = BasePath.begin(),
- E = BasePath.end();
- I != E; ++I) {
- Mangler.mangleName(*I);
- }
+ for (const CXXRecordDecl *RD : BasePath)
+ Mangler.mangleName(RD);
Mangler.getStream() << '@';
}
@@ -2212,11 +2223,8 @@ void MicrosoftMangleContextImpl::mangleCXXVBTable(
Mangler.getStream() << "\01??_8";
Mangler.mangleName(Derived);
Mangler.getStream() << "7B"; // '7' for vbtable, 'B' for const.
- for (ArrayRef<const CXXRecordDecl *>::iterator I = BasePath.begin(),
- E = BasePath.end();
- I != E; ++I) {
- Mangler.mangleName(*I);
- }
+ for (const CXXRecordDecl *RD : BasePath)
+ Mangler.mangleName(RD);
Mangler.getStream() << '@';
}
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index ce55d2e49a..5eb87e7fc7 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -141,8 +141,7 @@ public:
void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
// Check the bases.
for (const auto &I : Class->bases()) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
CharUnits EmptySize;
const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
@@ -168,7 +167,7 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
continue;
CharUnits EmptySize;
- const CXXRecordDecl *MemberDecl = cast<CXXRecordDecl>(RT->getDecl());
+ const CXXRecordDecl *MemberDecl = RT->getAsCXXRecordDecl();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl);
if (MemberDecl->isEmpty()) {
// If the class decl is empty, get its size.
@@ -349,8 +348,7 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
if (I.isVirtual())
continue;
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
if (!CanPlaceFieldSubobjectAtOffset(BaseDecl, Class, BaseOffset))
@@ -360,9 +358,8 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
if (RD == Class) {
// This is the most derived class, traverse virtual bases as well.
for (const auto &I : RD->vbases()) {
- const CXXRecordDecl *VBaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
-
+ const CXXRecordDecl *VBaseDecl = I.getType()->getAsCXXRecordDecl();
+
CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
if (!CanPlaceFieldSubobjectAtOffset(VBaseDecl, Class, VBaseOffset))
return false;
@@ -394,10 +391,8 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
return true;
QualType T = FD->getType();
- if (const RecordType *RT = T->getAs<RecordType>()) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
return CanPlaceFieldSubobjectAtOffset(RD, RD, Offset);
- }
// If we have an array type we need to look at every element.
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
@@ -405,8 +400,8 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
const RecordType *RT = ElemTy->getAs<RecordType>();
if (!RT)
return true;
-
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ const CXXRecordDecl *RD = RT->getAsCXXRecordDecl();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
uint64_t NumElements = Context.getConstantArrayElementCount(AT);
@@ -459,8 +454,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
if (I.isVirtual())
continue;
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset);
@@ -469,9 +463,8 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
if (RD == Class) {
// This is the most derived class, traverse virtual bases as well.
for (const auto &I : RD->vbases()) {
- const CXXRecordDecl *VBaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
-
+ const CXXRecordDecl *VBaseDecl = I.getType()->getAsCXXRecordDecl();
+
CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
UpdateEmptyFieldSubobjects(VBaseDecl, Class, VBaseOffset);
}
@@ -493,8 +486,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD,
CharUnits Offset) {
QualType T = FD->getType();
- if (const RecordType *RT = T->getAs<RecordType>()) {
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
UpdateEmptyFieldSubobjects(RD, RD, Offset);
return;
}
@@ -505,8 +497,8 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD,
const RecordType *RT = ElemTy->getAs<RecordType>();
if (!RT)
return;
-
- const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ const CXXRecordDecl *RD = RT->getAsCXXRecordDecl();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
uint64_t NumElements = Context.getConstantArrayElementCount(AT);
@@ -780,8 +772,7 @@ RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
assert(!I.getType()->isDependentType() &&
"Cannot layout class with dependent bases.");
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *Base = I.getType()->getAsCXXRecordDecl();
// Check if this is a nearly empty virtual base.
if (I.isVirtual() && Context.isNearlyEmpty(Base)) {
@@ -822,8 +813,7 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
if (I.isVirtual())
continue;
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *Base = I.getType()->getAsCXXRecordDecl();
if (Base->isDynamicClass()) {
// We found it.
@@ -911,10 +901,9 @@ RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD,
// Now go through all direct bases.
for (const auto &I : RD->bases()) {
bool IsVirtual = I.isVirtual();
-
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
-
+
+ const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
+
Info->Bases.push_back(ComputeBaseSubobjectInfo(BaseDecl, IsVirtual, Info));
}
@@ -937,9 +926,8 @@ void RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD) {
for (const auto &I : RD->bases()) {
bool IsVirtual = I.isVirtual();
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
-
+ const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
+
// Compute the base subobject info for this base.
BaseSubobjectInfo *Info = ComputeBaseSubobjectInfo(BaseDecl, IsVirtual, 0);
@@ -1315,16 +1303,14 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
if (I.isVirtual())
continue;
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
assert(Bases.count(BaseDecl) && "Did not find base offset!");
}
// And all virtual bases.
for (const auto &I : RD->vbases()) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
assert(VBases.count(BaseDecl) && "Did not find base offset!");
}
@@ -2056,7 +2042,7 @@ static bool isMsLayout(const RecordDecl* D) {
}
// This section contains an implementation of struct layout that is, up to the
-// included tests, compatible with cl.exe (2012). The layout produced is
+// included tests, compatible with cl.exe (2013). The layout produced is
// significantly different than those produced by the Itanium ABI. Here we note
// the most important differences.
//
@@ -2064,52 +2050,86 @@ static bool isMsLayout(const RecordDecl* D) {
// alignment of the union.
// * The existence of zero-width bitfield that occurs after anything other than
// a non-zero length bitfield is ignored.
+// * There is no explicit primary base for the purposes of layout. All bases
+// with vfptrs are laid out first, followed by all bases without vfptrs.
// * The Itanium equivalent vtable pointers are split into a vfptr (virtual
// function pointer) and a vbptr (virtual base pointer). They can each be
// shared with a, non-virtual bases. These bases need not be the same. vfptrs
-// always occur at offset 0. vbptrs can occur at an
-// arbitrary offset and are placed after non-virtual bases but before fields.
+// always occur at offset 0. vbptrs can occur at an arbitrary offset and are
+// placed after the lexiographically last non-virtual base. This placement
+// is always before fields but can be in the middle of the non-virtual bases
+// due to the two-pass layout scheme for non-virtual-bases.
// * Virtual bases sometimes require a 'vtordisp' field that is laid out before
// the virtual base and is used in conjunction with virtual overrides during
-// construction and destruction.
-// * vfptrs are allocated in a block of memory equal to the alignment of the
-// fields and non-virtual bases at offset 0 in 32 bit mode and in a pointer
-// sized block of memory in 64 bit mode.
-// * vbptrs are allocated in a block of memory equal to the alignment of the
-// fields and non-virtual bases. This block is at a potentially unaligned
-// offset. If the allocation slot is unaligned and the alignment is less than
-// or equal to the pointer size, additional space is allocated so that the
-// pointer can be aligned properly. This causes very strange effects on the
-// placement of objects after the allocated block. (see the code).
+// construction and destruction. This is always a 4 byte value and is used as
+// an alternative to constructor vtables.
// * vtordisps are allocated in a block of memory with size and alignment equal
// to the alignment of the completed structure (before applying __declspec(
// align())). The vtordisp always occur at the end of the allocation block,
// immediately prior to the virtual base.
-// * The last zero sized non-virtual base is allocated after the placement of
-// vbptr if one exists and can be placed at the end of the struct, potentially
-// aliasing either the first member or another struct allocated after this
-// one.
-// * The last zero size virtual base may be placed at the end of the struct.
-// and can potentially alias a zero sized type in the next struct.
-// * If the last field is a non-zero length bitfield, all virtual bases will
-// have extra padding added before them for no obvious reason. The padding
-// has the same number of bits as the type of the bitfield.
-// * When laying out empty non-virtual bases, an extra byte of padding is added
-// if the non-virtual base before the empty non-virtual base has a vbptr.
+// * vfptrs are injected after all bases and fields have been laid out. In
+// order to guarantee proper alignment of all fields, the vfptr injection
+// pushes all bases and fields back by the alignment imposed by those bases
+// and fields. This can potentially add a significant amount of padding.
+// vfptrs are always injected at offset 0.
+// * vbptrs are injected after all bases and fields have been laid out. In
+// order to guarantee proper alignment of all fields, the vfptr injection
+// pushes all bases and fields back by the alignment imposed by those bases
+// and fields. This can potentially add a significant amount of padding.
+// vbptrs are injected immediately after the last non-virtual base as
+// lexiographically ordered in the code. If this site isn't pointer aligned
+// the vbptr is placed at the next properly aligned location. Enough padding
+// is added to guarantee a fit.
+// * The last zero sized non-virtual base can be placed at the end of the
+// struct (potentially aliasing another object), or may alias with the first
+// field, even if they are of the same type.
+// * The last zero size virtual base may be placed at the end of the struct
+// potentially aliasing another object.
// * The ABI attempts to avoid aliasing of zero sized bases by adding padding
// between bases or vbases with specific properties. The criteria for
// additional padding between two bases is that the first base is zero sized
-// or has a zero sized subobject and the second base is zero sized or leads
-// with a zero sized base (sharing of vfptrs can reorder the layout of the
-// so the leading base is not always the first one declared). The padding
-// added for bases is 1 byte. The padding added for vbases depends on the
-// alignment of the object but is at least 4 bytes (in both 32 and 64 bit
-// modes).
-// * There is no concept of non-virtual alignment or any distinction between
-// data size and non-virtual size.
+// or ends with a zero sized subobject and the second base is zero sized or
+// trails with a zero sized base or field (sharing of vfptrs can reorder the
+// layout of the so the leading base is not always the first one declared).
+// This rule does take into account fields that are not records, so padding
+// will occur even if the last field is, e.g. an int. The padding added for
+// bases is 1 byte. The padding added between vbases depends on the alignment
+// of the object but is at least 4 bytes (in both 32 and 64 bit modes).
+// * There is no concept of non-virtual alignment, non-virtual alignment and
+// alignment are always identical.
+// * There is a distinction between alignment and required alignment.
+// __declspec(align) changes the required alignment of a struct. This
+// alignment is _always_ obeyed, even in the presence of #pragma pack. A
+// record inherites required alignment from all of its fields an bases.
// * __declspec(align) on bitfields has the effect of changing the bitfield's
-// alignment instead of its required alignment. This has implications on how
-// it interacts with pragam pack.
+// alignment instead of its required alignment. This is the only known way
+// to make the alignment of a struct bigger than 8. Interestingly enough
+// this alignment is also immune to the effects of #pragma pack and can be
+// used to create structures with large alignment under #pragma pack.
+// However, because it does not impact required alignment, such a structure,
+// when used as a field or base, will not be aligned if #pragma pack is
+// still active at the time of use.
+//
+// Known incompatiblities:
+// * all: #pragma pack between fields in a record
+// * 2010 and back: If the last field in a record is a bitfield, every object
+// laid out after the record will have extra padding inserted before it. The
+// extra padding will have size equal to the size of the storage class of the
+// bitfield. 0 sized bitfields don't exhibit this behavior and the extra
+// padding can be avoided by adding a 0 sized bitfield after the non-zero-
+// sized bitfield.
+// * 2012 and back: In 64-bit mode, if the alignment of a record is 16 or
+// greater due to __declspec(align()) then a second layout phase occurs after
+// The locations of the vf and vb pointers are known. This layout phase
+// suffers from the "last field is a bitfield" bug in 2010 and results in
+// _every_ field getting padding put in front of it, potentially including the
+// vfptr, leaving the vfprt at a non-zero location which results in a fault if
+// anything tries to read the vftbl. The second layout phase also treats
+// bitfields as seperate entities and gives them each storage rather than
+// packing them. Additionally, because this phase appears to perform a
+// (an unstable) sort on the members before laying them out and because merged
+// bitfields have the same address, the bitfields end up in whatever order
+// the sort left them in, a behavior we could never hope to replicate.
namespace {
struct MicrosoftRecordLayoutBuilder {
@@ -2150,8 +2170,7 @@ public:
void finalizeLayout(const RecordDecl *RD);
/// \brief Gets the size and alignment of a base taking pragma pack and
/// __declspec(align) into account.
- ElementInfo getAdjustedElementInfo(const ASTRecordLayout &Layout,
- bool AsBase = true);
+ ElementInfo getAdjustedElementInfo(const ASTRecordLayout &Layout);
/// \brief Gets the size and alignment of a field taking pragma pack and
/// __declspec(align) into account. It also updates RequiredAlignment as a
/// side effect because it is most convenient to do so here.
@@ -2211,11 +2230,10 @@ public:
bool HasOwnVFPtr : 1;
/// \brief True if the class has a vbtable pointer.
bool HasVBPtr : 1;
- /// \brief Lets us know if we're in 64-bit mode
- bool Is64BitMode : 1;
- /// \brief True if this class contains a zero sized member or base or a base
- /// with a zero sized member or base. Only used for MS-ABI.
- bool HasZeroSizedSubObject : 1;
+ /// \brief True if the last sub-object within the type is zero sized or the
+ /// object itself is zero sized. This *does not* count members that are not
+ /// records. Only used for MS-ABI.
+ bool EndsWithZeroSizedObject : 1;
/// \brief True if this class is zero sized or first base is zero sized or
/// has this property. Only used for MS-ABI.
bool LeadsWithZeroSizedBase : 1;
@@ -2224,21 +2242,21 @@ public:
MicrosoftRecordLayoutBuilder::ElementInfo
MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
- const ASTRecordLayout &Layout, bool AsBase) {
+ const ASTRecordLayout &Layout) {
ElementInfo Info;
Info.Alignment = Layout.getAlignment();
// Respect pragma pack.
if (!MaxFieldAlignment.isZero())
Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment);
// Track zero-sized subobjects here where it's already available.
- if (Layout.hasZeroSizedSubObject())
- HasZeroSizedSubObject = true;
+ EndsWithZeroSizedObject = Layout.hasZeroSizedSubObject();
// Respect required alignment, this is necessary because we may have adjusted
// the alignment in the case of pragam pack. Note that the required alignment
// doesn't actually apply to the struct alignment at this point.
Alignment = std::max(Alignment, Info.Alignment);
+ RequiredAlignment = std::max(RequiredAlignment, Layout.getRequiredAlignment());
Info.Alignment = std::max(Info.Alignment, Layout.getRequiredAlignment());
- Info.Size = AsBase ? Layout.getNonVirtualSize() : Layout.getSize();
+ Info.Size = Layout.getNonVirtualSize();
return Info;
}
@@ -2252,37 +2270,27 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
CharUnits FieldRequiredAlignment =
Context.toCharUnitsFromBits(FD->getMaxAlignment());
// Respect attributes applied to subobjects of the field.
- if (const RecordType *RT =
- FD->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RT->getDecl());
- // Get the element info for a layout, respecting pack.
- Info.Alignment = getAdjustedElementInfo(Layout, false).Alignment;
- // Capture required alignment as a side-effect.
- RequiredAlignment = std::max(RequiredAlignment,
- Layout.getRequiredAlignment());
- } else {
- if (FD->isBitField() && FD->getMaxAlignment() != 0)
- Info.Alignment = std::max(Info.Alignment, FieldRequiredAlignment);
- // Respect pragma pack.
- if (!MaxFieldAlignment.isZero())
- Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment);
- }
- // Respect packed field attribute.
- if (FD->hasAttr<PackedAttr>())
- Info.Alignment = CharUnits::One();
- // Take required alignment into account. __declspec(align) on bitfields
- // impacts the alignment rather than the required alignment.
- if (!FD->isBitField()) {
+ if (FD->isBitField())
+ // For some reason __declspec align impacts alignment rather than required
+ // alignment when it is applied to bitfields.
Info.Alignment = std::max(Info.Alignment, FieldRequiredAlignment);
+ else {
+ if (auto RT =
+ FD->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
+ auto const &Layout = Context.getASTRecordLayout(RT->getDecl());
+ EndsWithZeroSizedObject = Layout.hasZeroSizedSubObject();
+ FieldRequiredAlignment = std::max(FieldRequiredAlignment,
+ Layout.getRequiredAlignment());
+ }
// Capture required alignment as a side-effect.
RequiredAlignment = std::max(RequiredAlignment, FieldRequiredAlignment);
}
- // TODO: Add a Sema warning that MS ignores bitfield alignment in unions.
- if (!(FD->isBitField() && IsUnion)) {
- Alignment = std::max(Alignment, Info.Alignment);
- if (!MaxFieldAlignment.isZero())
- Alignment = std::min(Alignment, MaxFieldAlignment);
- }
+ // Respect pragma pack, attribute pack and declspec align
+ if (!MaxFieldAlignment.isZero())
+ Info.Alignment = std::min(Info.Alignment, MaxFieldAlignment);
+ if (FD->hasAttr<PackedAttr>())
+ Info.Alignment = CharUnits::One();
+ Info.Alignment = std::max(Info.Alignment, FieldRequiredAlignment);
return Info;
}
@@ -2304,7 +2312,10 @@ void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) {
injectVFPtr(RD);
if (HasOwnVFPtr || (HasVBPtr && !SharedVBPtrBase))
Alignment = std::max(Alignment, PointerInfo.Alignment);
- NonVirtualSize = Size = Size.RoundUpToAlignment(Alignment);
+ auto RoundingAlignment = Alignment;
+ if (!MaxFieldAlignment.isZero())
+ RoundingAlignment = std::min(RoundingAlignment, MaxFieldAlignment);
+ NonVirtualSize = Size = Size.RoundUpToAlignment(RoundingAlignment);
RequiredAlignment = std::max(
RequiredAlignment, Context.toCharUnitsFromBits(RD->getMaxAlignment()));
layoutVirtualBases(RD);
@@ -2313,13 +2324,13 @@ void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) {
void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
IsUnion = RD->isUnion();
- Is64BitMode = Context.getTargetInfo().getPointerWidth(0) == 64;
Size = CharUnits::Zero();
Alignment = CharUnits::One();
// In 64-bit mode we always perform an alignment step after laying out vbases.
// In 32-bit mode we do not. The check to see if we need to perform alignment
// checks the RequiredAlignment field and performs alignment if it isn't 0.
- RequiredAlignment = Is64BitMode ? CharUnits::One() : CharUnits::Zero();
+ RequiredAlignment = Context.getTargetInfo().getPointerWidth(0) == 64 ?
+ CharUnits::One() : CharUnits::Zero();
// Compute the maximum field alignment.
MaxFieldAlignment = CharUnits::Zero();
// Honor the default struct packing maximum alignment flag.
@@ -2339,7 +2350,7 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
void
MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) {
- HasZeroSizedSubObject = false;
+ EndsWithZeroSizedObject = false;
LeadsWithZeroSizedBase = false;
HasOwnVFPtr = false;
HasVBPtr = false;
@@ -2373,9 +2384,6 @@ MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
HasVBPtr = true;
continue;
}
- // Track RequiredAlignment for all bases in this pass.
- RequiredAlignment = std::max(RequiredAlignment,
- BaseLayout.getRequiredAlignment());
// Check fo a base to share a VBPtr with.
if (!SharedVBPtrBase && BaseLayout.hasVBPtr()) {
SharedVBPtrBase = BaseDecl;
@@ -2408,8 +2416,10 @@ MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl);
// Only lay out bases without extendable VFPtrs on the second pass.
- if (BaseLayout.hasExtendableVFPtr())
+ if (BaseLayout.hasExtendableVFPtr()) {
+ VBPtrOffset = Bases[BaseDecl] + BaseLayout.getNonVirtualSize();
continue;
+ }
// If this is the first layout, check to see if it leads with a zero sized
// object. If it does, so do we.
if (CheckLeadingLayout) {
@@ -2418,6 +2428,7 @@ MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
}
// Lay out the base.
layoutNonVirtualBase(BaseDecl, BaseLayout, PreviousBaseLayout);
+ VBPtrOffset = Bases[BaseDecl] + BaseLayout.getNonVirtualSize();
}
// Set our VBPtroffset if we know it at this point.
if (!HasVBPtr)
@@ -2443,7 +2454,6 @@ void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(
Bases.insert(std::make_pair(BaseDecl, BaseOffset));
Size = BaseOffset + BaseLayout.getNonVirtualSize();
PreviousBaseLayout = &BaseLayout;
- VBPtrOffset = Size;
}
void MicrosoftRecordLayoutBuilder::layoutFields(const RecordDecl *RD) {
@@ -2459,6 +2469,7 @@ void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {
}
LastFieldIsNonZeroWidthBitfield = false;
ElementInfo Info = getAdjustedElementInfo(FD);
+ Alignment = std::max(Alignment, Info.Alignment);
if (IsUnion) {
placeFieldAtOffset(CharUnits::Zero());
Size = std::max(Size, Info.Size);
@@ -2494,11 +2505,13 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
if (IsUnion) {
placeFieldAtOffset(CharUnits::Zero());
Size = std::max(Size, Info.Size);
+ // TODO: Add a Sema warning that MS ignores bitfield alignment in unions.
} else {
// Allocate a new block of memory and place the bitfield in it.
CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment);
placeFieldAtOffset(FieldOffset);
Size = FieldOffset + Info.Size;
+ Alignment = std::max(Alignment, Info.Alignment);
RemainingBitsInField = Context.toBits(Info.Size) - Width;
}
}
@@ -2518,11 +2531,13 @@ MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) {
if (IsUnion) {
placeFieldAtOffset(CharUnits::Zero());
Size = std::max(Size, Info.Size);
+ // TODO: Add a Sema warning that MS ignores bitfield alignment in unions.
} else {
// Round up the current record size to the field's alignment boundary.
CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment);
placeFieldAtOffset(FieldOffset);
Size = FieldOffset;
+ Alignment = std::max(Alignment, Info.Alignment);
}
}
@@ -2548,8 +2563,8 @@ void MicrosoftRecordLayoutBuilder::injectVBPtr(const CXXRecordDecl *RD) {
*i += Context.toBits(Offset);
for (BaseOffsetsMapTy::iterator i = Bases.begin(), e = Bases.end();
i != e; ++i)
- if (i->second >= InjectionSite)
- i->second += Offset;
+ if (i->second >= InjectionSite)
+ i->second += Offset;
}
void MicrosoftRecordLayoutBuilder::injectVFPtr(const CXXRecordDecl *RD) {
@@ -2601,23 +2616,15 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl);
bool HasVtordisp = HasVtordispSet.count(BaseDecl);
- // If the last field we laid out was a non-zero length bitfield then add
- // some extra padding for no obvious reason.
- if (LastFieldIsNonZeroWidthBitfield)
- Size += CurrentBitfieldSize;
// Insert padding between two bases if the left first one is zero sized or
// contains a zero sized subobject and the right is zero sized or one leads
// with a zero sized base. The padding between virtual bases is 4
// bytes (in both 32 and 64 bits modes) and always involves rounding up to
// the required alignment, we don't know why.
- if (PreviousBaseLayout && PreviousBaseLayout->hasZeroSizedSubObject() &&
- BaseLayout.leadsWithZeroSizedBase())
- Size = Size.RoundUpToAlignment(VtorDispAlignment) + VtorDispSize;
- // Insert the vtordisp.
- if (HasVtordisp)
+ if ((PreviousBaseLayout && PreviousBaseLayout->hasZeroSizedSubObject() &&
+ BaseLayout.leadsWithZeroSizedBase()) || HasVtordisp)
Size = Size.RoundUpToAlignment(VtorDispAlignment) + VtorDispSize;
// Insert the virtual base.
- HasZeroSizedSubObject = false;
ElementInfo Info = getAdjustedElementInfo(BaseLayout);
CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment);
VBases.insert(std::make_pair(BaseDecl,
@@ -2633,28 +2640,34 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
DataSize = Size;
if (!RequiredAlignment.isZero()) {
Alignment = std::max(Alignment, RequiredAlignment);
- Size = Size.RoundUpToAlignment(Alignment);
+ auto RoundingAlignment = Alignment;
+ if (!MaxFieldAlignment.isZero())
+ RoundingAlignment = std::min(RoundingAlignment, MaxFieldAlignment);
+ RoundingAlignment = std::max(RoundingAlignment, RequiredAlignment);
+ Size = Size.RoundUpToAlignment(RoundingAlignment);
}
// Zero-sized structures have size equal to their alignment.
if (Size.isZero()) {
- HasZeroSizedSubObject = true;
+ EndsWithZeroSizedObject = true;
LeadsWithZeroSizedBase = true;
Size = Alignment;
}
}
-static bool
-RequiresVtordisp(const llvm::SmallPtrSet<const CXXRecordDecl *, 2> &HasVtordisp,
- const CXXRecordDecl *RD) {
- if (HasVtordisp.count(RD))
+// Recursively walks the non-virtual bases of a class and determines if any of
+// them are in the bases with overridden methods set.
+static bool RequiresVtordisp(
+ const llvm::SmallPtrSet<const CXXRecordDecl *, 2> &
+ BasesWithOverriddenMethods,
+ const CXXRecordDecl *RD) {
+ if (BasesWithOverriddenMethods.count(RD))
return true;
// If any of a virtual bases non-virtual bases (recursively) requires a
// vtordisp than so does this virtual base.
for (const auto &I : RD->bases())
if (!I.isVirtual() &&
- RequiresVtordisp(
- HasVtordisp,
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl())))
+ RequiresVtordisp(BasesWithOverriddenMethods,
+ I.getType()->getAsCXXRecordDecl()))
return true;
return false;
}
@@ -2663,10 +2676,6 @@ llvm::SmallPtrSet<const CXXRecordDecl *, 2>
MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) {
llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordispSet;
- // /vd0 or #pragma vtordisp(0): Never use vtordisps when used as a vbase.
- if (RD->getMSVtorDispMode() == MSVtorDispAttr::Never)
- return HasVtordispSet;
-
// /vd2 or #pragma vtordisp(2): Always use vtordisps for virtual bases with
// vftables.
if (RD->getMSVtorDispMode() == MSVtorDispAttr::ForVFTable) {
@@ -2679,56 +2688,53 @@ MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) {
return HasVtordispSet;
}
- // /vd1 or #pragma vtordisp(1): Try to guess based on whether we think it's
- // possible for a partially constructed object with virtual base overrides to
- // escape a non-trivial constructor.
- assert(RD->getMSVtorDispMode() == MSVtorDispAttr::ForVBaseOverride);
-
// If any of our bases need a vtordisp for this type, so do we. Check our
// direct bases for vtordisp requirements.
for (const auto &I : RD->bases()) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
- for (ASTRecordLayout::VBaseOffsetsMapTy::const_iterator
- bi = Layout.getVBaseOffsetsMap().begin(),
- be = Layout.getVBaseOffsetsMap().end();
- bi != be; ++bi)
- if (bi->second.hasVtorDisp())
- HasVtordispSet.insert(bi->first);
- }
- // If we define a constructor or destructor and override a function that is
- // defined in a virtual base's vtable, that virtual bases need a vtordisp.
- // Here we collect a list of classes with vtables for which our virtual bases
- // actually live. The virtual bases with this property will require
- // vtordisps. In addition, virtual bases that contain non-virtual bases that
- // define functions we override also require vtordisps, this case is checked
- // explicitly below.
- if (RD->hasUserDeclaredConstructor() || RD->hasUserDeclaredDestructor()) {
- llvm::SmallPtrSet<const CXXMethodDecl *, 8> Work;
- // Seed the working set with our non-destructor virtual methods.
- for (const auto *I : RD->methods())
- if (I->isVirtual() && !isa<CXXDestructorDecl>(I))
- Work.insert(I);
- while (!Work.empty()) {
- const CXXMethodDecl *MD = *Work.begin();
- CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(),
- e = MD->end_overridden_methods();
- if (i == e)
- // If a virtual method has no-overrides it lives in its parent's vtable.
- HasVtordispSet.insert(MD->getParent());
- else
- Work.insert(i, e);
- // We've finished processing this element, remove it from the working set.
- Work.erase(MD);
- }
+ for (const auto &bi : Layout.getVBaseOffsetsMap())
+ if (bi.second.hasVtorDisp())
+ HasVtordispSet.insert(bi.first);
+ }
+ // We don't introduce any additional vtordisps if either:
+ // * A user declared constructor or destructor aren't declared.
+ // * #pragma vtordisp(0) or the /vd0 flag are in use.
+ if ((!RD->hasUserDeclaredConstructor() && !RD->hasUserDeclaredDestructor()) ||
+ RD->getMSVtorDispMode() == MSVtorDispAttr::Never)
+ return HasVtordispSet;
+ // /vd1 or #pragma vtordisp(1): Try to guess based on whether we think it's
+ // possible for a partially constructed object with virtual base overrides to
+ // escape a non-trivial constructor.
+ assert(RD->getMSVtorDispMode() == MSVtorDispAttr::ForVBaseOverride);
+ // Compute a set of base classes which define methods we override. A virtual
+ // base in this set will require a vtordisp. A virtual base that transitively
+ // contains one of these bases as a non-virtual base will also require a
+ // vtordisp.
+ llvm::SmallPtrSet<const CXXMethodDecl *, 8> Work;
+ llvm::SmallPtrSet<const CXXRecordDecl *, 2> BasesWithOverriddenMethods;
+ // Seed the working set with our non-destructor virtual methods.
+ for (const auto *I : RD->methods())
+ if (I->isVirtual() && !isa<CXXDestructorDecl>(I))
+ Work.insert(I);
+ while (!Work.empty()) {
+ const CXXMethodDecl *MD = *Work.begin();
+ CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(),
+ e = MD->end_overridden_methods();
+ // If a virtual method has no-overrides it lives in its parent's vtable.
+ if (i == e)
+ BasesWithOverriddenMethods.insert(MD->getParent());
+ else
+ Work.insert(i, e);
+ // We've finished processing this element, remove it from the working set.
+ Work.erase(MD);
}
- // Re-check all of our vbases for vtordisp requirements (in case their
- // non-virtual bases have vtordisp requirements).
+ // For each of our virtual bases, check if it is in the set of overridden
+ // bases or if it transitively contains a non-virtual base that is.
for (const auto &I : RD->vbases()) {
const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl();
if (!HasVtordispSet.count(BaseDecl) &&
- RequiresVtordisp(HasVtordispSet, BaseDecl))
+ RequiresVtordisp(BasesWithOverriddenMethods, BaseDecl))
HasVtordispSet.insert(BaseDecl);
}
return HasVtordispSet;
@@ -2750,7 +2756,7 @@ ASTContext::BuildMicrosoftASTRecordLayout(const RecordDecl *D) const {
Builder.FieldOffsets.size(), Builder.NonVirtualSize,
Builder.Alignment, CharUnits::Zero(), Builder.PrimaryBase,
false, Builder.SharedVBPtrBase,
- Builder.HasZeroSizedSubObject, Builder.LeadsWithZeroSizedBase,
+ Builder.EndsWithZeroSizedObject, Builder.LeadsWithZeroSizedBase,
Builder.Bases, Builder.VBases);
} else {
Builder.layout(D);
@@ -3032,13 +3038,11 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
CharUnits FieldOffset = Offset +
C.toCharUnitsFromBits(Layout.getFieldOffset(FieldNo));
- if (const RecordType *RT = Field.getType()->getAs<RecordType>()) {
- if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- DumpCXXRecordLayout(OS, D, C, FieldOffset, IndentLevel,
- Field.getName().data(),
- /*IncludeVirtualBases=*/true);
- continue;
- }
+ if (const CXXRecordDecl *D = Field.getType()->getAsCXXRecordDecl()) {
+ DumpCXXRecordLayout(OS, D, C, FieldOffset, IndentLevel,
+ Field.getName().data(),
+ /*IncludeVirtualBases=*/true);
+ continue;
}
PrintOffset(OS, FieldOffset, IndentLevel);
@@ -3053,8 +3057,7 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
Layout.getVBaseOffsetsMap();
for (const auto &I : RD->vbases()) {
assert(I.isVirtual() && "Found non-virtual class!");
- const CXXRecordDecl *VBase =
- cast<CXXRecordDecl>(I.getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *VBase = I.getType()->getAsCXXRecordDecl();
CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBase);
@@ -3078,7 +3081,6 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
PrintIndentNoOffset(OS, IndentLevel - 1);
OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity();
OS << ", nvalign=" << Layout.getNonVirtualAlignment().getQuantity() << "]\n";
- OS << '\n';
}
void ASTContext::DumpRecordLayout(const RecordDecl *RD,
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index a03ef00ce7..8e937fb08b 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -1192,6 +1192,30 @@ OMPSharedClause *OMPSharedClause::CreateEmpty(const ASTContext &C,
return new (Mem) OMPSharedClause(N);
}
+OMPLinearClause *OMPLinearClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL, Expr *Step) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * (VL.size() + 1));
+ OMPLinearClause *Clause = new (Mem)
+ OMPLinearClause(StartLoc, LParenLoc, ColonLoc, EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ Clause->setStep(Step);
+ return Clause;
+}
+
+OMPLinearClause *OMPLinearClause::CreateEmpty(const ASTContext &C,
+ unsigned NumVars) {
+ void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause),
+ llvm::alignOf<Expr *>()) +
+ sizeof(Expr *) * (NumVars + 1));
+ return new (Mem) OMPLinearClause(NumVars);
+}
+
OMPCopyinClause *OMPCopyinClause::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation LParenLoc,
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 7ad5491005..758db44828 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -664,6 +664,18 @@ void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) {
}
}
+void OMPClausePrinter::VisitOMPLinearClause(OMPLinearClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "linear";
+ VisitOMPClauseList(Node, '(');
+ if (Node->getStep() != 0) {
+ OS << ": ";
+ Node->getStep()->printPretty(OS, 0, Policy, 0);
+ }
+ OS << ")";
+ }
+}
+
void OMPClausePrinter::VisitOMPCopyinClause(OMPCopyinClause *Node) {
if (!Node->varlist_empty()) {
OS << "copyin";
@@ -789,6 +801,9 @@ void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
case PredefinedExpr::FuncDName:
OS << "__FUNCDNAME__";
break;
+ case PredefinedExpr::FuncSig:
+ OS << "__FUNCSIG__";
+ break;
case PredefinedExpr::LFunction:
OS << "L__FUNCTION__";
break;
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 07ed86a91c..1a6d1812dc 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -297,6 +297,10 @@ void OMPClauseProfiler::VisitOMPFirstprivateClause(
void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) {
VisitOMPClauseList(C);
}
+void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause *C) {
+ VisitOMPClauseList(C);
+ Profiler->VisitStmt(C->getStep());
+}
void OMPClauseProfiler::VisitOMPCopyinClause(const OMPCopyinClause *C) {
VisitOMPClauseList(C);
}
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index c6b38d31d4..b45f2aa252 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -64,10 +64,14 @@ public:
/// Method - The method decl of the overrider.
const CXXMethodDecl *Method;
+ /// VirtualBase - The virtual base class subobject of this overridder.
+ /// Note that this records the closest derived virtual base class subobject.
+ const CXXRecordDecl *VirtualBase;
+
/// Offset - the base offset of the overrider's parent in the layout class.
CharUnits Offset;
- OverriderInfo() : Method(0), Offset(CharUnits::Zero()) { }
+ OverriderInfo() : Method(0), VirtualBase(0), Offset(CharUnits::Zero()) { }
};
private:
@@ -201,6 +205,7 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass,
Overrider.Offset = OverriderOffset;
Overrider.Method = Method.Method;
+ Overrider.VirtualBase = Method.InVirtualSubobject;
}
}
@@ -2649,6 +2654,8 @@ VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) {
CharUnits Ret;
bool First = true;
+ const ASTRecordLayout &OverriderRDLayout =
+ Context.getASTRecordLayout(Overrider.Method->getParent());
for (CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end();
I != E; ++I) {
const CXXBasePath &Path = (*I);
@@ -2665,19 +2672,18 @@ VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(PrevRD);
if (Element.Base->isVirtual()) {
- LastVBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(CurRD);
- if (Overrider.Method->getParent() == PrevRD) {
- // This one's interesting. If the final overrider is in a vbase B of the
- // most derived class and it overrides a method of the B's own vbase A,
- // it uses A* as "this". In its prologue, it can cast A* to B* with
- // a static offset. This offset is used regardless of the actual
- // offset of A from B in the most derived class, requiring an
- // this-adjusting thunk in the vftable if A and B are laid out
- // differently in the most derived class.
- ThisOffset += Layout.getVBaseClassOffset(CurRD);
- } else {
- ThisOffset = LastVBaseOffset;
- }
+ // The interesting things begin when you have virtual inheritance.
+ // The final overrider will use a static adjustment equal to the offset
+ // of the vbase in the final overrider class.
+ // For example, if the final overrider is in a vbase B of the most
+ // derived class and it overrides a method of the B's own vbase A,
+ // it uses A* as "this". In its prologue, it can cast A* to B* with
+ // a static offset. This offset is used regardless of the actual
+ // offset of A from B in the most derived class, requiring an
+ // this-adjusting thunk in the vftable if A and B are laid out
+ // differently in the most derived class.
+ LastVBaseOffset = ThisOffset =
+ Overrider.Offset + OverriderRDLayout.getVBaseClassOffset(CurRD);
} else {
ThisOffset += Layout.getBaseClassOffset(CurRD);
}
@@ -2715,26 +2721,22 @@ void VFTableBuilder::CalculateVtordispAdjustment(
VBaseMap.find(WhichVFPtr.getVBaseWithVPtr());
assert(VBaseMapEntry != VBaseMap.end());
- // Check if we need a vtordisp adjustment at all.
- if (!VBaseMapEntry->second.hasVtorDisp())
+ // If there's no vtordisp or the final overrider is defined in the same vbase
+ // as the initial declaration, we don't need any vtordisp adjustment.
+ if (!VBaseMapEntry->second.hasVtorDisp() ||
+ Overrider.VirtualBase == WhichVFPtr.getVBaseWithVPtr())
return;
- CharUnits VFPtrVBaseOffset = VBaseMapEntry->second.VBaseOffset;
+ // OK, now we know we need to use a vtordisp thunk.
// The implicit vtordisp field is located right before the vbase.
+ CharUnits VFPtrVBaseOffset = VBaseMapEntry->second.VBaseOffset;
TA.Virtual.Microsoft.VtordispOffset =
(VFPtrVBaseOffset - WhichVFPtr.FullOffsetInMDC).getQuantity() - 4;
- // If the final overrider is defined in either:
- // - the most derived class or its non-virtual base or
- // - the same vbase as the initial declaration,
- // a simple vtordisp thunk will suffice.
- const CXXRecordDecl *OverriderRD = Overrider.Method->getParent();
- if (OverriderRD == MostDerivedClass)
- return;
-
- const CXXRecordDecl *OverriderVBase =
- ComputeBaseOffset(Context, OverriderRD, MostDerivedClass).VirtualBase;
- if (!OverriderVBase || OverriderVBase == WhichVFPtr.getVBaseWithVPtr())
+ // A simple vtordisp thunk will suffice if the final overrider is defined
+ // in either the most derived class or its non-virtual base.
+ if (Overrider.Method->getParent() == MostDerivedClass ||
+ !Overrider.VirtualBase)
return;
// Otherwise, we need to do use the dynamic offset of the final overrider
@@ -2744,7 +2746,7 @@ void VFTableBuilder::CalculateVtordispAdjustment(
MostDerivedClassLayout.getVBPtrOffset()).getQuantity();
TA.Virtual.Microsoft.VBOffsetOffset =
Context.getTypeSizeInChars(Context.IntTy).getQuantity() *
- VTables.getVBTableIndex(MostDerivedClass, OverriderVBase);
+ VTables.getVBTableIndex(MostDerivedClass, Overrider.VirtualBase);
TA.NonVirtual = (ThisOffset - Overrider.Offset).getQuantity();
}
@@ -3174,11 +3176,7 @@ void MicrosoftVTableContext::computeVTablePaths(bool ForVBTables,
const VPtrInfoVector &BasePaths =
ForVBTables ? enumerateVBTables(Base) : getVFPtrOffsets(Base);
- for (VPtrInfoVector::const_iterator II = BasePaths.begin(),
- EE = BasePaths.end();
- II != EE; ++II) {
- VPtrInfo *BaseInfo = *II;
-
+ for (VPtrInfo *BaseInfo : BasePaths) {
// Don't include the path if it goes through a virtual base that we've
// already included.
if (setsIntersect(VBasesSeen, BaseInfo->ContainingVBases))
@@ -3196,12 +3194,16 @@ void MicrosoftVTableContext::computeVTablePaths(bool ForVBTables,
// FIXME: Why do we need this?
P->PathToBaseWithVPtr.insert(P->PathToBaseWithVPtr.begin(), Base);
- // Keep track of which derived class ultimately uses the vtable, and what
- // the full adjustment is from the MDC to this vtable. The adjustment is
- // captured by an optional vbase and a non-virtual offset.
- if (Base == (ForVBTables ? Layout.getBaseSharingVBPtr()
+ // Keep track of which vtable the derived class is going to extend with
+ // new methods or bases. We append to either the vftable of our primary
+ // base, or the first non-virtual base that has a vbtable.
+ if (P->ReusingBase == Base &&
+ Base == (ForVBTables ? Layout.getBaseSharingVBPtr()
: Layout.getPrimaryBase()))
P->ReusingBase = RD;
+
+ // Keep track of the full adjustment from the MDC to this vtable. The
+ // adjustment is captured by an optional vbase and a non-virtual offset.
if (B.isVirtual())
P->ContainingVBases.push_back(Base);
else if (P->ContainingVBases.empty())
@@ -3272,6 +3274,8 @@ static bool rebucketPaths(VPtrInfoVector &Paths) {
}
MicrosoftVTableContext::~MicrosoftVTableContext() {
+ for (auto &P : VFPtrLocations)
+ llvm::DeleteContainerPointers(*P.second);
llvm::DeleteContainerSeconds(VFPtrLocations);
llvm::DeleteContainerSeconds(VFTableLayouts);
llvm::DeleteContainerSeconds(VBaseInfo);
diff --git a/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/lib/ASTMatchers/Dynamic/Diagnostics.cpp
index da2ed9a1d2..b0abdc7cf8 100644
--- a/lib/ASTMatchers/Dynamic/Diagnostics.cpp
+++ b/lib/ASTMatchers/Dynamic/Diagnostics.cpp
@@ -87,7 +87,7 @@ StringRef contextTypeToFormatString(Diagnostics::ContextType Type) {
StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
switch (Type) {
- case Diagnostics::ET_RegistryNotFound:
+ case Diagnostics::ET_RegistryMatcherNotFound:
return "Matcher not found: $0";
case Diagnostics::ET_RegistryWrongArgCount:
return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
@@ -98,6 +98,8 @@ StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) {
case Diagnostics::ET_RegistryAmbiguousOverload:
// TODO: Add type info about the overload error.
return "Ambiguous matcher overload.";
+ case Diagnostics::ET_RegistryValueNotFound:
+ return "Value not found: $0";
case Diagnostics::ET_ParserStringError:
return "Error parsing string token: <$0>";
diff --git a/lib/ASTMatchers/Dynamic/Parser.cpp b/lib/ASTMatchers/Dynamic/Parser.cpp
index 24ffdcda51..7034381189 100644
--- a/lib/ASTMatchers/Dynamic/Parser.cpp
+++ b/lib/ASTMatchers/Dynamic/Parser.cpp
@@ -258,6 +258,10 @@ private:
Parser::Sema::~Sema() {}
+VariantValue Parser::Sema::getNamedValue(StringRef Name) {
+ return VariantValue();
+}
+
struct Parser::ScopedContextEntry {
Parser *P;
@@ -274,12 +278,43 @@ struct Parser::ScopedContextEntry {
}
};
+/// \brief Parse expressions that start with an identifier.
+///
+/// This function can parse named values and matchers.
+/// In case of failure it will try to determine the user's intent to give
+/// an appropriate error message.
+bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) {
+ const TokenInfo NameToken = Tokenizer->consumeNextToken();
+
+ if (Tokenizer->nextTokenKind() != TokenInfo::TK_OpenParen) {
+ // Parse as a named value.
+ if (const VariantValue NamedValue = S->getNamedValue(NameToken.Text)) {
+ *Value = NamedValue;
+ return true;
+ }
+ // If the syntax is correct and the name is not a matcher either, report
+ // unknown named value.
+ if ((Tokenizer->nextTokenKind() == TokenInfo::TK_Comma ||
+ Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen ||
+ Tokenizer->nextTokenKind() == TokenInfo::TK_Eof) &&
+ !S->lookupMatcherCtor(NameToken.Text)) {
+ Error->addError(NameToken.Range, Error->ET_RegistryValueNotFound)
+ << NameToken.Text;
+ return false;
+ }
+ // Otherwise, fallback to the matcher parser.
+ }
+
+ // Parse as a matcher expression.
+ return parseMatcherExpressionImpl(NameToken, Value);
+}
+
/// \brief Parse and validate a matcher expression.
/// \return \c true on success, in which case \c Value has the matcher parsed.
/// If the input is malformed, or some argument has an error, it
/// returns \c false.
-bool Parser::parseMatcherExpressionImpl(VariantValue *Value) {
- const TokenInfo NameToken = Tokenizer->consumeNextToken();
+bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken,
+ VariantValue *Value) {
assert(NameToken.Kind == TokenInfo::TK_Ident);
const TokenInfo OpenToken = Tokenizer->consumeNextToken();
if (OpenToken.Kind != TokenInfo::TK_OpenParen) {
@@ -288,8 +323,14 @@ bool Parser::parseMatcherExpressionImpl(VariantValue *Value) {
return false;
}
- llvm::Optional<MatcherCtor> Ctor =
- S->lookupMatcherCtor(NameToken.Text, NameToken.Range, Error);
+ llvm::Optional<MatcherCtor> Ctor = S->lookupMatcherCtor(NameToken.Text);
+
+ if (!Ctor) {
+ Error->addError(NameToken.Range, Error->ET_RegistryMatcherNotFound)
+ << NameToken.Text;
+ // Do not return here. We need to continue to give completion suggestions.
+ }
+
std::vector<ParserValue> Args;
TokenInfo EndToken;
@@ -425,7 +466,7 @@ bool Parser::parseExpressionImpl(VariantValue *Value) {
return true;
case TokenInfo::TK_Ident:
- return parseMatcherExpressionImpl(Value);
+ return parseIdentifierPrefixImpl(Value);
case TokenInfo::TK_CodeCompletion:
addExpressionCompletions();
@@ -457,27 +498,23 @@ Parser::Parser(CodeTokenizer *Tokenizer, Sema *S,
Diagnostics *Error)
: Tokenizer(Tokenizer), S(S), Error(Error) {}
-class RegistrySema : public Parser::Sema {
-public:
- virtual ~RegistrySema() {}
- llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName,
- const SourceRange &NameRange,
- Diagnostics *Error) {
- return Registry::lookupMatcherCtor(MatcherName, NameRange, Error);
- }
- VariantMatcher actOnMatcherExpression(MatcherCtor Ctor,
- const SourceRange &NameRange,
- StringRef BindID,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) {
- if (BindID.empty()) {
- return Registry::constructMatcher(Ctor, NameRange, Args, Error);
- } else {
- return Registry::constructBoundMatcher(Ctor, NameRange, BindID, Args,
- Error);
- }
+Parser::RegistrySema::~RegistrySema() {}
+
+llvm::Optional<MatcherCtor>
+Parser::RegistrySema::lookupMatcherCtor(StringRef MatcherName) {
+ return Registry::lookupMatcherCtor(MatcherName);
+}
+
+VariantMatcher Parser::RegistrySema::actOnMatcherExpression(
+ MatcherCtor Ctor, const SourceRange &NameRange, StringRef BindID,
+ ArrayRef<ParserValue> Args, Diagnostics *Error) {
+ if (BindID.empty()) {
+ return Registry::constructMatcher(Ctor, NameRange, Args, Error);
+ } else {
+ return Registry::constructBoundMatcher(Ctor, NameRange, BindID, Args,
+ Error);
}
-};
+}
bool Parser::parseExpression(StringRef Code, VariantValue *Value,
Diagnostics *Error) {
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
index 6089b45e42..87fe043406 100644
--- a/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -325,17 +325,12 @@ static llvm::ManagedStatic<RegistryMaps> RegistryData;
} // anonymous namespace
// static
-llvm::Optional<MatcherCtor>
-Registry::lookupMatcherCtor(StringRef MatcherName, const SourceRange &NameRange,
- Diagnostics *Error) {
+llvm::Optional<MatcherCtor> Registry::lookupMatcherCtor(StringRef MatcherName) {
ConstructorMap::const_iterator it =
RegistryData->constructors().find(MatcherName);
- if (it == RegistryData->constructors().end()) {
- Error->addError(NameRange, Error->ET_RegistryNotFound) << MatcherName;
- return llvm::Optional<MatcherCtor>();
- }
-
- return it->second;
+ return it == RegistryData->constructors().end()
+ ? llvm::Optional<MatcherCtor>()
+ : it->second;
}
namespace {
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index c90d947951..fa4bd33fa1 100644
--- a/lib/Analysis/AnalysisDeclContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -189,6 +189,9 @@ CFG *AnalysisDeclContext::getCFG() {
if (PM)
addParentsForSyntheticStmts(cfg.get(), *PM);
+
+ // The Observer should only observe one build of the CFG.
+ getCFGBuildOptions().Observer = 0;
}
return cfg.get();
}
@@ -205,6 +208,9 @@ CFG *AnalysisDeclContext::getUnoptimizedCFG() {
if (PM)
addParentsForSyntheticStmts(completeCFG.get(), *PM);
+
+ // The Observer should only observe one build of the CFG.
+ getCFGBuildOptions().Observer = 0;
}
return completeCFG.get();
}
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 400c2025bc..7c716116eb 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -495,6 +495,215 @@ private:
cfg->getBumpVectorContext());
}
+ /// \brief Find a relational comparison with an expression evaluating to a
+ /// boolean and a constant other than 0 and 1.
+ /// e.g. if ((x < y) == 10)
+ TryResult checkIncorrectRelationalOperator(const BinaryOperator *B) {
+ const Expr *LHSExpr = B->getLHS()->IgnoreParens();
+ const Expr *RHSExpr = B->getRHS()->IgnoreParens();
+
+ const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
+ const Expr *BoolExpr = RHSExpr;
+ bool IntFirst = true;
+ if (!IntLiteral) {
+ IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
+ BoolExpr = LHSExpr;
+ IntFirst = false;
+ }
+
+ if (!IntLiteral || !BoolExpr->isKnownToHaveBooleanValue())
+ return TryResult();
+
+ llvm::APInt IntValue = IntLiteral->getValue();
+ if ((IntValue == 1) || (IntValue == 0))
+ return TryResult();
+
+ bool IntLarger = IntLiteral->getType()->isUnsignedIntegerType() ||
+ !IntValue.isNegative();
+
+ BinaryOperatorKind Bok = B->getOpcode();
+ if (Bok == BO_GT || Bok == BO_GE) {
+ // Always true for 10 > bool and bool > -1
+ // Always false for -1 > bool and bool > 10
+ return TryResult(IntFirst == IntLarger);
+ } else {
+ // Always true for -1 < bool and bool < 10
+ // Always false for 10 < bool and bool < -1
+ return TryResult(IntFirst != IntLarger);
+ }
+ }
+
+ /// Find a equality comparison with an expression evaluating to a boolean and
+ /// a constant other than 0 and 1.
+ /// e.g. if (!x == 10)
+ TryResult checkIncorrectEqualityOperator(const BinaryOperator *B) {
+ const Expr *LHSExpr = B->getLHS()->IgnoreParens();
+ const Expr *RHSExpr = B->getRHS()->IgnoreParens();
+
+ const IntegerLiteral *IntLiteral = dyn_cast<IntegerLiteral>(LHSExpr);
+ const Expr *BoolExpr = RHSExpr;
+
+ if (!IntLiteral) {
+ IntLiteral = dyn_cast<IntegerLiteral>(RHSExpr);
+ BoolExpr = LHSExpr;
+ }
+
+ if (!IntLiteral || !BoolExpr->isKnownToHaveBooleanValue())
+ return TryResult();
+
+ llvm::APInt IntValue = IntLiteral->getValue();
+ if ((IntValue == 1) || (IntValue == 0)) {
+ return TryResult();
+ }
+
+ return TryResult(B->getOpcode() != BO_EQ);
+ }
+
+ TryResult analyzeLogicOperatorCondition(BinaryOperatorKind Relation,
+ const llvm::APSInt &Value1,
+ const llvm::APSInt &Value2) {
+ assert(Value1.isSigned() == Value2.isSigned());
+ switch (Relation) {
+ default:
+ return TryResult();
+ case BO_EQ:
+ return TryResult(Value1 == Value2);
+ case BO_NE:
+ return TryResult(Value1 != Value2);
+ case BO_LT:
+ return TryResult(Value1 < Value2);
+ case BO_LE:
+ return TryResult(Value1 <= Value2);
+ case BO_GT:
+ return TryResult(Value1 > Value2);
+ case BO_GE:
+ return TryResult(Value1 >= Value2);
+ }
+ }
+
+ /// \brief Find a pair of comparison expressions with or without parentheses
+ /// with a shared variable and constants and a logical operator between them
+ /// that always evaluates to either true or false.
+ /// e.g. if (x != 3 || x != 4)
+ TryResult checkIncorrectLogicOperator(const BinaryOperator *B) {
+ assert(B->isLogicalOp());
+ const BinaryOperator *LHS =
+ dyn_cast<BinaryOperator>(B->getLHS()->IgnoreParens());
+ const BinaryOperator *RHS =
+ dyn_cast<BinaryOperator>(B->getRHS()->IgnoreParens());
+ if (!LHS || !RHS)
+ return TryResult();
+
+ if (!LHS->isComparisonOp() || !RHS->isComparisonOp())
+ return TryResult();
+
+ BinaryOperatorKind BO1 = LHS->getOpcode();
+ const DeclRefExpr *Decl1 =
+ dyn_cast<DeclRefExpr>(LHS->getLHS()->IgnoreParenImpCasts());
+ const IntegerLiteral *Literal1 =
+ dyn_cast<IntegerLiteral>(LHS->getRHS()->IgnoreParens());
+ if (!Decl1 && !Literal1) {
+ if (BO1 == BO_GT)
+ BO1 = BO_LT;
+ else if (BO1 == BO_GE)
+ BO1 = BO_LE;
+ else if (BO1 == BO_LT)
+ BO1 = BO_GT;
+ else if (BO1 == BO_LE)
+ BO1 = BO_GE;
+ Decl1 = dyn_cast<DeclRefExpr>(LHS->getRHS()->IgnoreParenImpCasts());
+ Literal1 = dyn_cast<IntegerLiteral>(LHS->getLHS()->IgnoreParens());
+ }
+
+ if (!Decl1 || !Literal1)
+ return TryResult();
+
+ BinaryOperatorKind BO2 = RHS->getOpcode();
+ const DeclRefExpr *Decl2 =
+ dyn_cast<DeclRefExpr>(RHS->getLHS()->IgnoreParenImpCasts());
+ const IntegerLiteral *Literal2 =
+ dyn_cast<IntegerLiteral>(RHS->getRHS()->IgnoreParens());
+ if (!Decl2 && !Literal2) {
+ if (BO2 == BO_GT)
+ BO2 = BO_LT;
+ else if (BO2 == BO_GE)
+ BO2 = BO_LE;
+ else if (BO2 == BO_LT)
+ BO2 = BO_GT;
+ else if (BO2 == BO_LE)
+ BO2 = BO_GE;
+ Decl2 = dyn_cast<DeclRefExpr>(RHS->getRHS()->IgnoreParenImpCasts());
+ Literal2 = dyn_cast<IntegerLiteral>(RHS->getLHS()->IgnoreParens());
+ }
+
+ if (!Decl2 || !Literal2)
+ return TryResult();
+
+ // Check that it is the same variable on both sides.
+ if (Decl1->getDecl() != Decl2->getDecl())
+ return TryResult();
+
+ llvm::APSInt L1, L2;
+
+ if (!Literal1->EvaluateAsInt(L1, *Context) ||
+ !Literal2->EvaluateAsInt(L2, *Context))
+ return TryResult();
+
+ // Can't compare signed with unsigned or with different bit width.
+ if (L1.isSigned() != L2.isSigned() || L1.getBitWidth() != L2.getBitWidth())
+ return TryResult();
+
+ // Values that will be used to determine if result of logical
+ // operator is always true/false
+ const llvm::APSInt Values[] = {
+ // Value less than both Value1 and Value2
+ llvm::APSInt::getMinValue(L1.getBitWidth(), L1.isUnsigned()),
+ // L1
+ L1,
+ // Value between Value1 and Value2
+ ((L1 < L2) ? L1 : L2) + llvm::APSInt(llvm::APInt(L1.getBitWidth(), 1),
+ L1.isUnsigned()),
+ // L2
+ L2,
+ // Value greater than both Value1 and Value2
+ llvm::APSInt::getMaxValue(L1.getBitWidth(), L1.isUnsigned()),
+ };
+
+ // Check whether expression is always true/false by evaluating the following
+ // * variable x is less than the smallest literal.
+ // * variable x is equal to the smallest literal.
+ // * Variable x is between smallest and largest literal.
+ // * Variable x is equal to the largest literal.
+ // * Variable x is greater than largest literal.
+ bool AlwaysTrue = true, AlwaysFalse = true;
+ for (unsigned int ValueIndex = 0;
+ ValueIndex < sizeof(Values) / sizeof(Values[0]);
+ ++ValueIndex) {
+ llvm::APSInt Value = Values[ValueIndex];
+ TryResult Res1, Res2;
+ Res1 = analyzeLogicOperatorCondition(BO1, Value, L1);
+ Res2 = analyzeLogicOperatorCondition(BO2, Value, L2);
+
+ if (!Res1.isKnown() || !Res2.isKnown())
+ return TryResult();
+
+ if (B->getOpcode() == BO_LAnd) {
+ AlwaysTrue &= (Res1.isTrue() && Res2.isTrue());
+ AlwaysFalse &= !(Res1.isTrue() && Res2.isTrue());
+ } else {
+ AlwaysTrue &= (Res1.isTrue() || Res2.isTrue());
+ AlwaysFalse &= !(Res1.isTrue() || Res2.isTrue());
+ }
+ }
+
+ if (AlwaysTrue || AlwaysFalse) {
+ if (BuildOpts.Observer)
+ BuildOpts.Observer->compareAlwaysTrue(B, AlwaysTrue);
+ return TryResult(AlwaysTrue);
+ }
+ return TryResult();
+ }
+
/// Try and evaluate an expression to an integer constant.
bool tryEvaluate(Expr *S, Expr::EvalResult &outResult) {
if (!BuildOpts.PruneTriviallyFalseEdges)
@@ -577,10 +786,22 @@ private:
// is determined by the RHS: X && 0 -> 0, X || 1 -> 1.
if (RHS.isTrue() == (Bop->getOpcode() == BO_LOr))
return RHS.isTrue();
+ } else {
+ TryResult BopRes = checkIncorrectLogicOperator(Bop);
+ if (BopRes.isKnown())
+ return BopRes.isTrue();
}
}
return TryResult();
+ } else if (Bop->isEqualityOp()) {
+ TryResult BopRes = checkIncorrectEqualityOperator(Bop);
+ if (BopRes.isKnown())
+ return BopRes.isTrue();
+ } else if (Bop->isRelationalOp()) {
+ TryResult BopRes = checkIncorrectRelationalOperator(Bop);
+ if (BopRes.isKnown())
+ return BopRes.isTrue();
}
}
@@ -1320,6 +1541,8 @@ CFGBuilder::VisitLogicalOperator(BinaryOperator *B,
else {
RHSBlock->setTerminator(Term);
TryResult KnownVal = tryEvaluateBool(RHS);
+ if (!KnownVal.isKnown())
+ KnownVal = tryEvaluateBool(B);
addSuccessor(RHSBlock, TrueBlock, !KnownVal.isFalse());
addSuccessor(RHSBlock, FalseBlock, !KnownVal.isTrue());
}
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index 9630bc0be0..f3e4358974 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -22,6 +22,7 @@ add_clang_library(clangAnalysis
PseudoConstantAnalysis.cpp
ReachableCode.cpp
ScanfFormatString.cpp
+ ThreadSafetyCommon.cpp
ThreadSafety.cpp
UninitializedValues.cpp
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
index 649ba57bf5..f78f6740d4 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Analysis/CallGraph.cpp
@@ -10,8 +10,6 @@
// This file defines the AST-based CallGraph.
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "CallGraph"
-
#include "clang/Analysis/CallGraph.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
@@ -22,6 +20,8 @@
using namespace clang;
+#define DEBUG_TYPE "CallGraph"
+
STATISTIC(NumObjCCallEdges, "Number of Objective-C method call edges");
STATISTIC(NumBlockCallEdges, "Number of block call edges");
diff --git a/lib/Analysis/Consumed.cpp b/lib/Analysis/Consumed.cpp
index 7b6ad574b7..aac5658d56 100644
--- a/lib/Analysis/Consumed.cpp
+++ b/lib/Analysis/Consumed.cpp
@@ -57,11 +57,9 @@ ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {}
static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
// Find the source location of the first statement in the block, if the block
// is not empty.
- for (CFGBlock::const_iterator BI = Block->begin(), BE = Block->end();
- BI != BE; ++BI) {
- if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>())
+ for (const auto &B : *Block)
+ if (Optional<CFGStmt> CS = B.getAs<CFGStmt>())
return CS->getStmt()->getLocStart();
- }
// Block is empty.
// If we have one successor, return the first statement in that block
@@ -1144,21 +1142,19 @@ bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
ConsumedWarningsHandlerBase &WarningsHandler) const {
- for (VarMapType::const_iterator DMI = VarMap.begin(), DME = VarMap.end();
- DMI != DME; ++DMI) {
-
- if (isa<ParmVarDecl>(DMI->first)) {
- const ParmVarDecl *Param = cast<ParmVarDecl>(DMI->first);
+ for (const auto &DM : VarMap) {
+ if (isa<ParmVarDecl>(DM.first)) {
+ const ParmVarDecl *Param = cast<ParmVarDecl>(DM.first);
const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
if (!RTA)
continue;
ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA);
- if (DMI->second != ExpectedState)
+ if (DM.second != ExpectedState)
WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
Param->getNameAsString(), stateToString(ExpectedState),
- stateToString(DMI->second));
+ stateToString(DM.second));
}
}
}
@@ -1194,16 +1190,14 @@ void ConsumedStateMap::intersect(const ConsumedStateMap *Other) {
return;
}
- for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
- DME = Other->VarMap.end(); DMI != DME; ++DMI) {
-
- LocalState = this->getState(DMI->first);
+ for (const auto &DM : Other->VarMap) {
+ LocalState = this->getState(DM.first);
if (LocalState == CS_None)
continue;
- if (LocalState != DMI->second)
- VarMap[DMI->first] = CS_Unknown;
+ if (LocalState != DM.second)
+ VarMap[DM.first] = CS_Unknown;
}
}
@@ -1214,18 +1208,16 @@ void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
ConsumedState LocalState;
SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
- for (VarMapType::const_iterator DMI = LoopBackStates->VarMap.begin(),
- DME = LoopBackStates->VarMap.end(); DMI != DME; ++DMI) {
-
- LocalState = this->getState(DMI->first);
+ for (const auto &DM : LoopBackStates->VarMap) {
+ LocalState = this->getState(DM.first);
if (LocalState == CS_None)
continue;
- if (LocalState != DMI->second) {
- VarMap[DMI->first] = CS_Unknown;
- WarningsHandler.warnLoopStateMismatch(
- BlameLoc, DMI->first->getNameAsString());
+ if (LocalState != DM.second) {
+ VarMap[DM.first] = CS_Unknown;
+ WarningsHandler.warnLoopStateMismatch(BlameLoc,
+ DM.first->getNameAsString());
}
}
}
@@ -1250,13 +1242,9 @@ void ConsumedStateMap::remove(const VarDecl *Var) {
}
bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
- for (VarMapType::const_iterator DMI = Other->VarMap.begin(),
- DME = Other->VarMap.end(); DMI != DME; ++DMI) {
-
- if (this->getState(DMI->first) != DMI->second)
- return true;
- }
-
+ for (const auto &DM : Other->VarMap)
+ if (this->getState(DM.first) != DM.second)
+ return true;
return false;
}
@@ -1396,16 +1384,11 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
ConsumedStmtVisitor Visitor(AC, *this, CurrStates);
// Add all trackable parameters to the state map.
- for (auto PI : D->params()) {
+ for (const auto *PI : D->params())
Visitor.VisitParmVarDecl(PI);
- }
// Visit all of the function's basic blocks.
- for (PostOrderCFGView::iterator I = SortedGraph->begin(),
- E = SortedGraph->end(); I != E; ++I) {
-
- const CFGBlock *CurrBlock = *I;
-
+ for (const auto *CurrBlock : *SortedGraph) {
if (CurrStates == NULL)
CurrStates = BlockInfo.getInfo(CurrBlock);
@@ -1421,16 +1404,14 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
Visitor.reset(CurrStates);
// Visit all of the basic block's statements.
- for (CFGBlock::const_iterator BI = CurrBlock->begin(),
- BE = CurrBlock->end(); BI != BE; ++BI) {
-
- switch (BI->getKind()) {
+ for (const auto &B : *CurrBlock) {
+ switch (B.getKind()) {
case CFGElement::Statement:
- Visitor.Visit(BI->castAs<CFGStmt>().getStmt());
+ Visitor.Visit(B.castAs<CFGStmt>().getStmt());
break;
case CFGElement::TemporaryDtor: {
- const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>();
+ const CFGTemporaryDtor &DTor = B.castAs<CFGTemporaryDtor>();
const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
Visitor.checkCallability(PropagationInfo(BTE),
@@ -1440,7 +1421,7 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
}
case CFGElement::AutomaticObjectDtor: {
- const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>();
+ const CFGAutomaticObjDtor &DTor = B.castAs<CFGAutomaticObjDtor>();
SourceLocation Loc = DTor.getTriggerStmt()->getLocEnd();
const VarDecl *Var = DTor.getVarDecl();
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index 3cc8ae4a08..8be1af7cef 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -139,6 +139,9 @@ static bool isConfigurationValue(const Stmt *S,
if (!S)
return false;
+ if (const Expr *Ex = dyn_cast<Expr>(S))
+ S = Ex->IgnoreCasts();
+
// Special case looking for the sigil '()' around an integer literal.
if (const ParenExpr *PE = dyn_cast<ParenExpr>(S))
if (!PE->getLocStart().isMacroID())
@@ -146,7 +149,7 @@ static bool isConfigurationValue(const Stmt *S,
IncludeIntegers, true);
if (const Expr *Ex = dyn_cast<Expr>(S))
- S = Ex->IgnoreParenCasts();
+ S = Ex->IgnoreCasts();
bool IgnoreYES_NO = false;
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index fd804eba99..94d8e7025c 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -10,18 +10,21 @@
// A intra-procedural analysis for thread safety (e.g. deadlocks and race
// conditions), based off of an annotation system.
//
-// See http://clang.llvm.org/docs/LanguageExtensions.html#thread-safety-annotation-checking
+// See http://clang.llvm.org/docs/ThreadSafetyAnalysis.html
// for more information.
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/Analyses/ThreadSafety.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Analysis/Analyses/ThreadSafety.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
+#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
@@ -1066,8 +1069,8 @@ public:
}
/// Builds the variable map.
- void traverseCFG(CFG *CFGraph, PostOrderCFGView *SortedGraph,
- std::vector<CFGBlockInfo> &BlockInfo);
+ void traverseCFG(CFG *CFGraph, const PostOrderCFGView *SortedGraph,
+ std::vector<CFGBlockInfo> &BlockInfo);
protected:
// Get the current context index
@@ -1286,15 +1289,13 @@ void LocalVariableMap::intersectBackEdge(Context C1, Context C2) {
// ... { y -> y1 | x3 = 2, x2 = 1, ... }
//
void LocalVariableMap::traverseCFG(CFG *CFGraph,
- PostOrderCFGView *SortedGraph,
+ const PostOrderCFGView *SortedGraph,
std::vector<CFGBlockInfo> &BlockInfo) {
PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
CtxIndices.resize(CFGraph->getNumBlockIDs());
- for (PostOrderCFGView::iterator I = SortedGraph->begin(),
- E = SortedGraph->end(); I!= E; ++I) {
- const CFGBlock *CurrBlock = *I;
+ for (const auto *CurrBlock : *SortedGraph) {
int CurrBlockID = CurrBlock->getBlockID();
CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
@@ -1373,11 +1374,9 @@ void LocalVariableMap::traverseCFG(CFG *CFGraph,
/// Find the appropriate source locations to use when producing diagnostics for
/// each block in the CFG.
static void findBlockLocations(CFG *CFGraph,
- PostOrderCFGView *SortedGraph,
+ const PostOrderCFGView *SortedGraph,
std::vector<CFGBlockInfo> &BlockInfo) {
- for (PostOrderCFGView::iterator I = SortedGraph->begin(),
- E = SortedGraph->end(); I!= E; ++I) {
- const CFGBlock *CurrBlock = *I;
+ for (const auto *CurrBlock : *SortedGraph) {
CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlock->getBlockID()];
// Find the source location of the last statement in the block, if the
@@ -2362,16 +2361,21 @@ inline bool neverReturns(const CFGBlock* B) {
/// at the end of each block, and issue warnings for thread safety violations.
/// Each block in the CFG is traversed exactly once.
void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
- CFG *CFGraph = AC.getCFG();
- if (!CFGraph) return;
- const NamedDecl *D = dyn_cast_or_null<NamedDecl>(AC.getDecl());
+ // TODO: this whole function needs be rewritten as a visitor for CFGWalker.
+ // For now, we just use the walker to set things up.
+ threadSafety::CFGWalker walker;
+ if (!walker.init(AC))
+ return;
// AC.dumpCFG(true);
+ // threadSafety::printSCFG(walker);
+
+ CFG *CFGraph = walker.getGraph();
+ const NamedDecl *D = walker.getDecl();
- if (!D)
- return; // Ignore anonymous functions for now.
if (D->hasAttr<NoThreadSafetyAnalysisAttr>())
return;
+
// FIXME: Do something a bit more intelligent inside constructor and
// destructor code. Constructors and destructors must assume unique access
// to 'this', so checks on member variable access is disabled, but we should
@@ -2387,7 +2391,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
// We need to explore the CFG via a "topological" ordering.
// That way, we will be guaranteed to have information about required
// predecessor locksets when exploring a new block.
- PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
+ const PostOrderCFGView *SortedGraph = walker.getSortedGraph();
PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph);
// Mark entry block as reachable
@@ -2416,23 +2420,22 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
StringRef CapDiagKind = "mutex";
SourceLocation Loc = D->getLocation();
- for (unsigned i = 0; i < ArgAttrs.size(); ++i) {
- Attr *Attr = ArgAttrs[i];
+ for (const auto *Attr : ArgAttrs) {
Loc = Attr->getLocation();
- if (RequiresCapabilityAttr *A = dyn_cast<RequiresCapabilityAttr>(Attr)) {
+ if (const auto *A = dyn_cast<RequiresCapabilityAttr>(Attr)) {
getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A,
0, D);
CapDiagKind = ClassifyDiagnostic(A);
- } else if (auto *A = dyn_cast<ReleaseCapabilityAttr>(Attr)) {
+ } else if (const auto *A = dyn_cast<ReleaseCapabilityAttr>(Attr)) {
// UNLOCK_FUNCTION() is used to hide the underlying lock implementation.
// We must ignore such methods.
if (A->args_size() == 0)
return;
// FIXME -- deal with exclusive vs. shared unlock functions?
- getMutexIDs(ExclusiveLocksToAdd, A, (Expr*) 0, D);
- getMutexIDs(LocksReleased, A, (Expr*) 0, D);
+ getMutexIDs(ExclusiveLocksToAdd, A, nullptr, D);
+ getMutexIDs(LocksReleased, A, nullptr, D);
CapDiagKind = ClassifyDiagnostic(A);
- } else if (auto *A = dyn_cast<AcquireCapabilityAttr>(Attr)) {
+ } else if (const auto *A = dyn_cast<AcquireCapabilityAttr>(Attr)) {
if (A->args_size() == 0)
return;
getMutexIDs(A->isShared() ? SharedLocksAcquired
@@ -2457,9 +2460,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
CapDiagKind);
}
- for (PostOrderCFGView::iterator I = SortedGraph->begin(),
- E = SortedGraph->end(); I!= E; ++I) {
- const CFGBlock *CurrBlock = *I;
+ for (const auto *CurrBlock : *SortedGraph) {
int CurrBlockID = CurrBlock->getBlockID();
CFGBlockInfo *CurrBlockInfo = &BlockInfo[CurrBlockID];
@@ -2485,7 +2486,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
PE = CurrBlock->pred_end(); PI != PE; ++PI) {
// if *PI -> CurrBlock is a back edge
- if (*PI == 0 || !VisitedBlocks.alreadySet(*PI))
+ if (*PI == nullptr || !VisitedBlocks.alreadySet(*PI))
continue;
int PrevBlockID = (*PI)->getBlockID();
@@ -2528,9 +2529,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
// Process continue and break blocks. Assume that the lockset for the
// resulting block is unaffected by any discrepancies in them.
- for (unsigned SpecialI = 0, SpecialN = SpecialBlocks.size();
- SpecialI < SpecialN; ++SpecialI) {
- CFGBlock *PrevBlock = SpecialBlocks[SpecialI];
+ for (const auto *PrevBlock : SpecialBlocks) {
int PrevBlockID = PrevBlock->getBlockID();
CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
@@ -2626,17 +2625,14 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
// by *-LOCK_FUNCTION and UNLOCK_FUNCTION. The intersect below will then
// issue the appropriate warning.
// FIXME: the location here is not quite right.
- for (unsigned i=0,n=ExclusiveLocksAcquired.size(); i<n; ++i) {
- ExpectedExitSet.addLock(FactMan, ExclusiveLocksAcquired[i],
+ for (const auto &Lock : ExclusiveLocksAcquired)
+ ExpectedExitSet.addLock(FactMan, Lock,
LockData(D->getLocation(), LK_Exclusive));
- }
- for (unsigned i=0,n=SharedLocksAcquired.size(); i<n; ++i) {
- ExpectedExitSet.addLock(FactMan, SharedLocksAcquired[i],
+ for (const auto &Lock : SharedLocksAcquired)
+ ExpectedExitSet.addLock(FactMan, Lock,
LockData(D->getLocation(), LK_Shared));
- }
- for (unsigned i=0,n=LocksReleased.size(); i<n; ++i) {
- ExpectedExitSet.removeLock(FactMan, LocksReleased[i]);
- }
+ for (const auto &Lock : LocksReleased)
+ ExpectedExitSet.removeLock(FactMan, Lock);
// FIXME: Should we call this function for all blocks which exit the function?
intersectAndWarn(ExpectedExitSet, Final->ExitSet,
diff --git a/lib/Analysis/ThreadSafetyCommon.cpp b/lib/Analysis/ThreadSafetyCommon.cpp
new file mode 100644
index 0000000000..0a6efebd31
--- /dev/null
+++ b/lib/Analysis/ThreadSafetyCommon.cpp
@@ -0,0 +1,808 @@
+//===- ThreadSafetyCommon.cpp ----------------------------------*- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of the interfaces declared in ThreadSafetyCommon.h
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/Analyses/ThreadSafetyCommon.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
+#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+#include <algorithm>
+#include <climits>
+#include <vector>
+
+
+namespace clang {
+namespace threadSafety {
+
+namespace til {
+
+// If E is a variable, then trace back through any aliases or redundant
+// Phi nodes to find the canonical definition.
+SExpr *getCanonicalVal(SExpr *E) {
+ while (auto *V = dyn_cast<Variable>(E)) {
+ SExpr *D;
+ do {
+ if (V->kind() != Variable::VK_Let)
+ return V;
+ D = V->definition();
+ auto *V2 = dyn_cast<Variable>(D);
+ if (V2)
+ V = V2;
+ else
+ break;
+ } while (true);
+
+ if (ThreadSafetyTIL::isTrivial(D))
+ return D;
+
+ if (Phi *Ph = dyn_cast<Phi>(D)) {
+ if (Ph->status() == Phi::PH_Incomplete)
+ simplifyIncompleteArg(V, Ph);
+
+ if (Ph->status() == Phi::PH_SingleVal) {
+ E = Ph->values()[0];
+ continue;
+ }
+ }
+ return V;
+ }
+ return E;
+}
+
+
+// Trace the arguments of an incomplete Phi node to see if they have the same
+// canonical definition. If so, mark the Phi node as redundant.
+// getCanonicalVal() will recursively call simplifyIncompletePhi().
+void simplifyIncompleteArg(Variable *V, til::Phi *Ph) {
+ assert(Ph && Ph->status() == Phi::PH_Incomplete);
+
+ // eliminate infinite recursion -- assume that this node is not redundant.
+ Ph->setStatus(Phi::PH_MultiVal);
+
+ SExpr *E0 = getCanonicalVal(Ph->values()[0]);
+ for (unsigned i=1, n=Ph->values().size(); i<n; ++i) {
+ SExpr *Ei = getCanonicalVal(Ph->values()[i]);
+ if (Ei == V)
+ continue; // Recursive reference to itself. Don't count.
+ if (Ei != E0) {
+ return; // Status is already set to MultiVal.
+ }
+ }
+ Ph->setStatus(Phi::PH_SingleVal);
+ // Eliminate Redundant Phi node.
+ V->setDefinition(Ph->values()[0]);
+}
+
+
+// Return true if E is a variable that points to an incomplete Phi node.
+static bool isIncompleteVar(const SExpr *E) {
+ if (const auto *V = dyn_cast<Variable>(E)) {
+ if (const auto *Ph = dyn_cast<Phi>(V->definition()))
+ return Ph->status() == Phi::PH_Incomplete;
+ }
+ return false;
+}
+
+
+} // end namespace til
+
+
+typedef SExprBuilder::CallingContext CallingContext;
+
+
+til::SExpr *SExprBuilder::lookupStmt(const Stmt *S) {
+ auto It = SMap.find(S);
+ if (It != SMap.end())
+ return It->second;
+ return nullptr;
+}
+
+
+til::SCFG *SExprBuilder::buildCFG(CFGWalker &Walker) {
+ Walker.walk(*this);
+ return Scfg;
+}
+
+
+// Translate a clang statement or expression to a TIL expression.
+// Also performs substitution of variables; Ctx provides the context.
+// Dispatches on the type of S.
+til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) {
+ if (!S)
+ return nullptr;
+
+ // Check if S has already been translated and cached.
+ // This handles the lookup of SSA names for DeclRefExprs here.
+ if (til::SExpr *E = lookupStmt(S))
+ return E;
+
+ switch (S->getStmtClass()) {
+ case Stmt::DeclRefExprClass:
+ return translateDeclRefExpr(cast<DeclRefExpr>(S), Ctx);
+ case Stmt::CXXThisExprClass:
+ return translateCXXThisExpr(cast<CXXThisExpr>(S), Ctx);
+ case Stmt::MemberExprClass:
+ return translateMemberExpr(cast<MemberExpr>(S), Ctx);
+ case Stmt::CallExprClass:
+ return translateCallExpr(cast<CallExpr>(S), Ctx);
+ case Stmt::CXXMemberCallExprClass:
+ return translateCXXMemberCallExpr(cast<CXXMemberCallExpr>(S), Ctx);
+ case Stmt::CXXOperatorCallExprClass:
+ return translateCXXOperatorCallExpr(cast<CXXOperatorCallExpr>(S), Ctx);
+ case Stmt::UnaryOperatorClass:
+ return translateUnaryOperator(cast<UnaryOperator>(S), Ctx);
+ case Stmt::BinaryOperatorClass:
+ case Stmt::CompoundAssignOperatorClass:
+ return translateBinaryOperator(cast<BinaryOperator>(S), Ctx);
+
+ case Stmt::ArraySubscriptExprClass:
+ return translateArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Ctx);
+ case Stmt::ConditionalOperatorClass:
+ return translateConditionalOperator(cast<ConditionalOperator>(S), Ctx);
+ case Stmt::BinaryConditionalOperatorClass:
+ return translateBinaryConditionalOperator(
+ cast<BinaryConditionalOperator>(S), Ctx);
+
+ // We treat these as no-ops
+ case Stmt::ParenExprClass:
+ return translate(cast<ParenExpr>(S)->getSubExpr(), Ctx);
+ case Stmt::ExprWithCleanupsClass:
+ return translate(cast<ExprWithCleanups>(S)->getSubExpr(), Ctx);
+ case Stmt::CXXBindTemporaryExprClass:
+ return translate(cast<CXXBindTemporaryExpr>(S)->getSubExpr(), Ctx);
+
+ // Collect all literals
+ case Stmt::CharacterLiteralClass:
+ case Stmt::CXXNullPtrLiteralExprClass:
+ case Stmt::GNUNullExprClass:
+ case Stmt::CXXBoolLiteralExprClass:
+ case Stmt::FloatingLiteralClass:
+ case Stmt::ImaginaryLiteralClass:
+ case Stmt::IntegerLiteralClass:
+ case Stmt::StringLiteralClass:
+ case Stmt::ObjCStringLiteralClass:
+ return new (Arena) til::Literal(cast<Expr>(S));
+
+ case Stmt::DeclStmtClass:
+ return translateDeclStmt(cast<DeclStmt>(S), Ctx);
+ default:
+ break;
+ }
+ if (const CastExpr *CE = dyn_cast<CastExpr>(S))
+ return translateCastExpr(CE, Ctx);
+
+ return new (Arena) til::Undefined(S);
+}
+
+
+til::SExpr *SExprBuilder::translateDeclRefExpr(const DeclRefExpr *DRE,
+ CallingContext *Ctx) {
+ const ValueDecl *VD = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
+
+ // Function parameters require substitution and/or renaming.
+ if (const ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(VD)) {
+ const FunctionDecl *FD =
+ cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl();
+ unsigned I = PV->getFunctionScopeIndex();
+
+ if (Ctx && Ctx->FunArgs && FD == Ctx->AttrDecl->getCanonicalDecl()) {
+ // Substitute call arguments for references to function parameters
+ assert(I < Ctx->NumArgs);
+ return translate(Ctx->FunArgs[I], Ctx->Prev);
+ }
+ // Map the param back to the param of the original function declaration
+ // for consistent comparisons.
+ VD = FD->getParamDecl(I);
+ }
+
+ // For non-local variables, treat it as a referenced to a named object.
+ return new (Arena) til::LiteralPtr(VD);
+}
+
+
+til::SExpr *SExprBuilder::translateCXXThisExpr(const CXXThisExpr *TE,
+ CallingContext *Ctx) {
+ // Substitute for 'this'
+ if (Ctx && Ctx->SelfArg)
+ return translate(Ctx->SelfArg, Ctx->Prev);
+ assert(SelfVar && "We have no variable for 'this'!");
+ return SelfVar;
+}
+
+
+til::SExpr *SExprBuilder::translateMemberExpr(const MemberExpr *ME,
+ CallingContext *Ctx) {
+ til::SExpr *E = translate(ME->getBase(), Ctx);
+ E = new (Arena) til::SApply(E);
+ return new (Arena) til::Project(E, ME->getMemberDecl());
+}
+
+
+til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
+ CallingContext *Ctx) {
+ // TODO -- Lock returned
+ til::SExpr *E = translate(CE->getCallee(), Ctx);
+ for (const auto *Arg : CE->arguments()) {
+ til::SExpr *A = translate(Arg, Ctx);
+ E = new (Arena) til::Apply(E, A);
+ }
+ return new (Arena) til::Call(E, CE);
+}
+
+
+til::SExpr *SExprBuilder::translateCXXMemberCallExpr(
+ const CXXMemberCallExpr *ME, CallingContext *Ctx) {
+ return translateCallExpr(cast<CallExpr>(ME), Ctx);
+}
+
+
+til::SExpr *SExprBuilder::translateCXXOperatorCallExpr(
+ const CXXOperatorCallExpr *OCE, CallingContext *Ctx) {
+ return translateCallExpr(cast<CallExpr>(OCE), Ctx);
+}
+
+
+til::SExpr *SExprBuilder::translateUnaryOperator(const UnaryOperator *UO,
+ CallingContext *Ctx) {
+ switch (UO->getOpcode()) {
+ case UO_PostInc:
+ case UO_PostDec:
+ case UO_PreInc:
+ case UO_PreDec:
+ return new (Arena) til::Undefined(UO);
+
+ // We treat these as no-ops
+ case UO_AddrOf:
+ case UO_Deref:
+ case UO_Plus:
+ return translate(UO->getSubExpr(), Ctx);
+
+ case UO_Minus:
+ case UO_Not:
+ case UO_LNot:
+ case UO_Real:
+ case UO_Imag:
+ case UO_Extension:
+ return new (Arena)
+ til::UnaryOp(UO->getOpcode(), translate(UO->getSubExpr(), Ctx));
+ }
+ return new (Arena) til::Undefined(UO);
+}
+
+
+til::SExpr *SExprBuilder::translateBinAssign(til::TIL_BinaryOpcode Op,
+ const BinaryOperator *BO,
+ CallingContext *Ctx) {
+ const Expr *LHS = BO->getLHS();
+ const Expr *RHS = BO->getRHS();
+ til::SExpr *E0 = translate(LHS, Ctx);
+ til::SExpr *E1 = translate(RHS, Ctx);
+
+ const ValueDecl *VD = nullptr;
+ til::SExpr *CV = nullptr;
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LHS)) {
+ VD = DRE->getDecl();
+ CV = lookupVarDecl(VD);
+ }
+
+ if (Op != BO_Assign) {
+ til::SExpr *Arg = CV ? CV : new (Arena) til::Load(E0);
+ E1 = new (Arena) til::BinaryOp(Op, Arg, E1);
+ E1 = addStatement(E1, nullptr, VD);
+ }
+ if (VD && CV)
+ return updateVarDecl(VD, E1);
+ return new (Arena) til::Store(E0, E1);
+}
+
+
+til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
+ CallingContext *Ctx) {
+ switch (BO->getOpcode()) {
+ case BO_PtrMemD:
+ case BO_PtrMemI:
+ return new (Arena) til::Undefined(BO);
+
+ case BO_Mul:
+ case BO_Div:
+ case BO_Rem:
+ case BO_Add:
+ case BO_Sub:
+ case BO_Shl:
+ case BO_Shr:
+ case BO_LT:
+ case BO_GT:
+ case BO_LE:
+ case BO_GE:
+ case BO_EQ:
+ case BO_NE:
+ case BO_And:
+ case BO_Xor:
+ case BO_Or:
+ case BO_LAnd:
+ case BO_LOr:
+ return new (Arena)
+ til::BinaryOp(BO->getOpcode(), translate(BO->getLHS(), Ctx),
+ translate(BO->getRHS(), Ctx));
+
+ case BO_Assign: return translateBinAssign(BO_Assign, BO, Ctx);
+ case BO_MulAssign: return translateBinAssign(BO_Mul, BO, Ctx);
+ case BO_DivAssign: return translateBinAssign(BO_Div, BO, Ctx);
+ case BO_RemAssign: return translateBinAssign(BO_Rem, BO, Ctx);
+ case BO_AddAssign: return translateBinAssign(BO_Add, BO, Ctx);
+ case BO_SubAssign: return translateBinAssign(BO_Sub, BO, Ctx);
+ case BO_ShlAssign: return translateBinAssign(BO_Shl, BO, Ctx);
+ case BO_ShrAssign: return translateBinAssign(BO_Shr, BO, Ctx);
+ case BO_AndAssign: return translateBinAssign(BO_And, BO, Ctx);
+ case BO_XorAssign: return translateBinAssign(BO_Xor, BO, Ctx);
+ case BO_OrAssign: return translateBinAssign(BO_Or, BO, Ctx);
+
+ case BO_Comma:
+ // The clang CFG should have already processed both sides.
+ return translate(BO->getRHS(), Ctx);
+ }
+ return new (Arena) til::Undefined(BO);
+}
+
+
+til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
+ CallingContext *Ctx) {
+ clang::CastKind K = CE->getCastKind();
+ switch (K) {
+ case CK_LValueToRValue: {
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CE->getSubExpr())) {
+ til::SExpr *E0 = lookupVarDecl(DRE->getDecl());
+ if (E0)
+ return E0;
+ }
+ til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
+ return new (Arena) til::Load(E0);
+ }
+ case CK_NoOp:
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase:
+ case CK_ArrayToPointerDecay:
+ case CK_FunctionToPointerDecay: {
+ til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
+ return E0;
+ }
+ default: {
+ til::SExpr *E0 = translate(CE->getSubExpr(), Ctx);
+ return new (Arena) til::Cast(K, E0);
+ }
+ }
+}
+
+
+til::SExpr *
+SExprBuilder::translateArraySubscriptExpr(const ArraySubscriptExpr *E,
+ CallingContext *Ctx) {
+ til::SExpr *E0 = translate(E->getBase(), Ctx);
+ til::SExpr *E1 = translate(E->getIdx(), Ctx);
+ auto *AA = new (Arena) til::ArrayAdd(E0, E1);
+ return new (Arena) til::ArrayFirst(AA);
+}
+
+
+til::SExpr *
+SExprBuilder::translateConditionalOperator(const ConditionalOperator *C,
+ CallingContext *Ctx) {
+ return new (Arena) til::Undefined(C);
+}
+
+
+til::SExpr *SExprBuilder::translateBinaryConditionalOperator(
+ const BinaryConditionalOperator *C, CallingContext *Ctx) {
+ return new (Arena) til::Undefined(C);
+}
+
+
+til::SExpr *
+SExprBuilder::translateDeclStmt(const DeclStmt *S, CallingContext *Ctx) {
+ DeclGroupRef DGrp = S->getDeclGroup();
+ for (DeclGroupRef::iterator I = DGrp.begin(), E = DGrp.end(); I != E; ++I) {
+ if (VarDecl *VD = dyn_cast_or_null<VarDecl>(*I)) {
+ Expr *E = VD->getInit();
+ til::SExpr* SE = translate(E, Ctx);
+
+ // Add local variables with trivial type to the variable map
+ QualType T = VD->getType();
+ if (T.isTrivialType(VD->getASTContext())) {
+ return addVarDecl(VD, SE);
+ }
+ else {
+ // TODO: add alloca
+ }
+ }
+ }
+ return nullptr;
+}
+
+
+
+// If (E) is non-trivial, then add it to the current basic block, and
+// update the statement map so that S refers to E. Returns a new variable
+// that refers to E.
+// If E is trivial returns E.
+til::SExpr *SExprBuilder::addStatement(til::SExpr* E, const Stmt *S,
+ const ValueDecl *VD) {
+ if (!E)
+ return nullptr;
+ if (til::ThreadSafetyTIL::isTrivial(E))
+ return E;
+
+ til::Variable *V = new (Arena) til::Variable(E, VD);
+ CurrentInstructions.push_back(V);
+ if (S)
+ insertStmt(S, V);
+ return V;
+}
+
+
+// Returns the current value of VD, if known, and nullptr otherwise.
+til::SExpr *SExprBuilder::lookupVarDecl(const ValueDecl *VD) {
+ auto It = LVarIdxMap.find(VD);
+ if (It != LVarIdxMap.end()) {
+ assert(CurrentLVarMap[It->second].first == VD);
+ return CurrentLVarMap[It->second].second;
+ }
+ return nullptr;
+}
+
+
+// if E is a til::Variable, update its clangDecl.
+inline void maybeUpdateVD(til::SExpr *E, const ValueDecl *VD) {
+ if (!E)
+ return;
+ if (til::Variable *V = dyn_cast<til::Variable>(E)) {
+ if (!V->clangDecl())
+ V->setClangDecl(VD);
+ }
+}
+
+// Adds a new variable declaration.
+til::SExpr *SExprBuilder::addVarDecl(const ValueDecl *VD, til::SExpr *E) {
+ maybeUpdateVD(E, VD);
+ LVarIdxMap.insert(std::make_pair(VD, CurrentLVarMap.size()));
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.push_back(std::make_pair(VD, E));
+ return E;
+}
+
+
+// Updates a current variable declaration. (E.g. by assignment)
+til::SExpr *SExprBuilder::updateVarDecl(const ValueDecl *VD, til::SExpr *E) {
+ maybeUpdateVD(E, VD);
+ auto It = LVarIdxMap.find(VD);
+ if (It == LVarIdxMap.end()) {
+ til::SExpr *Ptr = new (Arena) til::LiteralPtr(VD);
+ til::SExpr *St = new (Arena) til::Store(Ptr, E);
+ return St;
+ }
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.elem(It->second).second = E;
+ return E;
+}
+
+
+// Make a Phi node in the current block for the i^th variable in CurrentVarMap.
+// If E != null, sets Phi[CurrentBlockInfo->ArgIndex] = E.
+// If E == null, this is a backedge and will be set later.
+void SExprBuilder::makePhiNodeVar(unsigned i, unsigned NPreds, til::SExpr *E) {
+ unsigned ArgIndex = CurrentBlockInfo->ProcessedPredecessors;
+ assert(ArgIndex > 0 && ArgIndex < NPreds);
+
+ til::Variable *V = dyn_cast<til::Variable>(CurrentLVarMap[i].second);
+ if (V && V->getBlockID() == CurrentBB->blockID()) {
+ // We already have a Phi node in the current block,
+ // so just add the new variable to the Phi node.
+ til::Phi *Ph = dyn_cast<til::Phi>(V->definition());
+ assert(Ph && "Expecting Phi node.");
+ if (E)
+ Ph->values()[ArgIndex] = E;
+ return;
+ }
+
+ // Make a new phi node: phi(..., E)
+ // All phi args up to the current index are set to the current value.
+ til::SExpr *CurrE = CurrentLVarMap[i].second;
+ til::Phi *Ph = new (Arena) til::Phi(Arena, NPreds);
+ Ph->values().setValues(NPreds, nullptr);
+ for (unsigned PIdx = 0; PIdx < ArgIndex; ++PIdx)
+ Ph->values()[PIdx] = CurrE;
+ if (E)
+ Ph->values()[ArgIndex] = E;
+ // If E is from a back-edge, or either E or CurrE are incomplete, then
+ // mark this node as incomplete; we may need to remove it later.
+ if (!E || isIncompleteVar(E) || isIncompleteVar(CurrE)) {
+ Ph->setStatus(til::Phi::PH_Incomplete);
+ }
+
+ // Add Phi node to current block, and update CurrentLVarMap[i]
+ auto *Var = new (Arena) til::Variable(Ph, CurrentLVarMap[i].first);
+ CurrentArguments.push_back(Var);
+ if (Ph->status() == til::Phi::PH_Incomplete)
+ IncompleteArgs.push_back(Var);
+
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.elem(i).second = Var;
+}
+
+
+// Merge values from Map into the current variable map.
+// This will construct Phi nodes in the current basic block as necessary.
+void SExprBuilder::mergeEntryMap(LVarDefinitionMap Map) {
+ assert(CurrentBlockInfo && "Not processing a block!");
+
+ if (!CurrentLVarMap.valid()) {
+ // Steal Map, using copy-on-write.
+ CurrentLVarMap = std::move(Map);
+ return;
+ }
+ if (CurrentLVarMap.sameAs(Map))
+ return; // Easy merge: maps from different predecessors are unchanged.
+
+ unsigned NPreds = CurrentBB->numPredecessors();
+ unsigned ESz = CurrentLVarMap.size();
+ unsigned MSz = Map.size();
+ unsigned Sz = std::min(ESz, MSz);
+
+ for (unsigned i=0; i<Sz; ++i) {
+ if (CurrentLVarMap[i].first != Map[i].first) {
+ // We've reached the end of variables in common.
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.downsize(i);
+ break;
+ }
+ if (CurrentLVarMap[i].second != Map[i].second)
+ makePhiNodeVar(i, NPreds, Map[i].second);
+ }
+ if (ESz > MSz) {
+ CurrentLVarMap.makeWritable();
+ CurrentLVarMap.downsize(Map.size());
+ }
+}
+
+
+// Merge a back edge into the current variable map.
+// This will create phi nodes for all variables in the variable map.
+void SExprBuilder::mergeEntryMapBackEdge() {
+ // We don't have definitions for variables on the backedge, because we
+ // haven't gotten that far in the CFG. Thus, when encountering a back edge,
+ // we conservatively create Phi nodes for all variables. Unnecessary Phi
+ // nodes will be marked as incomplete, and stripped out at the end.
+ //
+ // An Phi node is unnecessary if it only refers to itself and one other
+ // variable, e.g. x = Phi(y, y, x) can be reduced to x = y.
+
+ assert(CurrentBlockInfo && "Not processing a block!");
+
+ if (CurrentBlockInfo->HasBackEdges)
+ return;
+ CurrentBlockInfo->HasBackEdges = true;
+
+ CurrentLVarMap.makeWritable();
+ unsigned Sz = CurrentLVarMap.size();
+ unsigned NPreds = CurrentBB->numPredecessors();
+
+ for (unsigned i=0; i < Sz; ++i) {
+ makePhiNodeVar(i, NPreds, nullptr);
+ }
+}
+
+
+// Update the phi nodes that were initially created for a back edge
+// once the variable definitions have been computed.
+// I.e., merge the current variable map into the phi nodes for Blk.
+void SExprBuilder::mergePhiNodesBackEdge(const CFGBlock *Blk) {
+ til::BasicBlock *BB = lookupBlock(Blk);
+ unsigned ArgIndex = BBInfo[Blk->getBlockID()].ProcessedPredecessors;
+ assert(ArgIndex > 0 && ArgIndex < BB->numPredecessors());
+
+ for (til::Variable *V : BB->arguments()) {
+ til::Phi *Ph = dyn_cast_or_null<til::Phi>(V->definition());
+ assert(Ph && "Expecting Phi Node.");
+ assert(Ph->values()[ArgIndex] == nullptr && "Wrong index for back edge.");
+ assert(V->clangDecl() && "No local variable for Phi node.");
+
+ til::SExpr *E = lookupVarDecl(V->clangDecl());
+ assert(E && "Couldn't find local variable for Phi node.");
+
+ Ph->values()[ArgIndex] = E;
+ }
+}
+
+
+void SExprBuilder::enterCFG(CFG *Cfg, const FunctionDecl *FD,
+ const CFGBlock *First) {
+ // Perform initial setup operations.
+ unsigned NBlocks = Cfg->getNumBlockIDs();
+ Scfg = new (Arena) til::SCFG(Arena, NBlocks);
+
+ // allocate all basic blocks immediately, to handle forward references.
+ BBInfo.resize(NBlocks);
+ BlockMap.resize(NBlocks, nullptr);
+ // create map from clang blockID to til::BasicBlocks
+ for (auto *B : *Cfg) {
+ auto *BB = new (Arena) til::BasicBlock(Arena, 0, B->size());
+ BlockMap[B->getBlockID()] = BB;
+ }
+ CallCtx.reset(new SExprBuilder::CallingContext(FD));
+
+ CurrentBB = lookupBlock(&Cfg->getEntry());
+ for (auto *Pm : FD->parameters()) {
+ QualType T = Pm->getType();
+ if (!T.isTrivialType(Pm->getASTContext()))
+ continue;
+
+ // Add parameters to local variable map.
+ // FIXME: right now we emulate params with loads; that should be fixed.
+ til::SExpr *Lp = new (Arena) til::LiteralPtr(Pm);
+ til::SExpr *Ld = new (Arena) til::Load(Lp);
+ til::SExpr *V = addStatement(Ld, nullptr, Pm);
+ addVarDecl(Pm, V);
+ }
+}
+
+
+void SExprBuilder::enterCFGBlock(const CFGBlock *B) {
+ // Intialize TIL basic block and add it to the CFG.
+ CurrentBB = lookupBlock(B);
+ CurrentBB->setNumPredecessors(B->pred_size());
+ Scfg->add(CurrentBB);
+
+ CurrentBlockInfo = &BBInfo[B->getBlockID()];
+
+ // CurrentLVarMap is moved to ExitMap on block exit.
+ // FIXME: the entry block will hold function parameters.
+ // assert(!CurrentLVarMap.valid() && "CurrentLVarMap already initialized.");
+}
+
+
+void SExprBuilder::handlePredecessor(const CFGBlock *Pred) {
+ // Compute CurrentLVarMap on entry from ExitMaps of predecessors
+
+ BlockInfo *PredInfo = &BBInfo[Pred->getBlockID()];
+ assert(PredInfo->UnprocessedSuccessors > 0);
+
+ if (--PredInfo->UnprocessedSuccessors == 0)
+ mergeEntryMap(std::move(PredInfo->ExitMap));
+ else
+ mergeEntryMap(PredInfo->ExitMap.clone());
+
+ ++CurrentBlockInfo->ProcessedPredecessors;
+}
+
+
+void SExprBuilder::handlePredecessorBackEdge(const CFGBlock *Pred) {
+ mergeEntryMapBackEdge();
+}
+
+
+void SExprBuilder::enterCFGBlockBody(const CFGBlock *B) {
+ // The merge*() methods have created arguments.
+ // Push those arguments onto the basic block.
+ CurrentBB->arguments().reserve(
+ static_cast<unsigned>(CurrentArguments.size()), Arena);
+ for (auto *V : CurrentArguments)
+ CurrentBB->addArgument(V);
+}
+
+
+void SExprBuilder::handleStatement(const Stmt *S) {
+ til::SExpr *E = translate(S, CallCtx.get());
+ addStatement(E, S);
+}
+
+
+void SExprBuilder::handleDestructorCall(const VarDecl *VD,
+ const CXXDestructorDecl *DD) {
+ til::SExpr *Sf = new (Arena) til::LiteralPtr(VD);
+ til::SExpr *Dr = new (Arena) til::LiteralPtr(DD);
+ til::SExpr *Ap = new (Arena) til::Apply(Dr, Sf);
+ til::SExpr *E = new (Arena) til::Call(Ap);
+ addStatement(E, nullptr);
+}
+
+
+
+void SExprBuilder::exitCFGBlockBody(const CFGBlock *B) {
+ CurrentBB->instructions().reserve(
+ static_cast<unsigned>(CurrentInstructions.size()), Arena);
+ for (auto *V : CurrentInstructions)
+ CurrentBB->addInstruction(V);
+
+ // Create an appropriate terminator
+ unsigned N = B->succ_size();
+ auto It = B->succ_begin();
+ if (N == 1) {
+ til::BasicBlock *BB = *It ? lookupBlock(*It) : nullptr;
+ // TODO: set index
+ til::SExpr *Tm = new (Arena) til::Goto(BB, 0);
+ CurrentBB->setTerminator(Tm);
+ }
+ else if (N == 2) {
+ til::SExpr *C = translate(B->getTerminatorCondition(true), CallCtx.get());
+ til::BasicBlock *BB1 = *It ? lookupBlock(*It) : nullptr;
+ ++It;
+ til::BasicBlock *BB2 = *It ? lookupBlock(*It) : nullptr;
+ // TODO: set conditional, set index
+ til::SExpr *Tm = new (Arena) til::Branch(C, BB1, BB2);
+ CurrentBB->setTerminator(Tm);
+ }
+}
+
+
+void SExprBuilder::handleSuccessor(const CFGBlock *Succ) {
+ ++CurrentBlockInfo->UnprocessedSuccessors;
+}
+
+
+void SExprBuilder::handleSuccessorBackEdge(const CFGBlock *Succ) {
+ mergePhiNodesBackEdge(Succ);
+ ++BBInfo[Succ->getBlockID()].ProcessedPredecessors;
+}
+
+
+void SExprBuilder::exitCFGBlock(const CFGBlock *B) {
+ CurrentArguments.clear();
+ CurrentInstructions.clear();
+ CurrentBlockInfo->ExitMap = std::move(CurrentLVarMap);
+ CurrentBB = nullptr;
+ CurrentBlockInfo = nullptr;
+}
+
+
+void SExprBuilder::exitCFG(const CFGBlock *Last) {
+ for (auto *V : IncompleteArgs) {
+ til::Phi *Ph = dyn_cast<til::Phi>(V->definition());
+ if (Ph && Ph->status() == til::Phi::PH_Incomplete)
+ simplifyIncompleteArg(V, Ph);
+ }
+
+ CurrentArguments.clear();
+ CurrentInstructions.clear();
+ IncompleteArgs.clear();
+}
+
+
+
+class LLVMPrinter : public til::PrettyPrinter<LLVMPrinter, llvm::raw_ostream> {
+};
+
+
+void printSCFG(CFGWalker &Walker) {
+ llvm::BumpPtrAllocator Bpa;
+ til::MemRegionRef Arena(&Bpa);
+ SExprBuilder builder(Arena);
+ til::SCFG *Cfg = builder.buildCFG(Walker);
+ LLVMPrinter::print(Cfg, llvm::errs());
+}
+
+
+
+} // end namespace threadSafety
+
+} // end namespace clang
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index cf6933aeb1..5334ae88d1 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -361,6 +361,11 @@ bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) {
return GetDefaultDiagMappingInfo(DiagID).getMapping() == diag::MAP_ERROR;
}
+bool DiagnosticIDs::isRemark(unsigned DiagID) {
+ return DiagID < diag::DIAG_UPPER_LIMIT &&
+ getBuiltinDiagClass(DiagID) == CLASS_REMARK;
+}
+
/// getDescription - Given a diagnostic ID, return a description of the
/// issue.
StringRef DiagnosticIDs::getDescription(unsigned DiagID) const {
diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
index 237c78981f..e75485dbd6 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -25,13 +25,14 @@
using namespace clang;
Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
- bool IsFramework, bool IsExplicit)
- : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent),
- Umbrella(), ASTFile(0), IsAvailable(true), IsFromModuleFile(false),
- IsFramework(IsFramework), IsExplicit(IsExplicit), IsSystem(false),
- IsExternC(false), InferSubmodules(false), InferExplicitSubmodules(false),
- InferExportWildcard(false), ConfigMacrosExhaustive(false),
- NameVisibility(Hidden) {
+ const FileEntry *File, bool IsFramework, bool IsExplicit)
+ : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), ModuleMap(File),
+ Umbrella(), ASTFile(0), IsMissingRequirement(false), IsAvailable(true),
+ IsFromModuleFile(false), IsFramework(IsFramework), IsExplicit(IsExplicit),
+ IsSystem(false), IsExternC(false), IsInferred(false),
+ InferSubmodules(false), InferExplicitSubmodules(false),
+ InferExportWildcard(false), ConfigMacrosExhaustive(false),
+ NameVisibility(Hidden) {
if (Parent) {
if (!Parent->isAvailable())
IsAvailable = false;
@@ -39,6 +40,7 @@ Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
IsSystem = true;
if (Parent->IsExternC)
IsExternC = true;
+ IsMissingRequirement = Parent->IsMissingRequirement;
Parent->SubModuleIndex[Name] = Parent->SubModules.size();
Parent->SubModules.push_back(this);
@@ -91,7 +93,7 @@ Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
llvm_unreachable("could not find a reason why module is unavailable");
}
-bool Module::isSubModuleOf(Module *Other) const {
+bool Module::isSubModuleOf(const Module *Other) const {
const Module *This = this;
do {
if (This == Other)
@@ -160,6 +162,10 @@ void Module::addRequirement(StringRef Feature, bool RequiredState,
if (hasFeature(Feature, LangOpts, Target) == RequiredState)
return;
+ markUnavailable(/*MissingRequirement*/true);
+}
+
+void Module::markUnavailable(bool MissingRequirement) {
if (!IsAvailable)
return;
@@ -173,6 +179,7 @@ void Module::addRequirement(StringRef Feature, bool RequiredState,
continue;
Current->IsAvailable = false;
+ Current->IsMissingRequirement |= MissingRequirement;
for (submodule_iterator Sub = Current->submodule_begin(),
SubEnd = Current->submodule_end();
Sub != SubEnd; ++Sub) {
@@ -354,7 +361,8 @@ void Module::print(raw_ostream &OS, unsigned Indent) const {
for (submodule_const_iterator MI = submodule_begin(), MIEnd = submodule_end();
MI != MIEnd; ++MI)
- (*MI)->print(OS, Indent + 2);
+ if (!(*MI)->IsInferred)
+ (*MI)->print(OS, Indent + 2);
for (unsigned I = 0, N = Exports.size(); I != N; ++I) {
OS.indent(Indent + 2);
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index ec09de1eb3..6a7f89069a 100644
--- a/lib/Basic/OpenMPKinds.cpp
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -83,6 +83,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
+ case OMPC_linear:
case OMPC_copyin:
case NUM_OPENMP_CLAUSES:
break;
@@ -110,6 +111,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
+ case OMPC_linear:
case OMPC_copyin:
case NUM_OPENMP_CLAUSES:
break;
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index b78e9f596e..c78c285e31 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -436,12 +436,8 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt,
ContentCache *&Entry = FileInfos[FileEnt];
if (Entry) return Entry;
- // Nope, create a new Cache entry. Make sure it is at least 8-byte aligned
- // so that FileInfo can use the low 3 bits of the pointer for its own
- // nefarious purposes.
- unsigned EntryAlign = llvm::AlignOf<ContentCache>::Alignment;
- EntryAlign = std::max(8U, EntryAlign);
- Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign);
+ // Nope, create a new Cache entry.
+ Entry = ContentCacheAlloc.Allocate<ContentCache>();
if (OverriddenFilesInfo) {
// If the file contents are overridden with contents from another file,
@@ -468,12 +464,8 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt,
/// memory buffer. This does no caching.
const ContentCache*
SourceManager::createMemBufferContentCache(const MemoryBuffer *Buffer) {
- // Add a new ContentCache to the MemBufferInfos list and return it. Make sure
- // it is at least 8-byte aligned so that FileInfo can use the low 3 bits of
- // the pointer for its own nefarious purposes.
- unsigned EntryAlign = llvm::AlignOf<ContentCache>::Alignment;
- EntryAlign = std::max(8U, EntryAlign);
- ContentCache *Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign);
+ // Add a new ContentCache to the MemBufferInfos list and return it.
+ ContentCache *Entry = ContentCacheAlloc.Allocate<ContentCache>();
new (Entry) ContentCache();
MemBufferInfos.push_back(Entry);
Entry->setBuffer(Buffer);
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index fd59c002ea..ca94b3ff31 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -3066,9 +3066,9 @@ public:
namespace {
// x86-32 Windows Visual Studio target
-class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo {
+class MicrosoftX86_32TargetInfo : public WindowsX86_32TargetInfo {
public:
- VisualStudioWindowsX86_32TargetInfo(const llvm::Triple &Triple)
+ MicrosoftX86_32TargetInfo(const llvm::Triple &Triple)
: WindowsX86_32TargetInfo(Triple) {
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
@@ -3085,6 +3085,33 @@ public:
};
} // end anonymous namespace
+static void addMinGWDefines(const LangOptions &Opts, MacroBuilder &Builder) {
+ Builder.defineMacro("__MSVCRT__");
+ Builder.defineMacro("__MINGW32__");
+
+ // Mingw defines __declspec(a) to __attribute__((a)). Clang supports
+ // __declspec natively under -fms-extensions, but we define a no-op __declspec
+ // macro anyway for pre-processor compatibility.
+ if (Opts.MicrosoftExt)
+ Builder.defineMacro("__declspec", "__declspec");
+ else
+ Builder.defineMacro("__declspec(a)", "__attribute__((a))");
+
+ if (!Opts.MicrosoftExt) {
+ // Provide macros for all the calling convention keywords. Provide both
+ // single and double underscore prefixed variants. These are available on
+ // x64 as well as x86, even though they have no effect.
+ const char *CCs[] = {"cdecl", "stdcall", "fastcall", "thiscall", "pascal"};
+ for (const char *CC : CCs) {
+ std::string GCCSpelling = "__attribute__((__";
+ GCCSpelling += CC;
+ GCCSpelling += "__))";
+ Builder.defineMacro(Twine("_") + CC, GCCSpelling);
+ Builder.defineMacro(Twine("__") + CC, GCCSpelling);
+ }
+ }
+}
+
namespace {
// x86-32 MinGW target
class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo {
@@ -3097,17 +3124,7 @@ public:
DefineStd(Builder, "WIN32", Opts);
DefineStd(Builder, "WINNT", Opts);
Builder.defineMacro("_X86_");
- Builder.defineMacro("__MSVCRT__");
- Builder.defineMacro("__MINGW32__");
-
- // mingw32-gcc provides __declspec(a) as alias of __attribute__((a)).
- // In contrast, clang-cc1 provides __declspec(a) with -fms-extensions.
- if (Opts.MicrosoftExt)
- // Provide "as-is" __declspec.
- Builder.defineMacro("__declspec", "__declspec");
- else
- // Provide alias of __attribute__ like mingw32-gcc.
- Builder.defineMacro("__declspec(a)", "__attribute__((a))");
+ addMinGWDefines(Opts, Builder);
}
};
} // end anonymous namespace
@@ -3300,9 +3317,9 @@ public:
namespace {
// x86-64 Windows Visual Studio target
-class VisualStudioWindowsX86_64TargetInfo : public WindowsX86_64TargetInfo {
+class MicrosoftX86_64TargetInfo : public WindowsX86_64TargetInfo {
public:
- VisualStudioWindowsX86_64TargetInfo(const llvm::Triple &Triple)
+ MicrosoftX86_64TargetInfo(const llvm::Triple &Triple)
: WindowsX86_64TargetInfo(Triple) {
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
@@ -3327,18 +3344,8 @@ public:
MacroBuilder &Builder) const override {
WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
DefineStd(Builder, "WIN64", Opts);
- Builder.defineMacro("__MSVCRT__");
- Builder.defineMacro("__MINGW32__");
Builder.defineMacro("__MINGW64__");
-
- // mingw32-gcc provides __declspec(a) as alias of __attribute__((a)).
- // In contrast, clang-cc1 provides __declspec(a) with -fms-extensions.
- if (Opts.MicrosoftExt)
- // Provide "as-is" __declspec.
- Builder.defineMacro("__declspec", "__declspec");
- else
- // Provide alias of __attribute__ like mingw32-gcc.
- Builder.defineMacro("__declspec(a)", "__attribute__((a))");
+ addMinGWDefines(Opts, Builder);
}
};
} // end anonymous namespace
@@ -3708,6 +3715,9 @@ class ARMTargetInfo : public TargetInfo {
static const Builtin::Info BuiltinInfo[];
static bool shouldUseInlineAtomic(const llvm::Triple &T) {
+ if (T.isOSWindows())
+ return true;
+
// On linux, binaries targeting old cpus call functions in libgcc to
// perform atomic operations. The implementation in libgcc then calls into
// the kernel which on armv6 and newer uses ldrex and strex. The net result
@@ -3774,19 +3784,30 @@ class ARMTargetInfo : public TargetInfo {
if (IsThumb) {
// Thumb1 add sp, #imm requires the immediate value be multiple of 4,
// so set preferred for small types to 32.
- if (T.isOSBinFormatMachO())
+ if (T.isOSBinFormatMachO()) {
DescriptionString = BigEndian ?
"E-m:o-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-"
"v128:64:128-a:0:32-n32-S64" :
"e-m:o-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-"
"v128:64:128-a:0:32-n32-S64";
- else
+ } else if (T.isOSWindows()) {
+ // FIXME: this is invalid for WindowsCE
+ assert(!BigEndian && "Windows on ARM does not support big endian");
+ DescriptionString = "e"
+ "-m:e"
+ "-p:32:32"
+ "-i1:8:32-i8:8:32-i16:16:32-i64:64"
+ "-v128:64:128"
+ "-a:0:32"
+ "-n32"
+ "-S64";
+ } else {
DescriptionString = BigEndian ?
"E-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-"
"v128:64:128-a:0:32-n32-S64" :
"e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:64-"
"v128:64:128-a:0:32-n32-S64";
-
+ }
} else {
if (T.isOSBinFormatMachO())
DescriptionString = BigEndian ?
@@ -4095,12 +4116,14 @@ public:
// FIXME: It's more complicated than this and we don't really support
// interworking.
- if (5 <= CPUArchVer && CPUArchVer <= 8)
+ // Windows on ARM does not "support" interworking
+ if (5 <= CPUArchVer && CPUArchVer <= 8 && !getTriple().isOSWindows())
Builder.defineMacro("__THUMB_INTERWORK__");
if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") {
// Embedded targets on Darwin follow AAPCS, but not EABI.
- if (!getTriple().isOSDarwin())
+ // Windows on ARM follows AAPCS VFP, but does not conform to EABI.
+ if (!getTriple().isOSDarwin() && !getTriple().isOSWindows())
Builder.defineMacro("__ARM_EABI__");
Builder.defineMacro("__ARM_PCS", "1");
@@ -4373,6 +4396,72 @@ public:
} // end anonymous namespace.
namespace {
+class WindowsARMTargetInfo : public WindowsTargetInfo<ARMleTargetInfo> {
+ const llvm::Triple Triple;
+public:
+ WindowsARMTargetInfo(const llvm::Triple &Triple)
+ : WindowsTargetInfo<ARMleTargetInfo>(Triple), Triple(Triple) {
+ TLSSupported = false;
+ WCharType = UnsignedShort;
+ SizeType = UnsignedInt;
+ UserLabelPrefix = "";
+ }
+ void getVisualStudioDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ WindowsTargetInfo<ARMleTargetInfo>::getVisualStudioDefines(Opts, Builder);
+
+ // FIXME: this is invalid for WindowsCE
+ Builder.defineMacro("_M_ARM_NT", "1");
+ Builder.defineMacro("_M_ARMT", "_M_ARM");
+ Builder.defineMacro("_M_THUMB", "_M_ARM");
+
+ assert((Triple.getArch() == llvm::Triple::arm ||
+ Triple.getArch() == llvm::Triple::thumb) &&
+ "invalid architecture for Windows ARM target info");
+ unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6;
+ Builder.defineMacro("_M_ARM", Triple.getArchName().substr(Offset));
+
+ // TODO map the complete set of values
+ // 31: VFPv3 40: VFPv4
+ Builder.defineMacro("_M_ARM_FP", "31");
+ }
+};
+
+// Windows ARM + Itanium C++ ABI Target
+class ItaniumWindowsARMleTargetInfo : public WindowsARMTargetInfo {
+public:
+ ItaniumWindowsARMleTargetInfo(const llvm::Triple &Triple)
+ : WindowsARMTargetInfo(Triple) {
+ TheCXXABI.set(TargetCXXABI::GenericARM);
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ WindowsARMTargetInfo::getTargetDefines(Opts, Builder);
+
+ if (Opts.MSVCCompat)
+ WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder);
+ }
+};
+
+// Windows ARM, MS (C++) ABI
+class MicrosoftARMleTargetInfo : public WindowsARMTargetInfo {
+public:
+ MicrosoftARMleTargetInfo(const llvm::Triple &Triple)
+ : WindowsARMTargetInfo(Triple) {
+ TheCXXABI.set(TargetCXXABI::Microsoft);
+ }
+
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ WindowsARMTargetInfo::getTargetDefines(Opts, Builder);
+ WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder);
+ }
+};
+}
+
+
+namespace {
class DarwinARMTargetInfo :
public DarwinTargetInfo<ARMleTargetInfo> {
protected:
@@ -4398,9 +4487,18 @@ public:
namespace {
class ARM64TargetInfo : public TargetInfo {
+ virtual void setDescriptionString() = 0;
static const TargetInfo::GCCRegAlias GCCRegAliases[];
static const char *const GCCRegNames[];
+ enum FPUModeEnum {
+ FPUMode,
+ NeonMode
+ };
+
+ unsigned FPU;
+ unsigned Crypto;
+
static const Builtin::Info BuiltinInfo[];
std::string ABI;
@@ -4408,7 +4506,6 @@ class ARM64TargetInfo : public TargetInfo {
public:
ARM64TargetInfo(const llvm::Triple &Triple)
: TargetInfo(Triple), ABI("aapcs") {
- BigEndian = false;
LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
IntMaxType = SignedLong;
UIntMaxType = UnsignedLong;
@@ -4422,11 +4519,6 @@ public:
LongDoubleWidth = LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::IEEEquad;
- if (Triple.isOSBinFormatMachO())
- DescriptionString = "e-m:o-i64:64-i128:128-n32:64-S128";
- else
- DescriptionString = "e-m:e-i64:64-i128:128-n32:64-S128";
-
// {} in inline assembly are neon specifiers, not assembly variant
// specifiers.
NoAsmVariants = true;
@@ -4446,7 +4538,8 @@ public:
virtual bool setCPU(const std::string &Name) {
bool CPUKnown = llvm::StringSwitch<bool>(Name)
- .Case("arm64-generic", true)
+ .Case("generic", true)
+ .Cases("cortex-a53", "cortex-a57", true)
.Case("cyclone", true)
.Default(false);
return CPUKnown;
@@ -4455,23 +4548,11 @@ public:
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
// Target identification.
- Builder.defineMacro("__arm64");
- Builder.defineMacro("__arm64__");
Builder.defineMacro("__aarch64__");
- Builder.defineMacro("__ARM64_ARCH_8__");
- Builder.defineMacro("__AARCH64_SIMD__");
- Builder.defineMacro("__ARM_NEON__");
// Target properties.
Builder.defineMacro("_LP64");
Builder.defineMacro("__LP64__");
- Builder.defineMacro("__LITTLE_ENDIAN__");
-
- // Subtarget options.
- Builder.defineMacro("__REGISTER_PREFIX__", "");
-
- Builder.defineMacro("__aarch64__");
- Builder.defineMacro("__AARCH64EL__");
// ACLE predefines. Many can only have one possible value on v8 AArch64.
Builder.defineMacro("__ARM_ACLE", "200");
@@ -4507,18 +4588,14 @@ public:
Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM",
Opts.ShortEnums ? "1" : "4");
- if (BigEndian)
- Builder.defineMacro("__ARM_BIG_ENDIAN");
-
- // FIXME: the target should support NEON as an optional extension, like
- // the OSS AArch64.
- Builder.defineMacro("__ARM_NEON");
- // 64-bit NEON supports half, single and double precision operations.
- Builder.defineMacro("__ARM_NEON_FP", "7");
+ if (FPU == NeonMode) {
+ Builder.defineMacro("__ARM_NEON");
+ // 64-bit NEON supports half, single and double precision operations.
+ Builder.defineMacro("__ARM_NEON_FP", "7");
+ }
- // FIXME: the target should support crypto as an optional extension, like
- // the OSS AArch64
- Builder.defineMacro("__ARM_FEATURE_CRYPTO");
+ if (Crypto)
+ Builder.defineMacro("__ARM_FEATURE_CRYPTO");
}
virtual void getTargetBuiltins(const Builtin::Info *&Records,
@@ -4528,10 +4605,25 @@ public:
}
virtual bool hasFeature(StringRef Feature) const {
- return llvm::StringSwitch<bool>(Feature)
- .Case("arm64", true)
- .Case("neon", true)
- .Default(false);
+ return Feature == "aarch64" ||
+ Feature == "arm64" ||
+ (Feature == "neon" && FPU == NeonMode);
+ }
+
+ bool handleTargetFeatures(std::vector<std::string> &Features,
+ DiagnosticsEngine &Diags) override {
+ FPU = FPUMode;
+ Crypto = 0;
+ for (unsigned i = 0, e = Features.size(); i != e; ++i) {
+ if (Features[i] == "+neon")
+ FPU = NeonMode;
+ if (Features[i] == "+crypto")
+ Crypto = 1;
+ }
+
+ setDescriptionString();
+
+ return true;
}
virtual bool isCLZForZeroUndef() const { return false; }
@@ -4553,46 +4645,37 @@ public:
case 'w': // Floating point and SIMD registers (V0-V31)
Info.setAllowsRegister();
return true;
+ case 'I': // Constant that can be used with an ADD instruction
+ case 'J': // Constant that can be used with a SUB instruction
+ case 'K': // Constant that can be used with a 32-bit logical instruction
+ case 'L': // Constant that can be used with a 64-bit logical instruction
+ case 'M': // Constant that can be used as a 32-bit MOV immediate
+ case 'N': // Constant that can be used as a 64-bit MOV immediate
+ case 'Y': // Floating point constant zero
+ case 'Z': // Integer constant zero
+ return true;
+ case 'Q': // A memory reference with base register and no offset
+ Info.setAllowsMemory();
+ return true;
+ case 'S': // A symbolic address
+ Info.setAllowsRegister();
+ return true;
+ case 'U':
+ // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes, whatever they may be
+ // Utf: A memory address suitable for ldp/stp in TF mode, whatever it may be
+ // Usa: An absolute symbolic address
+ // Ush: The high part (bits 32:12) of a pc-relative symbolic address
+ llvm_unreachable("FIXME: Unimplemented support for bizarre constraints");
case 'z': // Zero register, wzr or xzr
Info.setAllowsRegister();
return true;
case 'x': // Floating point and SIMD registers (V0-V15)
Info.setAllowsRegister();
return true;
- case 'Q': // A memory address that is a single base register.
- Info.setAllowsMemory();
- return true;
}
return false;
}
- virtual bool validateConstraintModifier(StringRef Constraint,
- const char Modifier,
- unsigned Size) const {
- // Strip off constraint modifiers.
- while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&')
- Constraint = Constraint.substr(1);
-
- switch (Constraint[0]) {
- default:
- return true;
- case 'z':
- case 'r': {
- switch (Modifier) {
- case 'x':
- case 'w':
- // For now assume that the person knows what they're
- // doing with the modifier.
- return true;
- default:
- // By default an 'r' constraint will be in the 'x'
- // registers.
- return (Size == 64);
- }
- }
- }
- }
-
virtual const char *getClobbers() const { return ""; }
int getEHDataRegisterNumber(unsigned RegNo) const {
@@ -4661,13 +4744,65 @@ const Builtin::Info ARM64TargetInfo::BuiltinInfo[] = {
{ #ID, TYPE, ATTRS, 0, ALL_LANGUAGES },
#include "clang/Basic/BuiltinsARM64.def"
};
+
+class ARM64leTargetInfo : public ARM64TargetInfo {
+ void setDescriptionString() override {
+ if (getTriple().isOSBinFormatMachO())
+ DescriptionString = "e-m:o-i64:64-i128:128-n32:64-S128";
+ else
+ DescriptionString = "e-m:e-i64:64-i128:128-n32:64-S128";
+ }
+
+public:
+ ARM64leTargetInfo(const llvm::Triple &Triple)
+ : ARM64TargetInfo(Triple) {
+ BigEndian = false;
+ }
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ Builder.defineMacro("__AARCH64EL__");
+ ARM64TargetInfo::getTargetDefines(Opts, Builder);
+ }
+};
+
+class ARM64beTargetInfo : public ARM64TargetInfo {
+ void setDescriptionString() override {
+ assert(!getTriple().isOSBinFormatMachO());
+ DescriptionString = "E-m:e-i64:64-i128:128-n32:64-S128";
+ }
+
+public:
+ ARM64beTargetInfo(const llvm::Triple &Triple)
+ : ARM64TargetInfo(Triple) { }
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ Builder.defineMacro("__AARCH64EB__");
+ Builder.defineMacro("__AARCH_BIG_ENDIAN");
+ Builder.defineMacro("__ARM_BIG_ENDIAN");
+ ARM64TargetInfo::getTargetDefines(Opts, Builder);
+ }
+};
} // end anonymous namespace.
namespace {
-class DarwinARM64TargetInfo : public DarwinTargetInfo<ARM64TargetInfo> {
+class DarwinARM64TargetInfo : public DarwinTargetInfo<ARM64leTargetInfo> {
+protected:
+ void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ MacroBuilder &Builder) const override {
+ Builder.defineMacro("__AARCH64_SIMD__");
+ Builder.defineMacro("__ARM64_ARCH_8__");
+ Builder.defineMacro("__ARM_NEON__");
+ Builder.defineMacro("__LITTLE_ENDIAN__");
+ Builder.defineMacro("__REGISTER_PREFIX__", "");
+ Builder.defineMacro("__arm64", "1");
+ Builder.defineMacro("__arm64__", "1");
+
+ getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion);
+ }
+
public:
DarwinARM64TargetInfo(const llvm::Triple &Triple)
- : DarwinTargetInfo<ARM64TargetInfo>(Triple) {
+ : DarwinTargetInfo<ARM64leTargetInfo>(Triple) {
Int64Type = SignedLongLong;
WCharType = SignedInt;
UseSignedCharForObjCBool = false;
@@ -5040,108 +5175,108 @@ public:
} // end anonymous namespace.
namespace {
- class SystemZTargetInfo : public TargetInfo {
- static const char *const GCCRegNames[];
+class SystemZTargetInfo : public TargetInfo {
+ static const char *const GCCRegNames[];
- public:
- SystemZTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
- TLSSupported = true;
- IntWidth = IntAlign = 32;
- LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64;
- PointerWidth = PointerAlign = 64;
- LongDoubleWidth = 128;
- LongDoubleAlign = 64;
- LongDoubleFormat = &llvm::APFloat::IEEEquad;
- MinGlobalAlign = 16;
- DescriptionString = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64";
- MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
- }
- void getTargetDefines(const LangOptions &Opts,
- MacroBuilder &Builder) const override {
- Builder.defineMacro("__s390__");
- Builder.defineMacro("__s390x__");
- Builder.defineMacro("__zarch__");
- Builder.defineMacro("__LONG_DOUBLE_128__");
- }
- void getTargetBuiltins(const Builtin::Info *&Records,
- unsigned &NumRecords) const override {
- // FIXME: Implement.
- Records = 0;
- NumRecords = 0;
- }
+public:
+ SystemZTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {
+ TLSSupported = true;
+ IntWidth = IntAlign = 32;
+ LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64;
+ PointerWidth = PointerAlign = 64;
+ LongDoubleWidth = 128;
+ LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEquad;
+ MinGlobalAlign = 16;
+ DescriptionString = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64";
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+ }
+ void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const override {
+ Builder.defineMacro("__s390__");
+ Builder.defineMacro("__s390x__");
+ Builder.defineMacro("__zarch__");
+ Builder.defineMacro("__LONG_DOUBLE_128__");
+ }
+ void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const override {
+ // FIXME: Implement.
+ Records = 0;
+ NumRecords = 0;
+ }
- void getGCCRegNames(const char *const *&Names,
- unsigned &NumNames) const override;
- void getGCCRegAliases(const GCCRegAlias *&Aliases,
- unsigned &NumAliases) const override {
- // No aliases.
- Aliases = 0;
- NumAliases = 0;
- }
- bool validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &info) const override;
- const char *getClobbers() const override {
- // FIXME: Is this really right?
- return "";
- }
- BuiltinVaListKind getBuiltinVaListKind() const override {
- return TargetInfo::SystemZBuiltinVaList;
- }
- bool setCPU(const std::string &Name) override {
- bool CPUKnown = llvm::StringSwitch<bool>(Name)
- .Case("z10", true)
- .Case("z196", true)
- .Case("zEC12", true)
- .Default(false);
+ void getGCCRegNames(const char *const *&Names,
+ unsigned &NumNames) const override;
+ void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const override {
+ // No aliases.
+ Aliases = 0;
+ NumAliases = 0;
+ }
+ bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const override;
+ const char *getClobbers() const override {
+ // FIXME: Is this really right?
+ return "";
+ }
+ BuiltinVaListKind getBuiltinVaListKind() const override {
+ return TargetInfo::SystemZBuiltinVaList;
+ }
+ bool setCPU(const std::string &Name) override {
+ bool CPUKnown = llvm::StringSwitch<bool>(Name)
+ .Case("z10", true)
+ .Case("z196", true)
+ .Case("zEC12", true)
+ .Default(false);
- // No need to store the CPU yet. There aren't any CPU-specific
- // macros to define.
- return CPUKnown;
- }
- };
+ // No need to store the CPU yet. There aren't any CPU-specific
+ // macros to define.
+ return CPUKnown;
+ }
+};
- const char *const SystemZTargetInfo::GCCRegNames[] = {
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "f0", "f2", "f4", "f6", "f1", "f3", "f5", "f7",
- "f8", "f10", "f12", "f14", "f9", "f11", "f13", "f15"
- };
+const char *const SystemZTargetInfo::GCCRegNames[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "f0", "f2", "f4", "f6", "f1", "f3", "f5", "f7",
+ "f8", "f10", "f12", "f14", "f9", "f11", "f13", "f15"
+};
- void SystemZTargetInfo::getGCCRegNames(const char *const *&Names,
- unsigned &NumNames) const {
- Names = GCCRegNames;
- NumNames = llvm::array_lengthof(GCCRegNames);
- }
+void SystemZTargetInfo::getGCCRegNames(const char *const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+}
- bool SystemZTargetInfo::
- validateAsmConstraint(const char *&Name,
- TargetInfo::ConstraintInfo &Info) const {
- switch (*Name) {
- default:
- return false;
+bool SystemZTargetInfo::
+validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const {
+ switch (*Name) {
+ default:
+ return false;
- case 'a': // Address register
- case 'd': // Data register (equivalent to 'r')
- case 'f': // Floating-point register
- Info.setAllowsRegister();
- return true;
+ case 'a': // Address register
+ case 'd': // Data register (equivalent to 'r')
+ case 'f': // Floating-point register
+ Info.setAllowsRegister();
+ return true;
- case 'I': // Unsigned 8-bit constant
- case 'J': // Unsigned 12-bit constant
- case 'K': // Signed 16-bit constant
- case 'L': // Signed 20-bit displacement (on all targets we support)
- case 'M': // 0x7fffffff
- return true;
+ case 'I': // Unsigned 8-bit constant
+ case 'J': // Unsigned 12-bit constant
+ case 'K': // Signed 16-bit constant
+ case 'L': // Signed 20-bit displacement (on all targets we support)
+ case 'M': // 0x7fffffff
+ return true;
- case 'Q': // Memory with base and unsigned 12-bit displacement
- case 'R': // Likewise, plus an index
- case 'S': // Memory with base and signed 20-bit displacement
- case 'T': // Likewise, plus an index
- Info.setAllowsMemory();
- return true;
- }
+ case 'Q': // Memory with base and unsigned 12-bit displacement
+ case 'R': // Likewise, plus an index
+ case 'S': // Memory with base and signed 20-bit displacement
+ case 'T': // Likewise, plus an index
+ Info.setAllowsMemory();
+ return true;
}
}
+}
namespace {
class MSP430TargetInfo : public TargetInfo {
@@ -5644,32 +5779,44 @@ class Mips64TargetInfoBase : public MipsTargetInfoBase {
public:
Mips64TargetInfoBase(const llvm::Triple &Triple)
: MipsTargetInfoBase(Triple, "n64", "mips64r2") {
- LongWidth = LongAlign = 64;
- PointerWidth = PointerAlign = 64;
LongDoubleWidth = LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::IEEEquad;
if (getTriple().getOS() == llvm::Triple::FreeBSD) {
LongDoubleWidth = LongDoubleAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
}
+ setN64ABITypes();
SuitableAlign = 128;
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
}
+
+ void setN64ABITypes() {
+ LongWidth = LongAlign = 64;
+ PointerWidth = PointerAlign = 64;
+ SizeType = UnsignedLong;
+ PtrDiffType = SignedLong;
+ }
+
+ void setN32ABITypes() {
+ LongWidth = LongAlign = 32;
+ PointerWidth = PointerAlign = 32;
+ SizeType = UnsignedInt;
+ PtrDiffType = SignedInt;
+ }
+
bool setABI(const std::string &Name) override {
if (Name == "n32") {
- LongWidth = LongAlign = 32;
- PointerWidth = PointerAlign = 32;
+ setN32ABITypes();
ABI = Name;
return true;
- } else if (Name == "n64") {
- ABI = Name;
- return true;
- } else if (Name == "64") {
+ } else if (Name == "n64" || Name == "64") {
+ setN64ABITypes();
ABI = "n64";
return true;
- } else
- return false;
+ }
+ return false;
}
+
void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const override {
MipsTargetInfoBase::getTargetDefines(Opts, Builder);
@@ -5729,6 +5876,8 @@ public:
Aliases = GCCRegAliases;
NumAliases = llvm::array_lengthof(GCCRegAliases);
}
+
+ bool hasInt128Type() const override { return true; }
};
class Mips64EBTargetInfo : public Mips64TargetInfoBase {
@@ -6009,9 +6158,21 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
switch (os) {
case llvm::Triple::Linux:
- return new LinuxTargetInfo<ARM64TargetInfo>(Triple);
+ return new LinuxTargetInfo<ARM64leTargetInfo>(Triple);
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<ARM64leTargetInfo>(Triple);
default:
- return new ARM64TargetInfo(Triple);
+ return new ARM64leTargetInfo(Triple);
+ }
+
+ case llvm::Triple::arm64_be:
+ switch (os) {
+ case llvm::Triple::Linux:
+ return new LinuxTargetInfo<ARM64beTargetInfo>(Triple);
+ case llvm::Triple::NetBSD:
+ return new NetBSDTargetInfo<ARM64beTargetInfo>(Triple);
+ default:
+ return new ARM64beTargetInfo(Triple);
}
case llvm::Triple::xcore:
@@ -6060,6 +6221,15 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
return new RTEMSTargetInfo<ARMleTargetInfo>(Triple);
case llvm::Triple::NaCl:
return new NaClTargetInfo<ARMleTargetInfo>(Triple);
+ case llvm::Triple::Win32:
+ switch (Triple.getEnvironment()) {
+ default:
+ return new ARMleTargetInfo(Triple);
+ case llvm::Triple::Itanium:
+ return new ItaniumWindowsARMleTargetInfo(Triple);
+ case llvm::Triple::MSVC:
+ return new MicrosoftARMleTargetInfo(Triple);
+ }
default:
return new ARMleTargetInfo(Triple);
}
@@ -6292,7 +6462,7 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
case llvm::Triple::GNU:
return new MinGWX86_32TargetInfo(Triple);
case llvm::Triple::MSVC:
- return new VisualStudioWindowsX86_32TargetInfo(Triple);
+ return new MicrosoftX86_32TargetInfo(Triple);
}
}
case llvm::Triple::Haiku:
@@ -6335,7 +6505,7 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) {
case llvm::Triple::GNU:
return new MinGWX86_64TargetInfo(Triple);
case llvm::Triple::MSVC:
- return new VisualStudioWindowsX86_64TargetInfo(Triple);
+ return new MicrosoftX86_64TargetInfo(Triple);
}
}
case llvm::Triple::NaCl:
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 17f5f4d633..2c388ef58e 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -247,6 +247,7 @@ void EmitAssemblyHelper::CreatePasses() {
PMBuilder.SLPVectorize = CodeGenOpts.VectorizeSLP;
PMBuilder.LoopVectorize = CodeGenOpts.VectorizeLoop;
+ PMBuilder.DisableTailCalls = CodeGenOpts.DisableTailCalls;
PMBuilder.DisableUnitAtATime = !CodeGenOpts.UnitAtATime;
PMBuilder.DisableUnrollLoops = !CodeGenOpts.UnrollLoops;
PMBuilder.RerollLoops = CodeGenOpts.RerollLoops;
@@ -334,6 +335,8 @@ void EmitAssemblyHelper::CreatePasses() {
// Set up the per-module pass manager.
PassManager *MPM = getPerModulePasses();
+ if (CodeGenOpts.VerifyModule)
+ MPM->add(createDebugInfoVerifierPass());
if (!CodeGenOpts.DisableGCov &&
(CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes)) {
@@ -491,7 +494,6 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
Options.DisableTailCalls = CodeGenOpts.DisableTailCalls;
Options.TrapFuncName = CodeGenOpts.TrapFuncName;
Options.PositionIndependentExecutable = LangOpts.PIELevel != 0;
- Options.EnableSegmentedStacks = CodeGenOpts.EnableSegmentedStacks;
TargetMachine *TM = TheTarget->createTargetMachine(Triple, TargetOpts.CPU,
FeaturesStr, Options,
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 15b08d476c..18cfe49bc3 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -1135,6 +1135,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
// Begin generating the function.
StartFunction(blockDecl, fnType->getReturnType(), fn, fnInfo, args,
+ blockDecl->getLocation(),
blockInfo.getBlockExpr()->getBody()->getLocStart());
// Okay. Undo some of what StartFunction did.
@@ -1306,7 +1307,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
false);
// Create a scope with an artificial location for the body of this function.
ArtificialLocation AL(*this, Builder);
- StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
+ StartFunction(FD, C.VoidTy, Fn, FI, args);
AL.Emit();
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
@@ -1476,7 +1477,7 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
false, false);
// Create a scope with an artificial location for the body of this function.
ArtificialLocation AL(*this, Builder);
- StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
+ StartFunction(FD, C.VoidTy, Fn, FI, args);
AL.Emit();
llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
@@ -1765,7 +1766,7 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
SC_Static,
false, false);
- CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
+ CGF.StartFunction(FD, R, Fn, FI, args);
if (byrefInfo.needsCopy()) {
llvm::Type *byrefPtrType = byrefType.getPointerTo(0);
@@ -1834,7 +1835,7 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
SourceLocation(), II, R, 0,
SC_Static,
false, false);
- CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation());
+ CGF.StartFunction(FD, R, Fn, FI, args);
if (byrefInfo.needsDispose()) {
llvm::Value *V = CGF.GetAddrOfLocalVar(&src);
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 5a86bdd44c..d8e363387b 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -4326,6 +4326,11 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
+ if (BuiltinID == ARM::BI__yield) {
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_hint);
+ return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, 1));
+ }
+
if (BuiltinID == ARM::BI__clear_cache) {
assert(E->getNumArgs() == 2 && "__clear_cache takes 2 arguments");
const FunctionDecl *FD = E->getDirectCallee();
@@ -4423,8 +4428,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
}
if (BuiltinID == ARM::BI__builtin_arm_sevl) {
- Function *F = CGM.getIntrinsic(Intrinsic::arm_sevl);
- return Builder.CreateCall(F);
+ Function *F = CGM.getIntrinsic(Intrinsic::arm_hint);
+ return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, 5));
}
// CRC32
@@ -4823,7 +4828,6 @@ static Value *EmitARM64TblBuiltinExpr(CodeGenFunction &CGF, unsigned BuiltinID,
unsigned int Int = 0;
const char *s = NULL;
- unsigned TblPos;
switch (BuiltinID) {
default:
return 0;
@@ -4839,7 +4843,6 @@ static Value *EmitARM64TblBuiltinExpr(CodeGenFunction &CGF, unsigned BuiltinID,
case NEON::BI__builtin_neon_vtbl4_v:
case NEON::BI__builtin_neon_vqtbl4_v:
case NEON::BI__builtin_neon_vqtbl4q_v:
- TblPos = 0;
break;
case NEON::BI__builtin_neon_vtbx1_v:
case NEON::BI__builtin_neon_vqtbx1_v:
@@ -4853,7 +4856,6 @@ static Value *EmitARM64TblBuiltinExpr(CodeGenFunction &CGF, unsigned BuiltinID,
case NEON::BI__builtin_neon_vtbx4_v:
case NEON::BI__builtin_neon_vqtbx4_v:
case NEON::BI__builtin_neon_vqtbx4q_v:
- TblPos = 1;
break;
}
@@ -4872,7 +4874,6 @@ static Value *EmitARM64TblBuiltinExpr(CodeGenFunction &CGF, unsigned BuiltinID,
if (!Ty)
return 0;
- Arg = E->getArg(TblPos);
unsigned nElts = VTy->getNumElements();
CodeGen::CGBuilderTy &Builder = CGF.Builder;
@@ -5526,10 +5527,8 @@ Value *CodeGenFunction::EmitARM64BuiltinExpr(unsigned BuiltinID,
case NEON::BI__builtin_neon_vqshlud_n_s64: {
Ops.push_back(EmitScalarExpr(E->getArg(1)));
Ops[1] = Builder.CreateZExt(Ops[1], Int64Ty);
- llvm::Type *VTy = llvm::VectorType::get(Int64Ty, 1);
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm64_neon_sqshlu, VTy),
- Ops, "vqshlu_n");
- return Builder.CreateBitCast(Ops[0], Int64Ty);
+ return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm64_neon_sqshlu, Int64Ty),
+ Ops, "vqshlu_n");
}
case NEON::BI__builtin_neon_vqshld_n_u64:
case NEON::BI__builtin_neon_vqshld_n_s64: {
@@ -5538,9 +5537,7 @@ Value *CodeGenFunction::EmitARM64BuiltinExpr(unsigned BuiltinID,
: Intrinsic::arm64_neon_sqshl;
Ops.push_back(EmitScalarExpr(E->getArg(1)));
Ops[1] = Builder.CreateZExt(Ops[1], Int64Ty);
- llvm::Type *VTy = llvm::VectorType::get(Int64Ty, 1);
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, VTy), Ops, "vqshl_n");
- return Builder.CreateBitCast(Ops[0], Int64Ty);
+ return EmitNeonCall(CGM.getIntrinsic(Int, Int64Ty), Ops, "vqshl_n");
}
case NEON::BI__builtin_neon_vrshrd_n_u64:
case NEON::BI__builtin_neon_vrshrd_n_s64: {
@@ -5548,9 +5545,9 @@ Value *CodeGenFunction::EmitARM64BuiltinExpr(unsigned BuiltinID,
? Intrinsic::arm64_neon_urshl
: Intrinsic::arm64_neon_srshl;
Ops.push_back(EmitScalarExpr(E->getArg(1)));
- llvm::Type *VTy = llvm::VectorType::get(Int64Ty, 1);
- Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, VTy), Ops, "vrshr_n", 1, true);
- return Builder.CreateBitCast(Ops[0], Int64Ty);
+ int SV = cast<ConstantInt>(Ops[1])->getSExtValue();
+ Ops[1] = ConstantInt::get(Int64Ty, -SV);
+ return EmitNeonCall(CGM.getIntrinsic(Int, Int64Ty), Ops, "vrshr_n");
}
case NEON::BI__builtin_neon_vrsrad_n_u64:
case NEON::BI__builtin_neon_vrsrad_n_s64: {
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index e26d6b2d0e..e82b6defa6 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -1090,6 +1090,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
FuncAttrs.addAttribute(llvm::Attribute::NoRedZone);
if (CodeGenOpts.NoImplicitFloat)
FuncAttrs.addAttribute(llvm::Attribute::NoImplicitFloat);
+ if (CodeGenOpts.EnableSegmentedStacks)
+ FuncAttrs.addAttribute("split-stack");
if (AttrOnCallSite) {
// Attributes that should go on the call site only.
@@ -2546,8 +2548,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// FIXME: Do this earlier rather than hacking it in here!
llvm::Value *ArgMemory = 0;
if (llvm::StructType *ArgStruct = CallInfo.getArgStruct()) {
- llvm::AllocaInst *AI = new llvm::AllocaInst(
- ArgStruct, "argmem", CallArgs.getStackBase()->getNextNode());
+ llvm::Instruction *IP = CallArgs.getStackBase();
+ llvm::AllocaInst *AI;
+ if (IP) {
+ IP = IP->getNextNode();
+ AI = new llvm::AllocaInst(ArgStruct, "argmem", IP);
+ } else {
+ AI = Builder.CreateAlloca(ArgStruct, nullptr, "argmem");
+ }
AI->setUsedWithInAlloca(true);
assert(AI->isUsedWithInAlloca() && !AI->isStaticAlloca());
ArgMemory = AI;
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 0e94b51817..86e76daf0f 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -719,6 +719,32 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
return BlockLiteralGeneric;
}
+llvm::DIType CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, llvm::DIFile Unit) {
+ assert(Ty->isTypeAlias());
+ llvm::DIType Src = getOrCreateType(Ty->getAliasedType(), Unit);
+ assert(Src);
+
+ SmallString<128> NS;
+ llvm::raw_svector_ostream OS(NS);
+ Ty->getTemplateName().print(OS, CGM.getContext().getPrintingPolicy(), /*qualified*/ false);
+
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Ty->getArgs(), Ty->getNumArgs(),
+ CGM.getContext().getPrintingPolicy());
+
+ TypeAliasDecl *AliasDecl =
+ cast<TypeAliasTemplateDecl>(Ty->getTemplateName().getAsTemplateDecl())
+ ->getTemplatedDecl();
+
+ SourceLocation Loc = AliasDecl->getLocation();
+ llvm::DIFile File = getOrCreateFile(Loc);
+ unsigned Line = getLineNumber(Loc);
+
+ llvm::DIDescriptor Ctxt = getContextDescriptor(cast<Decl>(AliasDecl->getDeclContext()));
+
+ return DBuilder.createTypedef(Src, internString(OS.str()), File, Line, Ctxt);
+}
+
llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile Unit) {
// Typedefs are derived from some other type. If we have a typedef of a
// typedef, make sure to emit the whole chain.
@@ -1330,14 +1356,11 @@ CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit) {
llvm::DIArray CGDebugInfo::
CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TSpecial,
llvm::DIFile Unit) {
- llvm::PointerUnion<ClassTemplateDecl *,
- ClassTemplatePartialSpecializationDecl *>
- PU = TSpecial->getSpecializedTemplateOrPartial();
-
- TemplateParameterList *TPList = PU.is<ClassTemplateDecl *>() ?
- PU.get<ClassTemplateDecl *>()->getTemplateParameters() :
- PU.get<ClassTemplatePartialSpecializationDecl *>()->getTemplateParameters();
- const TemplateArgumentList &TAList = TSpecial->getTemplateInstantiationArgs();
+ // Always get the full list of parameters, not just the ones from
+ // the specialization.
+ TemplateParameterList *TPList =
+ TSpecial->getSpecializedTemplate()->getTemplateParameters();
+ const TemplateArgumentList &TAList = TSpecial->getTemplateArgs();
return CollectTemplateParams(TPList, TAList.asArray(), Unit);
}
@@ -1932,9 +1955,12 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
switch (T->getTypeClass()) {
default:
return C.getQualifiedType(T.getTypePtr(), Quals);
- case Type::TemplateSpecialization:
- T = cast<TemplateSpecializationType>(T)->desugar();
- break;
+ case Type::TemplateSpecialization: {
+ const auto *Spec = cast<TemplateSpecializationType>(T);
+ if (Spec->isTypeAlias())
+ return C.getQualifiedType(T.getTypePtr(), Quals);
+ T = Spec->desugar();
+ break; }
case Type::TypeOfExpr:
T = cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType();
break;
@@ -2191,8 +2217,10 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
case Type::Atomic:
return CreateType(cast<AtomicType>(Ty), Unit);
- case Type::Attributed:
case Type::TemplateSpecialization:
+ return CreateType(cast<TemplateSpecializationType>(Ty), Unit);
+
+ case Type::Attributed:
case Type::Elaborated:
case Type::Paren:
case Type::SubstTemplateTypeParm:
@@ -2473,7 +2501,10 @@ llvm::DICompositeType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
}
/// EmitFunctionStart - Constructs the debug code for entering a function.
-void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
+void CGDebugInfo::EmitFunctionStart(GlobalDecl GD,
+ SourceLocation Loc,
+ SourceLocation ScopeLoc,
+ QualType FnType,
llvm::Function *Fn,
CGBuilderTy &Builder) {
@@ -2483,24 +2514,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
FnBeginRegionCount.push_back(LexicalBlockStack.size());
const Decl *D = GD.getDecl();
-
- // Use the location of the start of the function to determine where
- // the function definition is located. By default use the location
- // of the declaration as the location for the subprogram. A function
- // may lack a declaration in the source code if it is created by code
- // gen. (examples: _GLOBAL__I_a, __cxx_global_array_dtor, thunk).
bool HasDecl = (D != 0);
- SourceLocation Loc;
- if (HasDecl) {
- Loc = D->getLocation();
-
- // If this is a function specialization then use the pattern body
- // as the location for the function.
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- if (const FunctionDecl *SpecDecl = FD->getTemplateInstantiationPattern())
- if (SpecDecl->hasBody(SpecDecl))
- Loc = SpecDecl->getLocation();
- }
unsigned Flags = 0;
llvm::DIFile Unit = getOrCreateFile(Loc);
@@ -2560,9 +2574,14 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
if (!Name.empty() && Name[0] == '\01')
Name = Name.substr(1);
- unsigned LineNo = getLineNumber(Loc);
- if (!HasDecl || D->isImplicit())
+ if (!HasDecl || D->isImplicit()) {
Flags |= llvm::DIDescriptor::FlagArtificial;
+ // Artificial functions without a location should not silently reuse CurLoc.
+ if (Loc.isInvalid())
+ CurLoc = SourceLocation();
+ }
+ unsigned LineNo = getLineNumber(Loc);
+ unsigned ScopeLine = getLineNumber(ScopeLoc);
// FIXME: The function declaration we're constructing here is mostly reusing
// declarations from CXXMethodDecl and not constructing new ones for arbitrary
@@ -2573,7 +2592,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
DBuilder.createFunction(FDContext, Name, LinkageName, Unit, LineNo,
getOrCreateFunctionType(D, FnType, Unit),
Fn->hasInternalLinkage(), true /*definition*/,
- getLineNumber(CurLoc), Flags,
+ ScopeLine, Flags,
CGM.getLangOpts().Optimize, Fn, TParamsArray,
getFunctionDeclaration(D));
if (HasDecl)
@@ -2888,7 +2907,6 @@ llvm::DIType CGDebugInfo::CreateSelfType(const QualType &QualTy,
llvm::DIType Ty) {
llvm::DIType CachedTy = getTypeOrNull(QualTy);
if (CachedTy) Ty = CachedTy;
- else DEBUG(llvm::dbgs() << "No cached type for self.");
return DBuilder.createObjectPointerType(Ty);
}
@@ -3149,6 +3167,37 @@ CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) {
return T;
}
+/// Recursively collect all of the member fields of a global anonymous decl and
+/// create static variables for them. The first time this is called it needs
+/// to be on a union and then from there we can have additional unnamed fields.
+llvm::DIGlobalVariable
+CGDebugInfo::CollectAnonRecordDecls(const RecordDecl *RD, llvm::DIFile Unit,
+ unsigned LineNo, StringRef LinkageName,
+ llvm::GlobalVariable *Var,
+ llvm::DIDescriptor DContext) {
+ llvm::DIGlobalVariable GV;
+
+ for (const auto *Field : RD->fields()) {
+ llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
+ StringRef FieldName = Field->getName();
+
+ // Ignore unnamed fields, but recurse into anonymous records.
+ if (FieldName.empty()) {
+ const RecordType *RT = dyn_cast<RecordType>(Field->getType());
+ if (RT)
+ GV = CollectAnonRecordDecls(RT->getDecl(), Unit, LineNo, LinkageName,
+ Var, DContext);
+ continue;
+ }
+ // Use VarDecl's Tag, Scope and Line number.
+ GV = DBuilder.createStaticVariable(DContext, FieldName, LinkageName, Unit,
+ LineNo, FieldTy,
+ Var->hasInternalLinkage(), Var,
+ llvm::DIDerivedType());
+ }
+ return GV;
+}
+
/// EmitGlobalVariable - Emit information about a global variable.
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
const VarDecl *D) {
@@ -3169,19 +3218,35 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
T = CGM.getContext().getConstantArrayType(ET, ConstVal,
ArrayType::Normal, 0);
}
+
StringRef DeclName = D->getName();
StringRef LinkageName;
- if (D->getDeclContext() && !isa<FunctionDecl>(D->getDeclContext())
- && !isa<ObjCMethodDecl>(D->getDeclContext()))
+ if (D->getDeclContext() && !isa<FunctionDecl>(D->getDeclContext()) &&
+ !isa<ObjCMethodDecl>(D->getDeclContext()))
LinkageName = Var->getName();
if (LinkageName == DeclName)
LinkageName = StringRef();
+
llvm::DIDescriptor DContext =
getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()));
- llvm::DIGlobalVariable GV = DBuilder.createStaticVariable(
- DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit),
- Var->hasInternalLinkage(), Var,
- getOrCreateStaticDataMemberDeclarationOrNull(D));
+
+ // Attempt to store one global variable for the declaration - even if we
+ // emit a lot of fields.
+ llvm::DIGlobalVariable GV;
+
+ // If this is an anonymous union then we'll want to emit a global
+ // variable for each member of the anonymous union so that it's possible
+ // to find the name of any field in the union.
+ if (T->isUnionType() && DeclName.empty()) {
+ const RecordDecl *RD = cast<RecordType>(T)->getDecl();
+ assert(RD->isAnonymousStructOrUnion() && "unnamed non-anonymous struct or union?");
+ GV = CollectAnonRecordDecls(RD, Unit, LineNo, LinkageName, Var, DContext);
+ } else {
+ GV = DBuilder.createStaticVariable(
+ DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit),
+ Var->hasInternalLinkage(), Var,
+ getOrCreateStaticDataMemberDeclarationOrNull(D));
+ }
DeclCache.insert(std::make_pair(D->getCanonicalDecl(), llvm::WeakVH(GV)));
}
@@ -3227,10 +3292,20 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
// Do not use DIGlobalVariable for enums.
if (Ty.getTag() == llvm::dwarf::DW_TAG_enumeration_type)
return;
+ // Do not emit separate definitions for function local const/statics.
+ if (isa<FunctionDecl>(VD->getDeclContext()))
+ return;
+ VD = cast<ValueDecl>(VD->getCanonicalDecl());
+ auto pair = DeclCache.insert(std::make_pair(VD, llvm::WeakVH()));
+ if (!pair.second)
+ return;
+ llvm::DIDescriptor DContext =
+ getContextDescriptor(dyn_cast<Decl>(VD->getDeclContext()));
llvm::DIGlobalVariable GV = DBuilder.createStaticVariable(
- Unit, Name, Name, Unit, getLineNumber(VD->getLocation()), Ty, true, Init,
+ DContext, Name, StringRef(), Unit, getLineNumber(VD->getLocation()), Ty,
+ true, Init,
getOrCreateStaticDataMemberDeclarationOrNull(cast<VarDecl>(VD)));
- DeclCache.insert(std::make_pair(VD->getCanonicalDecl(), llvm::WeakVH(GV)));
+ pair.first->second = llvm::WeakVH(GV);
}
llvm::DIScope CGDebugInfo::getCurrentContextDescriptor(const Decl *D) {
@@ -3274,12 +3349,12 @@ CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) {
if (const NamespaceAliasDecl *Underlying =
dyn_cast<NamespaceAliasDecl>(NA.getAliasedNamespace()))
// This could cache & dedup here rather than relying on metadata deduping.
- R = DBuilder.createImportedModule(
+ R = DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(NA.getDeclContext())),
EmitNamespaceAlias(*Underlying), getLineNumber(NA.getLocation()),
NA.getName());
else
- R = DBuilder.createImportedModule(
+ R = DBuilder.createImportedDeclaration(
getCurrentContextDescriptor(cast<Decl>(NA.getDeclContext())),
getOrCreateNameSpace(cast<NamespaceDecl>(NA.getAliasedNamespace())),
getLineNumber(NA.getLocation()), NA.getName());
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 52784daf63..2fc35d5b87 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -109,6 +109,7 @@ class CGDebugInfo {
llvm::DIType CreateType(const ComplexType *Ty);
llvm::DIType CreateQualifiedType(QualType Ty, llvm::DIFile Fg);
llvm::DIType CreateType(const TypedefType *Ty, llvm::DIFile Fg);
+ llvm::DIType CreateType(const TemplateSpecializationType *Ty, llvm::DIFile Fg);
llvm::DIType CreateType(const ObjCObjectPointerType *Ty,
llvm::DIFile F);
llvm::DIType CreateType(const PointerType *Ty, llvm::DIFile F);
@@ -219,8 +220,12 @@ public:
/// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate
/// start of a new function.
- void EmitFunctionStart(GlobalDecl GD, QualType FnType,
- llvm::Function *Fn, CGBuilderTy &Builder);
+ /// \param Loc The location of the function header.
+ /// \param ScopeLoc The location of the function body.
+ void EmitFunctionStart(GlobalDecl GD,
+ SourceLocation Loc, SourceLocation ScopeLoc,
+ QualType FnType, llvm::Function *Fn,
+ CGBuilderTy &Builder);
/// EmitFunctionEnd - Constructs the debug code for exiting a function.
void EmitFunctionEnd(CGBuilderTy &Builder);
@@ -357,6 +362,13 @@ private:
llvm::DIDerivedType
getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D);
+ /// Return a global variable that represents one of the collection of
+ /// global variables created for an anonmyous union.
+ llvm::DIGlobalVariable
+ CollectAnonRecordDecls(const RecordDecl *RD, llvm::DIFile Unit, unsigned LineNo,
+ StringRef LinkageName, llvm::GlobalVariable *Var,
+ llvm::DIDescriptor DContext);
+
/// getFunctionName - Get function name for the given FunctionDecl. If the
/// name is constructed on demand (e.g. C++ destructor) then the name
/// is stored on the side.
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index bc8620d442..7a0ef8948e 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -178,8 +178,7 @@ static llvm::Constant *createAtExitStub(CodeGenModule &CGM, const VarDecl &VD,
CodeGenFunction CGF(CGM);
CGF.StartFunction(&VD, CGM.getContext().VoidTy, fn,
- CGM.getTypes().arrangeNullaryFunction(), FunctionArgList(),
- SourceLocation());
+ CGM.getTypes().arrangeNullaryFunction(), FunctionArgList());
llvm::CallInst *call = CGF.Builder.CreateCall(dtor, addr);
@@ -412,7 +411,8 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
StartFunction(GlobalDecl(D), getContext().VoidTy, Fn,
getTypes().arrangeNullaryFunction(),
- FunctionArgList(), D->getInit()->getExprLoc());
+ FunctionArgList(), D->getLocation(),
+ D->getInit()->getExprLoc());
// Use guarded initialization if the global variable is weak. This
// occurs for, e.g., instantiated static data members and
@@ -431,44 +431,49 @@ void
CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
ArrayRef<llvm::Constant *> Decls,
llvm::GlobalVariable *Guard) {
- StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
- getTypes().arrangeNullaryFunction(),
- FunctionArgList(), SourceLocation());
-
- llvm::BasicBlock *ExitBlock = 0;
- if (Guard) {
- // If we have a guard variable, check whether we've already performed these
- // initializations. This happens for TLS initialization functions.
- llvm::Value *GuardVal = Builder.CreateLoad(Guard);
- llvm::Value *Uninit = Builder.CreateIsNull(GuardVal, "guard.uninitialized");
- // Mark as initialized before initializing anything else. If the
- // initializers use previously-initialized thread_local vars, that's
- // probably supposed to be OK, but the standard doesn't say.
- Builder.CreateStore(llvm::ConstantInt::get(GuardVal->getType(), 1), Guard);
- llvm::BasicBlock *InitBlock = createBasicBlock("init");
- ExitBlock = createBasicBlock("exit");
- Builder.CreateCondBr(Uninit, InitBlock, ExitBlock);
- EmitBlock(InitBlock);
- }
+ {
+ ArtificialLocation AL(*this, Builder);
+ StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
+ getTypes().arrangeNullaryFunction(), FunctionArgList());
+ // Emit an artificial location for this function.
+ AL.Emit();
+
+ llvm::BasicBlock *ExitBlock = 0;
+ if (Guard) {
+ // If we have a guard variable, check whether we've already performed
+ // these initializations. This happens for TLS initialization functions.
+ llvm::Value *GuardVal = Builder.CreateLoad(Guard);
+ llvm::Value *Uninit = Builder.CreateIsNull(GuardVal,
+ "guard.uninitialized");
+ // Mark as initialized before initializing anything else. If the
+ // initializers use previously-initialized thread_local vars, that's
+ // probably supposed to be OK, but the standard doesn't say.
+ Builder.CreateStore(llvm::ConstantInt::get(GuardVal->getType(),1), Guard);
+ llvm::BasicBlock *InitBlock = createBasicBlock("init");
+ ExitBlock = createBasicBlock("exit");
+ Builder.CreateCondBr(Uninit, InitBlock, ExitBlock);
+ EmitBlock(InitBlock);
+ }
- RunCleanupsScope Scope(*this);
+ RunCleanupsScope Scope(*this);
- // When building in Objective-C++ ARC mode, create an autorelease pool
- // around the global initializers.
- if (getLangOpts().ObjCAutoRefCount && getLangOpts().CPlusPlus) {
- llvm::Value *token = EmitObjCAutoreleasePoolPush();
- EmitObjCAutoreleasePoolCleanup(token);
- }
+ // When building in Objective-C++ ARC mode, create an autorelease pool
+ // around the global initializers.
+ if (getLangOpts().ObjCAutoRefCount && getLangOpts().CPlusPlus) {
+ llvm::Value *token = EmitObjCAutoreleasePoolPush();
+ EmitObjCAutoreleasePoolCleanup(token);
+ }
- for (unsigned i = 0, e = Decls.size(); i != e; ++i)
- if (Decls[i])
- EmitRuntimeCall(Decls[i]);
+ for (unsigned i = 0, e = Decls.size(); i != e; ++i)
+ if (Decls[i])
+ EmitRuntimeCall(Decls[i]);
- Scope.ForceCleanup();
+ Scope.ForceCleanup();
- if (ExitBlock) {
- Builder.CreateBr(ExitBlock);
- EmitBlock(ExitBlock);
+ if (ExitBlock) {
+ Builder.CreateBr(ExitBlock);
+ EmitBlock(ExitBlock);
+ }
}
FinishFunction();
@@ -477,18 +482,22 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
void CodeGenFunction::GenerateCXXGlobalDtorsFunc(llvm::Function *Fn,
const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> >
&DtorsAndObjects) {
- StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
- getTypes().arrangeNullaryFunction(),
- FunctionArgList(), SourceLocation());
-
- // Emit the dtors, in reverse order from construction.
- for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) {
- llvm::Value *Callee = DtorsAndObjects[e - i - 1].first;
- llvm::CallInst *CI = Builder.CreateCall(Callee,
- DtorsAndObjects[e - i - 1].second);
- // Make sure the call and the callee agree on calling convention.
- if (llvm::Function *F = dyn_cast<llvm::Function>(Callee))
- CI->setCallingConv(F->getCallingConv());
+ {
+ ArtificialLocation AL(*this, Builder);
+ StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
+ getTypes().arrangeNullaryFunction(), FunctionArgList());
+ // Emit an artificial location for this function.
+ AL.Emit();
+
+ // Emit the dtors, in reverse order from construction.
+ for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) {
+ llvm::Value *Callee = DtorsAndObjects[e - i - 1].first;
+ llvm::CallInst *CI = Builder.CreateCall(Callee,
+ DtorsAndObjects[e - i - 1].second);
+ // Make sure the call and the callee agree on calling convention.
+ if (llvm::Function *F = dyn_cast<llvm::Function>(Callee))
+ CI->setCallingConv(F->getCallingConv());
+ }
}
FinishFunction();
@@ -509,7 +518,7 @@ llvm::Function *CodeGenFunction::generateDestroyHelper(
llvm::Function *fn =
CreateGlobalInitOrDestructFunction(CGM, FTy, "__cxx_global_array_dtor");
- StartFunction(VD, getContext().VoidTy, fn, FI, args, SourceLocation());
+ StartFunction(VD, getContext().VoidTy, fn, FI, args);
emitDestroy(addr, type, destroyer, useEHCleanupForArray);
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 1bdd094873..badde1b7c9 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -1953,33 +1953,27 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
case PredefinedExpr::Function:
case PredefinedExpr::LFunction:
case PredefinedExpr::FuncDName:
+ case PredefinedExpr::FuncSig:
case PredefinedExpr::PrettyFunction: {
PredefinedExpr::IdentType IdentType = E->getIdentType();
- std::string GlobalVarName;
+ std::string GVName;
+ // FIXME: We should use the string literal mangling for the Microsoft C++
+ // ABI so that strings get merged.
switch (IdentType) {
default: llvm_unreachable("Invalid type");
- case PredefinedExpr::Func:
- GlobalVarName = "__func__.";
- break;
- case PredefinedExpr::Function:
- GlobalVarName = "__FUNCTION__.";
- break;
- case PredefinedExpr::FuncDName:
- GlobalVarName = "__FUNCDNAME__.";
- break;
- case PredefinedExpr::LFunction:
- GlobalVarName = "L__FUNCTION__.";
- break;
- case PredefinedExpr::PrettyFunction:
- GlobalVarName = "__PRETTY_FUNCTION__.";
- break;
+ case PredefinedExpr::Func: GVName = "__func__."; break;
+ case PredefinedExpr::Function: GVName = "__FUNCTION__."; break;
+ case PredefinedExpr::FuncDName: GVName = "__FUNCDNAME__."; break;
+ case PredefinedExpr::FuncSig: GVName = "__FUNCSIG__."; break;
+ case PredefinedExpr::LFunction: GVName = "L__FUNCTION__."; break;
+ case PredefinedExpr::PrettyFunction: GVName = "__PRETTY_FUNCTION__."; break;
}
StringRef FnName = CurFn->getName();
if (FnName.startswith("\01"))
FnName = FnName.substr(1);
- GlobalVarName += FnName;
+ GVName += FnName;
// If this is outside of a function use the top level decl.
const Decl *CurDecl = CurCodeDecl;
@@ -2010,15 +2004,13 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
getContext().getTypeSizeInChars(ElemType).getQuantity(),
FunctionName, RawChars);
C = GetAddrOfConstantWideString(RawChars,
- GlobalVarName.c_str(),
+ GVName.c_str(),
getContext(),
E->getType(),
E->getLocation(),
CGM);
} else {
- C = CGM.GetAddrOfConstantCString(FunctionName,
- GlobalVarName.c_str(),
- 1);
+ C = CGM.GetAddrOfConstantCString(FunctionName, GVName.c_str(), 1);
}
return MakeAddrLValue(C, E->getType());
}
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 82382ddf68..4e615922fe 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -836,7 +836,10 @@ public:
// as an inline array.
std::string Str;
CGM.getContext().getObjCEncodingForType(E->getEncodedType(), Str);
- const ConstantArrayType *CAT = cast<ConstantArrayType>(E->getType());
+ QualType T = E->getType();
+ if (T->getTypeClass() == Type::TypeOfExpr)
+ T = cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType();
+ const ConstantArrayType *CAT = cast<ConstantArrayType>(T);
// Resize the string to the right size, adding zeros at the end, or
// truncating as needed.
@@ -1063,7 +1066,9 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
// Apply offset if necessary.
if (!Offset->isNullValue()) {
- llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, Int8PtrTy);
+ unsigned AS = C->getType()->getPointerAddressSpace();
+ llvm::Type *CharPtrTy = Int8Ty->getPointerTo(AS);
+ llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(C, CharPtrTy);
Casted = llvm::ConstantExpr::getGetElementPtr(Casted, Offset);
C = llvm::ConstantExpr::getPointerCast(Casted, C->getType());
}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 5f932b08b5..522a0e2d23 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -1460,7 +1460,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
// Splat the element across to all elements
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
- return Builder.CreateVectorSplat(NumElements, Elt, "splat");;
+ return Builder.CreateVectorSplat(NumElements, Elt, "splat");
}
case CK_IntegralCast:
@@ -3199,6 +3199,10 @@ Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) {
}
Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
+ QualType Ty = VE->getType();
+ if (Ty->isVariablyModifiedType())
+ CGF.EmitVariablyModifiedType(Ty);
+
llvm::Value *ArgValue = CGF.EmitVAListRef(VE->getSubExpr());
llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType());
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index f78bb0b310..47a096d540 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -481,7 +481,8 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
CurGD = OMD;
- StartFunction(OMD, OMD->getReturnType(), Fn, FI, args, StartLoc);
+ StartFunction(OMD, OMD->getReturnType(), Fn, FI, args,
+ OMD->getLocation(), StartLoc);
// In ARC, certain methods get an extra cleanup.
if (CGM.getLangOpts().ObjCAutoRefCount &&
@@ -2915,7 +2916,7 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
"__assign_helper_atomic_property_",
&CGM.getModule());
- StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
+ StartFunction(FD, C.VoidTy, Fn, FI, args);
DeclRefExpr DstExpr(&dstDecl, false, DestTy,
VK_RValue, SourceLocation());
@@ -2993,7 +2994,7 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
"__copy_helper_atomic_property_", &CGM.getModule());
- StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
+ StartFunction(FD, C.VoidTy, Fn, FI, args);
DeclRefExpr SrcExpr(&srcDecl, false, SrcTy,
VK_RValue, SourceLocation());
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 7049df7f78..04523bc08b 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -984,7 +984,8 @@ void CodeGenModule::EmitFundamentalRTTIDescriptors() {
Context.UnsignedShortTy, Context.IntTy,
Context.UnsignedIntTy, Context.LongTy,
Context.UnsignedLongTy, Context.LongLongTy,
- Context.UnsignedLongLongTy, Context.FloatTy,
+ Context.UnsignedLongLongTy,
+ Context.HalfTy, Context.FloatTy,
Context.DoubleTy, Context.LongDoubleTy,
Context.Char16Ty, Context.Char32Ty };
for (unsigned i = 0; i < llvm::array_lengthof(FundamentalTypes); ++i)
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h
index 0fc7b8acbd..b45fee56ea 100644
--- a/lib/CodeGen/CGRecordLayout.h
+++ b/lib/CodeGen/CGRecordLayout.h
@@ -183,6 +183,7 @@ public:
/// \brief Return llvm::StructType element number that corresponds to the
/// field FD.
unsigned getLLVMFieldNo(const FieldDecl *FD) const {
+ FD = FD->getCanonicalDecl();
assert(FieldInfo.count(FD) && "Invalid field for record!");
return FieldInfo.lookup(FD);
}
@@ -201,6 +202,7 @@ public:
/// \brief Return the BitFieldInfo that corresponds to the field FD.
const CGBitFieldInfo &getBitFieldInfo(const FieldDecl *FD) const {
+ FD = FD->getCanonicalDecl();
assert(FD->isBitField() && "Invalid call for non-bit-field decl!");
llvm::DenseMap<const FieldDecl *, CGBitFieldInfo>::const_iterator
it = BitFields.find(FD);
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 75b4504ca6..eb2d524ef7 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -212,7 +212,7 @@ CGRecordLowering::CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D)
void CGRecordLowering::setBitFieldInfo(
const FieldDecl *FD, CharUnits StartOffset, llvm::Type *StorageType) {
- CGBitFieldInfo &Info = BitFields[FD];
+ CGBitFieldInfo &Info = BitFields[FD->getCanonicalDecl()];
Info.IsSigned = FD->getType()->isSignedIntegerOrEnumerationType();
Info.Offset = (unsigned)(getFieldBitOffset(FD) - Context.toBits(StartOffset));
Info.Size = FD->getBitWidthValue(Context);
@@ -297,7 +297,7 @@ void CGRecordLowering::lowerUnion() {
FieldType = getByteArrayType(LayoutSize);
setBitFieldInfo(Field, CharUnits::Zero(), FieldType);
}
- Fields[Field] = 0;
+ Fields[Field->getCanonicalDecl()] = 0;
llvm::Type *FieldType = getStorageType(Field);
// Conditionally update our storage type if we've got a new "better" one.
if (!StorageType ||
@@ -414,10 +414,11 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field,
void CGRecordLowering::accumulateBases() {
// If we've got a primary virtual base, we need to add it with the bases.
- if (Layout.isPrimaryBaseVirtual())
- Members.push_back(StorageInfo(
- CharUnits::Zero(),
- getStorageType(Layout.getPrimaryBase())));
+ if (Layout.isPrimaryBaseVirtual()) {
+ const CXXRecordDecl *BaseDecl = Layout.getPrimaryBase();
+ Members.push_back(MemberInfo(CharUnits::Zero(), MemberInfo::Base,
+ getStorageType(BaseDecl), BaseDecl));
+ }
// Accumulate the non-virtual bases.
for (const auto &Base : RD->bases()) {
if (Base.isVirtual())
@@ -440,8 +441,24 @@ void CGRecordLowering::accumulateVPtrs() {
}
void CGRecordLowering::accumulateVBases() {
- Members.push_back(MemberInfo(Layout.getNonVirtualSize(),
- MemberInfo::Scissor, 0, RD));
+ CharUnits ScissorOffset = Layout.getNonVirtualSize();
+ // In the itanium ABI, it's possible to place a vbase at a dsize that is
+ // smaller than the nvsize. Here we check to see if such a base is placed
+ // before the nvsize and set the scissor offset to that, instead of the
+ // nvsize.
+ if (!useMSABI())
+ for (const auto &Base : RD->vbases()) {
+ const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
+ if (BaseDecl->isEmpty())
+ continue;
+ // If the vbase is a primary virtual base of some base, then it doesn't
+ // get its own storage location but instead lives inside of that base.
+ if (Context.isNearlyEmpty(BaseDecl) && !hasOwnStorage(RD, BaseDecl))
+ continue;
+ ScissorOffset = std::min(ScissorOffset,
+ Layout.getVBaseClassOffset(BaseDecl));
+ }
+ Members.push_back(MemberInfo(ScissorOffset, MemberInfo::Scissor, 0, RD));
for (const auto &Base : RD->vbases()) {
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
if (BaseDecl->isEmpty())
@@ -570,7 +587,7 @@ void CGRecordLowering::fillOutputFields() {
FieldTypes.push_back(Member->Data);
if (Member->Kind == MemberInfo::Field) {
if (Member->FD)
- Fields[Member->FD] = FieldTypes.size() - 1;
+ Fields[Member->FD->getCanonicalDecl()] = FieldTypes.size() - 1;
// A field without storage must be a bitfield.
if (!Member->Data)
setBitFieldInfo(Member->FD, Member->Offset, FieldTypes.back());
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index cba9e6cd4d..9ea53b3e1f 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -1944,7 +1944,9 @@ CodeGenFunction::GenerateCapturedStmtFunction(const CapturedDecl *CD,
CGM.SetInternalFunctionAttributes(CD, F, FuncInfo);
// Generate the function.
- StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getBody()->getLocStart());
+ StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args,
+ CD->getLocation(),
+ CD->getBody()->getLocStart());
// Set the context parameter in CapturedStmtInfo.
llvm::Value *DeclPtr = LocalDeclMap[CD->getContextParam()];
@@ -1960,8 +1962,11 @@ CodeGenFunction::GenerateCapturedStmtFunction(const CapturedDecl *CD,
CXXThisValue = EmitLoadOfLValue(ThisLValue, Loc).getScalarVal();
}
+ PGO.assignRegionCounters(CD, F);
CapturedStmtInfo->EmitBody(*this, CD->getBody());
FinishFunction(CD->getBodyRBrace());
+ PGO.emitInstrumentationData();
+ PGO.destroyRegionCounters();
return F;
}
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 0ad765ce22..08537d5f25 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -217,7 +217,7 @@ void CodeGenFunction::StartThunk(llvm::Function *Fn, GlobalDecl GD,
// Start defining the function.
StartFunction(GlobalDecl(), ResultType, Fn, FnInfo, FunctionArgs,
- SourceLocation());
+ MD->getLocation(), SourceLocation());
// Since we didn't pass a GlobalDecl to StartFunction, do this ourselves.
CGM.getCXXABI().EmitInstanceFunctionProlog(*this);
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 12cb1ab255..0d49a0951c 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -9,6 +9,7 @@ set(LLVM_LINK_COMPONENTS
Linker
MC
ObjCARCOpts
+ ProfileData
ScalarOpts
Support
Target
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index 573f8e98e7..e1e102fc23 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -20,6 +20,7 @@
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/LLVMContext.h"
@@ -220,6 +221,11 @@ namespace clang {
/// \return True if the diagnostic has been successfully reported, false
/// otherwise.
bool StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D);
+ /// \brief Specialized handler for the optimization diagnostic.
+ /// Note that this handler only accepts remarks and it always handles
+ /// them.
+ void
+ OptimizationRemarkHandler(const llvm::DiagnosticInfoOptimizationRemark &D);
};
void BackendConsumer::anchor() {}
@@ -374,6 +380,44 @@ BackendConsumer::StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D) {
return true;
}
+void BackendConsumer::OptimizationRemarkHandler(
+ const llvm::DiagnosticInfoOptimizationRemark &D) {
+ // We only support remarks.
+ assert (D.getSeverity() == llvm::DS_Remark);
+
+ // Optimization remarks are active only if -Rpass=regexp is given and the
+ // regular expression pattern in 'regexp' matches the name of the pass
+ // name in \p D.
+ if (CodeGenOpts.OptimizationRemarkPattern &&
+ CodeGenOpts.OptimizationRemarkPattern->match(D.getPassName())) {
+ SourceManager &SourceMgr = Context->getSourceManager();
+ FileManager &FileMgr = SourceMgr.getFileManager();
+ StringRef Filename;
+ unsigned Line, Column;
+ D.getLocation(&Filename, &Line, &Column);
+ SourceLocation Loc;
+ if (Line > 0) {
+ // If -gcolumn-info was not used, Column will be 0. This upsets the
+ // source manager, so if Column is not set, set it to 1.
+ if (Column == 0)
+ Column = 1;
+ Loc = SourceMgr.translateFileLineCol(FileMgr.getFile(Filename), Line,
+ Column);
+ }
+ Diags.Report(Loc, diag::remark_fe_backend_optimization_remark)
+ << AddFlagValue(D.getPassName()) << D.getMsg().str();
+
+ if (Line == 0)
+ // If we could not extract a source location for the diagnostic,
+ // inform the user how they can get source locations back.
+ //
+ // FIXME: We should really be generating !srcloc annotations when
+ // -Rpass is used. !srcloc annotations need to be emitted in
+ // approximately the same spots as !dbg nodes.
+ Diags.Report(diag::note_fe_backend_optimization_remark_missing_loc);
+ }
+}
+
/// \brief This function is invoked when the backend needs
/// to report something to the user.
void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) {
@@ -391,6 +435,11 @@ void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) {
return;
ComputeDiagID(Severity, backend_frame_larger_than, DiagID);
break;
+ case llvm::DK_OptimizationRemark:
+ // Optimization remarks are always handled completely by this
+ // handler. There is no generic way of emitting them.
+ OptimizationRemarkHandler(cast<DiagnosticInfoOptimizationRemark>(DI));
+ return;
default:
// Plugin IDs are not bound to any value as they are set dynamically.
ComputeDiagRemarkID(Severity, backend_plugin, DiagID);
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 806540a26c..95e4ee498d 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -339,6 +339,8 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
// Each MDNode is a list in the form of "key", N number of values which is
// the same number of values as their are kernel arguments.
+ const PrintingPolicy &Policy = ASTCtx.getPrintingPolicy();
+
// MDNode for the kernel argument address space qualifiers.
SmallVector<llvm::Value*, 8> addressQuals;
addressQuals.push_back(llvm::MDString::get(Context, "kernel_arg_addr_space"));
@@ -372,7 +374,8 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
pointeeTy.getAddressSpace())));
// Get argument type name.
- std::string typeName = pointeeTy.getUnqualifiedType().getAsString() + "*";
+ std::string typeName =
+ pointeeTy.getUnqualifiedType().getAsString(Policy) + "*";
// Turn "unsigned type" to "utype"
std::string::size_type pos = typeName.find("unsigned");
@@ -398,7 +401,7 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
addressQuals.push_back(Builder.getInt32(AddrSpc));
// Get argument type name.
- std::string typeName = ty.getUnqualifiedType().getAsString();
+ std::string typeName = ty.getUnqualifiedType().getAsString(Policy);
// Turn "unsigned type" to "utype"
std::string::size_type pos = typeName.find("unsigned");
@@ -500,6 +503,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
llvm::Function *Fn,
const CGFunctionInfo &FnInfo,
const FunctionArgList &Args,
+ SourceLocation Loc,
SourceLocation StartLoc) {
const Decl *D = GD.getDecl();
@@ -577,9 +581,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
QualType FnType =
getContext().getFunctionType(RetTy, ArgTypes,
FunctionProtoType::ExtProtoInfo());
-
- DI->setLocation(StartLoc);
- DI->EmitFunctionStart(GD, FnType, CurFn, Builder);
+ DI->EmitFunctionStart(GD, Loc, StartLoc, FnType, CurFn, Builder);
}
if (ShouldInstrumentFunction())
@@ -756,8 +758,24 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
CurEHLocation = BodyRange.getEnd();
+ // Use the location of the start of the function to determine where
+ // the function definition is located. By default use the location
+ // of the declaration as the location for the subprogram. A function
+ // may lack a declaration in the source code if it is created by code
+ // gen. (examples: _GLOBAL__I_a, __cxx_global_array_dtor, thunk).
+ SourceLocation Loc;
+ if (FD) {
+ Loc = FD->getLocation();
+
+ // If this is a function specialization then use the pattern body
+ // as the location for the function.
+ if (const FunctionDecl *SpecDecl = FD->getTemplateInstantiationPattern())
+ if (SpecDecl->hasBody(SpecDecl))
+ Loc = SpecDecl->getLocation();
+ }
+
// Emit the standard function prologue.
- StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin());
+ StartFunction(GD, ResTy, Fn, FnInfo, Args, Loc, BodyRange.getBegin());
// Generate the body of the function.
PGO.assignRegionCounters(GD.getDecl(), CurFn);
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 5b0653adc6..ec9601e064 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -195,6 +195,8 @@ public:
/// \brief Emit the captured statement body.
virtual void EmitBody(CodeGenFunction &CGF, Stmt *S) {
+ RegionCounter Cnt = CGF.getPGORegionCounter(S);
+ Cnt.beginRegion(CGF.Builder);
CGF.EmitStmt(S);
}
@@ -1140,12 +1142,16 @@ public:
void GenerateCode(GlobalDecl GD, llvm::Function *Fn,
const CGFunctionInfo &FnInfo);
+ /// \brief Emit code for the start of a function.
+ /// \param Loc The location to be associated with the function.
+ /// \param StartLoc The location of the function body.
void StartFunction(GlobalDecl GD,
QualType RetTy,
llvm::Function *Fn,
const CGFunctionInfo &FnInfo,
const FunctionArgList &Args,
- SourceLocation StartLoc);
+ SourceLocation Loc = SourceLocation(),
+ SourceLocation StartLoc = SourceLocation());
void EmitConstructorBody(FunctionArgList &Args);
void EmitDestructorBody(FunctionArgList &Args);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index c26f769118..34673bf29a 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -47,6 +47,7 @@
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
+#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
@@ -78,7 +79,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
ABI(createCXXABI(*this)), VMContext(M.getContext()), TBAA(0),
TheTargetCodeGenInfo(0), Types(*this), VTables(*this), ObjCRuntime(0),
OpenCLRuntime(0), CUDARuntime(0), DebugInfo(0), ARCData(0),
- NoObjCARCExceptionsMetadata(0), RRData(0), PGOData(0),
+ NoObjCARCExceptionsMetadata(0), RRData(0), PGOReader(nullptr),
CFConstantStringClassRef(0),
ConstantStringClassRef(0), NSConstantStringType(0),
NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), BlockObjectAssign(0),
@@ -134,8 +135,14 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
ARCData = new ARCEntrypoints();
RRData = new RREntrypoints();
- if (!CodeGenOpts.InstrProfileInput.empty())
- PGOData = new PGOProfileData(*this, CodeGenOpts.InstrProfileInput);
+ if (!CodeGenOpts.InstrProfileInput.empty()) {
+ if (llvm::error_code EC = llvm::IndexedInstrProfReader::create(
+ CodeGenOpts.InstrProfileInput, PGOReader)) {
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "Could not read profile: %0");
+ getDiags().Report(DiagID) << EC.message();
+ }
+ }
}
CodeGenModule::~CodeGenModule() {
@@ -283,6 +290,12 @@ void CodeGenModule::Release() {
if (ObjCRuntime)
if (llvm::Function *ObjCInitFunction = ObjCRuntime->ModuleInitFunction())
AddGlobalCtor(ObjCInitFunction);
+ if (getCodeGenOpts().ProfileInstrGenerate)
+ if (llvm::Function *PGOInit = CodeGenPGO::emitInitialization(*this))
+ AddGlobalCtor(PGOInit, 0);
+ if (PGOReader && PGOStats.isOutOfDate())
+ getDiags().Report(diag::warn_profile_data_out_of_date)
+ << PGOStats.Visited << PGOStats.Missing << PGOStats.Mismatched;
EmitCtorList(GlobalCtors, "llvm.global_ctors");
EmitCtorList(GlobalDtors, "llvm.global_dtors");
EmitGlobalAnnotations();
@@ -759,6 +772,31 @@ void CodeGenModule::SetInternalFunctionAttributes(const Decl *D,
SetCommonAttributes(D, F);
}
+static void setLinkageAndVisibilityForGV(llvm::GlobalValue *GV,
+ const NamedDecl *ND) {
+ // Set linkage and visibility in case we never see a definition.
+ LinkageInfo LV = ND->getLinkageAndVisibility();
+ if (LV.getLinkage() != ExternalLinkage) {
+ // Don't set internal linkage on declarations.
+ } else {
+ if (ND->hasAttr<DLLImportAttr>()) {
+ GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+ } else if (ND->hasAttr<DLLExportAttr>()) {
+ GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
+ } else if (ND->hasAttr<WeakAttr>() || ND->isWeakImported()) {
+ // "extern_weak" is overloaded in LLVM; we probably should have
+ // separate linkage types for this.
+ GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
+ }
+
+ // Set visibility on a declaration only if it's explicit.
+ if (LV.isVisibilityExplicit())
+ GV->setVisibility(CodeGenModule::GetLLVMVisibility(LV.getVisibility()));
+ }
+}
+
void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
llvm::Function *F,
bool IsIncompleteFunction) {
@@ -791,24 +829,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
// Only a few attributes are set on declarations; these may later be
// overridden by a definition.
- if (FD->hasAttr<DLLImportAttr>()) {
- F->setLinkage(llvm::Function::ExternalLinkage);
- F->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
- } else if (FD->hasAttr<WeakAttr>() ||
- FD->isWeakImported()) {
- // "extern_weak" is overloaded in LLVM; we probably should have
- // separate linkage types for this.
- F->setLinkage(llvm::Function::ExternalWeakLinkage);
- } else {
- F->setLinkage(llvm::Function::ExternalLinkage);
- if (FD->hasAttr<DLLExportAttr>())
- F->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
-
- LinkageInfo LV = FD->getLinkageAndVisibility();
- if (LV.getLinkage() == ExternalLinkage && LV.isVisibilityExplicit()) {
- F->setVisibility(GetLLVMVisibility(LV.getVisibility()));
- }
- }
+ setLinkageAndVisibilityForGV(F, FD);
if (const SectionAttr *SA = FD->getAttr<SectionAttr>())
F->setSection(SA->getName());
@@ -1544,6 +1565,18 @@ bool CodeGenModule::isTypeConstant(QualType Ty, bool ExcludeCtor) {
return true;
}
+static bool isVarDeclInlineInitializedStaticDataMember(const VarDecl *VD) {
+ if (!VD->isStaticDataMember())
+ return false;
+ const VarDecl *InitDecl;
+ const Expr *InitExpr = VD->getAnyInitializer(InitDecl);
+ if (!InitExpr)
+ return false;
+ if (InitDecl->isThisDeclarationADefinition())
+ return false;
+ return true;
+}
+
/// GetOrCreateLLVMGlobal - If the specified mangled name is not in the module,
/// create and return an llvm GlobalVariable with the specified type. If there
/// is something in the module with the specified name, return it potentially
@@ -1601,21 +1634,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
// handling.
GV->setConstant(isTypeConstant(D->getType(), false));
- // Set linkage and visibility in case we never see a definition.
- LinkageInfo LV = D->getLinkageAndVisibility();
- if (LV.getLinkage() != ExternalLinkage) {
- // Don't set internal linkage on declarations.
- } else {
- if (D->hasAttr<DLLImportAttr>()) {
- GV->setLinkage(llvm::GlobalValue::ExternalLinkage);
- GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
- } else if (D->hasAttr<WeakAttr>() || D->isWeakImported())
- GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
-
- // Set visibility on a declaration only if it's explicit.
- if (LV.isVisibilityExplicit())
- GV->setVisibility(GetLLVMVisibility(LV.getVisibility()));
- }
+ setLinkageAndVisibilityForGV(GV, D);
if (D->getTLSKind()) {
if (D->getTLSKind() == VarDecl::TLS_Dynamic)
@@ -1626,8 +1645,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
// If required by the ABI, treat declarations of static data members with
// inline initializers as definitions.
if (getCXXABI().isInlineInitializedStaticDataMemberLinkOnce() &&
- D->isStaticDataMember() && D->hasInit() &&
- !D->isThisDeclarationADefinition())
+ isVarDeclInlineInitializedStaticDataMember(D))
EmitGlobalVarDefinition(D);
}
@@ -1893,13 +1911,6 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
else if (D->hasAttr<DLLExportAttr>())
GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass);
- // If required by the ABI, give definitions of static data members with inline
- // initializers linkonce_odr linkage.
- if (getCXXABI().isInlineInitializedStaticDataMemberLinkOnce() &&
- D->isStaticDataMember() && InitExpr &&
- !InitDecl->isThisDeclarationADefinition())
- GV->setLinkage(llvm::GlobalVariable::LinkOnceODRLinkage);
-
if (Linkage == llvm::GlobalVariable::CommonLinkage)
// common vars aren't constant even if declared const.
GV->setConstant(false);
@@ -1928,6 +1939,34 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
DI->EmitGlobalVariable(GV, D);
}
+static bool isVarDeclStrongDefinition(const VarDecl *D, bool NoCommon) {
+ // Don't give variables common linkage if -fno-common was specified unless it
+ // was overridden by a NoCommon attribute.
+ if ((NoCommon || D->hasAttr<NoCommonAttr>()) && !D->hasAttr<CommonAttr>())
+ return true;
+
+ // C11 6.9.2/2:
+ // A declaration of an identifier for an 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.
+ if (D->getInit() || D->hasExternalStorage())
+ return true;
+
+ // A variable cannot be both common and exist in a section.
+ if (D->hasAttr<SectionAttr>())
+ return true;
+
+ // Thread local vars aren't considered common linkage.
+ if (D->getTLSKind())
+ return true;
+
+ // Tentative definitions marked with WeakImportAttr are true definitions.
+ if (D->hasAttr<WeakImportAttr>())
+ return true;
+
+ return false;
+}
+
llvm::GlobalValue::LinkageTypes
CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant) {
GVALinkage Linkage = getContext().GetGVALinkageForVariable(D);
@@ -1950,21 +1989,23 @@ CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant) {
return llvm::GlobalVariable::WeakAnyLinkage;
} else if (Linkage == GVA_TemplateInstantiation || Linkage == GVA_StrongODR)
return llvm::GlobalVariable::WeakODRLinkage;
- else if (!getLangOpts().CPlusPlus &&
- ((!CodeGenOpts.NoCommon && !D->hasAttr<NoCommonAttr>()) ||
- D->hasAttr<CommonAttr>()) &&
- !D->hasExternalStorage() && !D->getInit() &&
- !D->hasAttr<SectionAttr>() && !D->getTLSKind() &&
- !D->hasAttr<WeakImportAttr>()) {
- // Thread local vars aren't considered common linkage.
- return llvm::GlobalVariable::CommonLinkage;
- } else if (D->getTLSKind() == VarDecl::TLS_Dynamic &&
- getTarget().getTriple().isMacOSX())
+ else if (D->getTLSKind() == VarDecl::TLS_Dynamic &&
+ getTarget().getTriple().isMacOSX())
// On Darwin, the backing variable for a C++11 thread_local variable always
// has internal linkage; all accesses should just be calls to the
// Itanium-specified entry point, which has the normal linkage of the
// variable.
return llvm::GlobalValue::InternalLinkage;
+ else if (getCXXABI().isInlineInitializedStaticDataMemberLinkOnce() &&
+ isVarDeclInlineInitializedStaticDataMember(D))
+ // If required by the ABI, give definitions of static data members with inline
+ // initializers linkonce_odr linkage.
+ return llvm::GlobalVariable::LinkOnceODRLinkage;
+ // C++ doesn't have tentative definitions and thus cannot have common linkage.
+ else if (!getLangOpts().CPlusPlus &&
+ !isVarDeclStrongDefinition(D, CodeGenOpts.NoCommon))
+ return llvm::GlobalVariable::CommonLinkage;
+
return llvm::GlobalVariable::ExternalLinkage;
}
@@ -2193,10 +2234,6 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
AddGlobalDtor(Fn, DA->getPriority());
if (D->hasAttr<AnnotateAttr>())
AddGlobalAnnotations(D, Fn);
-
- llvm::Function *PGOInit = CodeGenPGO::emitInitialization(*this);
- if (PGOInit)
- AddGlobalCtor(PGOInit, 0);
}
void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
@@ -2656,7 +2693,7 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) {
LT = llvm::GlobalValue::LinkOnceODRLinkage;
GlobalVariableName = MangledNameBuffer;
} else {
- LT = llvm::GlobalValue::PrivateLinkage;;
+ LT = llvm::GlobalValue::PrivateLinkage;
GlobalVariableName = ".str";
}
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 0d13bdcc2f..0fd325b083 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -42,6 +42,7 @@ namespace llvm {
class DataLayout;
class FunctionType;
class LLVMContext;
+ class IndexedInstrProfReader;
}
namespace clang {
@@ -85,7 +86,6 @@ namespace CodeGen {
class CGCUDARuntime;
class BlockFieldFlags;
class FunctionArgList;
- class PGOProfileData;
struct OrderGlobalInits {
unsigned int priority;
@@ -220,6 +220,15 @@ struct ARCEntrypoints {
llvm::Constant *clang_arc_use;
};
+/// This class records statistics on instrumentation based profiling.
+struct InstrProfStats {
+ InstrProfStats() : Visited(0), Missing(0), Mismatched(0) {}
+ bool isOutOfDate() { return Missing || Mismatched; }
+ uint32_t Visited;
+ uint32_t Missing;
+ uint32_t Mismatched;
+};
+
/// CodeGenModule - This class organizes the cross-function state that is used
/// while generating LLVM code.
class CodeGenModule : public CodeGenTypeCache {
@@ -257,7 +266,8 @@ class CodeGenModule : public CodeGenTypeCache {
ARCEntrypoints *ARCData;
llvm::MDNode *NoObjCARCExceptionsMetadata;
RREntrypoints *RRData;
- PGOProfileData *PGOData;
+ std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader;
+ InstrProfStats PGOStats;
// WeakRefReferences - A set of references that have only been seen via
// a weakref so far. This is used to remove the weak of the reference if we
@@ -483,9 +493,8 @@ public:
return *RRData;
}
- PGOProfileData *getPGOData() const {
- return PGOData;
- }
+ InstrProfStats &getPGOStats() { return PGOStats; }
+ llvm::IndexedInstrProfReader *getPGOReader() const { return PGOReader.get(); }
llvm::Constant *getStaticLocalDeclAddress(const VarDecl *D) {
return StaticLocalDeclMap[D];
diff --git a/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp
index ac6b7bca40..9d4aaff888 100644
--- a/lib/CodeGen/CodeGenPGO.cpp
+++ b/lib/CodeGen/CodeGenPGO.cpp
@@ -15,143 +15,15 @@
#include "CodeGenFunction.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtVisitor.h"
-#include "llvm/Config/config.h" // for strtoull()/strtoll() define
#include "llvm/IR/MDBuilder.h"
+#include "llvm/ProfileData/InstrProfReader.h"
+#include "llvm/Support/Endian.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MD5.h"
using namespace clang;
using namespace CodeGen;
-static void ReportBadPGOData(CodeGenModule &CGM, const char *Message) {
- DiagnosticsEngine &Diags = CGM.getDiags();
- unsigned diagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0");
- Diags.Report(diagID) << Message;
-}
-
-PGOProfileData::PGOProfileData(CodeGenModule &CGM, std::string Path)
- : CGM(CGM) {
- if (llvm::MemoryBuffer::getFile(Path, DataBuffer)) {
- ReportBadPGOData(CGM, "failed to open pgo data file");
- return;
- }
-
- if (DataBuffer->getBufferSize() > std::numeric_limits<unsigned>::max()) {
- ReportBadPGOData(CGM, "pgo data file too big");
- return;
- }
-
- // Scan through the data file and map each function to the corresponding
- // file offset where its counts are stored.
- const char *BufferStart = DataBuffer->getBufferStart();
- const char *BufferEnd = DataBuffer->getBufferEnd();
- const char *CurPtr = BufferStart;
- uint64_t MaxCount = 0;
- while (CurPtr < BufferEnd) {
- // Read the function name.
- const char *FuncStart = CurPtr;
- // For Objective-C methods, the name may include whitespace, so search
- // backward from the end of the line to find the space that separates the
- // name from the number of counters. (This is a temporary hack since we are
- // going to completely replace this file format in the near future.)
- CurPtr = strchr(CurPtr, '\n');
- if (!CurPtr) {
- ReportBadPGOData(CGM, "pgo data file has malformed function entry");
- return;
- }
- StringRef FuncName(FuncStart, CurPtr - FuncStart);
-
- // Skip over the function hash.
- CurPtr = strchr(++CurPtr, '\n');
- if (!CurPtr) {
- ReportBadPGOData(CGM, "pgo data file is missing the function hash");
- return;
- }
-
- // Read the number of counters.
- char *EndPtr;
- unsigned NumCounters = strtol(++CurPtr, &EndPtr, 10);
- if (EndPtr == CurPtr || *EndPtr != '\n' || NumCounters <= 0) {
- ReportBadPGOData(CGM, "pgo data file has unexpected number of counters");
- return;
- }
- CurPtr = EndPtr;
-
- // Read function count.
- uint64_t Count = strtoll(CurPtr, &EndPtr, 10);
- if (EndPtr == CurPtr || *EndPtr != '\n') {
- ReportBadPGOData(CGM, "pgo-data file has bad count value");
- return;
- }
- CurPtr = EndPtr; // Point to '\n'.
- FunctionCounts[FuncName] = Count;
- MaxCount = Count > MaxCount ? Count : MaxCount;
-
- // There is one line for each counter; skip over those lines.
- // Since function count is already read, we start the loop from 1.
- for (unsigned N = 1; N < NumCounters; ++N) {
- CurPtr = strchr(++CurPtr, '\n');
- if (!CurPtr) {
- ReportBadPGOData(CGM, "pgo data file is missing some counter info");
- return;
- }
- }
-
- // Skip over the blank line separating functions.
- CurPtr += 2;
-
- DataOffsets[FuncName] = FuncStart - BufferStart;
- }
- MaxFunctionCount = MaxCount;
-}
-
-bool PGOProfileData::getFunctionCounts(StringRef FuncName, uint64_t &FuncHash,
- std::vector<uint64_t> &Counts) {
- // Find the relevant section of the pgo-data file.
- llvm::StringMap<unsigned>::const_iterator OffsetIter =
- DataOffsets.find(FuncName);
- if (OffsetIter == DataOffsets.end())
- return true;
- const char *CurPtr = DataBuffer->getBufferStart() + OffsetIter->getValue();
-
- // Skip over the function name.
- CurPtr = strchr(CurPtr, '\n');
- assert(CurPtr && "pgo-data has corrupted function entry");
-
- char *EndPtr;
- // Read the function hash.
- FuncHash = strtoll(++CurPtr, &EndPtr, 10);
- assert(EndPtr != CurPtr && *EndPtr == '\n' &&
- "pgo-data file has corrupted function hash");
- CurPtr = EndPtr;
-
- // Read the number of counters.
- unsigned NumCounters = strtol(++CurPtr, &EndPtr, 10);
- assert(EndPtr != CurPtr && *EndPtr == '\n' && NumCounters > 0 &&
- "pgo-data file has corrupted number of counters");
- CurPtr = EndPtr;
-
- Counts.reserve(NumCounters);
-
- for (unsigned N = 0; N < NumCounters; ++N) {
- // Read the count value.
- uint64_t Count = strtoll(CurPtr, &EndPtr, 10);
- if (EndPtr == CurPtr || *EndPtr != '\n') {
- ReportBadPGOData(CGM, "pgo-data file has bad count value");
- return true;
- }
- Counts.push_back(Count);
- CurPtr = EndPtr + 1;
- }
-
- // Make sure the number of counters matches up.
- if (Counts.size() != NumCounters) {
- ReportBadPGOData(CGM, "pgo-data file has inconsistent counters");
- return true;
- }
-
- return false;
-}
-
void CodeGenPGO::setFuncName(llvm::Function *Fn) {
RawFuncName = Fn->getName();
@@ -274,7 +146,7 @@ llvm::GlobalVariable *CodeGenPGO::buildDataVar() {
}
void CodeGenPGO::emitInstrumentationData() {
- if (!CGM.getCodeGenOpts().ProfileInstrGenerate)
+ if (!RegionCounters)
return;
// Build the data.
@@ -294,9 +166,8 @@ llvm::Function *CodeGenPGO::emitInitialization(CodeGenModule &CGM) {
if (!CGM.getCodeGenOpts().ProfileInstrGenerate)
return nullptr;
- // Only need to create this once per module.
- if (CGM.getModule().getFunction("__llvm_profile_init"))
- return nullptr;
+ assert(CGM.getModule().getFunction("__llvm_profile_init") == nullptr &&
+ "profile initialization already emitted");
// Get the function to call at initialization.
llvm::Constant *RegisterF = getRegisterFunc(CGM);
@@ -322,144 +193,154 @@ llvm::Function *CodeGenPGO::emitInitialization(CodeGenModule &CGM) {
}
namespace {
- /// A StmtVisitor that fills a map of statements to PGO counters.
- struct MapRegionCounters : public ConstStmtVisitor<MapRegionCounters> {
+/// \brief Stable hasher for PGO region counters.
+///
+/// PGOHash produces a stable hash of a given function's control flow.
+///
+/// Changing the output of this hash will invalidate all previously generated
+/// profiles -- i.e., don't do it.
+///
+/// \note When this hash does eventually change (years?), we still need to
+/// support old hashes. We'll need to pull in the version number from the
+/// profile data format and use the matching hash function.
+class PGOHash {
+ uint64_t Working;
+ unsigned Count;
+ llvm::MD5 MD5;
+
+ static const int NumBitsPerType = 6;
+ static const unsigned NumTypesPerWord = sizeof(uint64_t) * 8 / NumBitsPerType;
+ static const unsigned TooBig = 1u << NumBitsPerType;
+
+public:
+ /// \brief Hash values for AST nodes.
+ ///
+ /// Distinct values for AST nodes that have region counters attached.
+ ///
+ /// These values must be stable. All new members must be added at the end,
+ /// and no members should be removed. Changing the enumeration value for an
+ /// AST node will affect the hash of every function that contains that node.
+ enum HashType : unsigned char {
+ None = 0,
+ LabelStmt = 1,
+ WhileStmt,
+ DoStmt,
+ ForStmt,
+ CXXForRangeStmt,
+ ObjCForCollectionStmt,
+ SwitchStmt,
+ CaseStmt,
+ DefaultStmt,
+ IfStmt,
+ CXXTryStmt,
+ CXXCatchStmt,
+ ConditionalOperator,
+ BinaryOperatorLAnd,
+ BinaryOperatorLOr,
+ BinaryConditionalOperator,
+
+ // Keep this last. It's for the static assert that follows.
+ LastHashType
+ };
+ static_assert(LastHashType <= TooBig, "Too many types in HashType");
+
+ // TODO: When this format changes, take in a version number here, and use the
+ // old hash calculation for file formats that used the old hash.
+ PGOHash() : Working(0), Count(0) {}
+ void combine(HashType Type);
+ uint64_t finalize();
+};
+const int PGOHash::NumBitsPerType;
+const unsigned PGOHash::NumTypesPerWord;
+const unsigned PGOHash::TooBig;
+
+ /// A RecursiveASTVisitor that fills a map of statements to PGO counters.
+ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
/// The next counter value to assign.
unsigned NextCounter;
+ /// The function hash.
+ PGOHash Hash;
/// The map of statements to counters.
llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
MapRegionCounters(llvm::DenseMap<const Stmt *, unsigned> &CounterMap)
: NextCounter(0), CounterMap(CounterMap) {}
- void VisitChildren(const Stmt *S) {
- for (Stmt::const_child_range I = S->children(); I; ++I)
- if (*I)
- this->Visit(*I);
+ // Blocks and lambdas are handled as separate functions, so we need not
+ // traverse them in the parent context.
+ bool TraverseBlockExpr(BlockExpr *BE) { return true; }
+ bool TraverseLambdaBody(LambdaExpr *LE) { return true; }
+ bool TraverseCapturedStmt(CapturedStmt *CS) { return true; }
+
+ bool VisitDecl(const Decl *D) {
+ switch (D->getKind()) {
+ default:
+ break;
+ case Decl::Function:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::ObjCMethod:
+ case Decl::Block:
+ case Decl::Captured:
+ CounterMap[D->getBody()] = NextCounter++;
+ break;
+ }
+ return true;
}
- void VisitStmt(const Stmt *S) { VisitChildren(S); }
- /// Assign a counter to track entry to the function body.
- void VisitFunctionDecl(const FunctionDecl *S) {
- CounterMap[S->getBody()] = NextCounter++;
- Visit(S->getBody());
- }
- void VisitObjCMethodDecl(const ObjCMethodDecl *S) {
- CounterMap[S->getBody()] = NextCounter++;
- Visit(S->getBody());
- }
- void VisitBlockDecl(const BlockDecl *S) {
- CounterMap[S->getBody()] = NextCounter++;
- Visit(S->getBody());
- }
- /// Assign a counter to track the block following a label.
- void VisitLabelStmt(const LabelStmt *S) {
- CounterMap[S] = NextCounter++;
- Visit(S->getSubStmt());
- }
- /// Assign a counter for the body of a while loop.
- void VisitWhileStmt(const WhileStmt *S) {
- CounterMap[S] = NextCounter++;
- Visit(S->getCond());
- Visit(S->getBody());
- }
- /// Assign a counter for the body of a do-while loop.
- void VisitDoStmt(const DoStmt *S) {
- CounterMap[S] = NextCounter++;
- Visit(S->getBody());
- Visit(S->getCond());
- }
- /// Assign a counter for the body of a for loop.
- void VisitForStmt(const ForStmt *S) {
- CounterMap[S] = NextCounter++;
- if (S->getInit())
- Visit(S->getInit());
- const Expr *E;
- if ((E = S->getCond()))
- Visit(E);
- if ((E = S->getInc()))
- Visit(E);
- Visit(S->getBody());
- }
- /// Assign a counter for the body of a for-range loop.
- void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
- CounterMap[S] = NextCounter++;
- Visit(S->getRangeStmt());
- Visit(S->getBeginEndStmt());
- Visit(S->getCond());
- Visit(S->getLoopVarStmt());
- Visit(S->getBody());
- Visit(S->getInc());
- }
- /// Assign a counter for the body of a for-collection loop.
- void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
- CounterMap[S] = NextCounter++;
- Visit(S->getElement());
- Visit(S->getBody());
- }
- /// Assign a counter for the exit block of the switch statement.
- void VisitSwitchStmt(const SwitchStmt *S) {
- CounterMap[S] = NextCounter++;
- Visit(S->getCond());
- Visit(S->getBody());
- }
- /// Assign a counter for a particular case in a switch. This counts jumps
- /// from the switch header as well as fallthrough from the case before this
- /// one.
- void VisitCaseStmt(const CaseStmt *S) {
- CounterMap[S] = NextCounter++;
- Visit(S->getSubStmt());
- }
- /// Assign a counter for the default case of a switch statement. The count
- /// is the number of branches from the loop header to the default, and does
- /// not include fallthrough from previous cases. If we have multiple
- /// conditional branch blocks from the switch instruction to the default
- /// block, as with large GNU case ranges, this is the counter for the last
- /// edge in that series, rather than the first.
- void VisitDefaultStmt(const DefaultStmt *S) {
- CounterMap[S] = NextCounter++;
- Visit(S->getSubStmt());
- }
- /// Assign a counter for the "then" part of an if statement. The count for
- /// the "else" part, if it exists, will be calculated from this counter.
- void VisitIfStmt(const IfStmt *S) {
- CounterMap[S] = NextCounter++;
- Visit(S->getCond());
- Visit(S->getThen());
- if (S->getElse())
- Visit(S->getElse());
- }
- /// Assign a counter for the continuation block of a C++ try statement.
- void VisitCXXTryStmt(const CXXTryStmt *S) {
- CounterMap[S] = NextCounter++;
- Visit(S->getTryBlock());
- for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
- Visit(S->getHandler(I));
- }
- /// Assign a counter for a catch statement's handler block.
- void VisitCXXCatchStmt(const CXXCatchStmt *S) {
+ bool VisitStmt(const Stmt *S) {
+ auto Type = getHashType(S);
+ if (Type == PGOHash::None)
+ return true;
+
CounterMap[S] = NextCounter++;
- Visit(S->getHandlerBlock());
- }
- /// Assign a counter for the "true" part of a conditional operator. The
- /// count in the "false" part will be calculated from this counter.
- void VisitConditionalOperator(const ConditionalOperator *E) {
- CounterMap[E] = NextCounter++;
- Visit(E->getCond());
- Visit(E->getTrueExpr());
- Visit(E->getFalseExpr());
- }
- /// Assign a counter for the right hand side of a logical and operator.
- void VisitBinLAnd(const BinaryOperator *E) {
- CounterMap[E] = NextCounter++;
- Visit(E->getLHS());
- Visit(E->getRHS());
+ Hash.combine(Type);
+ return true;
}
- /// Assign a counter for the right hand side of a logical or operator.
- void VisitBinLOr(const BinaryOperator *E) {
- CounterMap[E] = NextCounter++;
- Visit(E->getLHS());
- Visit(E->getRHS());
+ PGOHash::HashType getHashType(const Stmt *S) {
+ switch (S->getStmtClass()) {
+ default:
+ break;
+ case Stmt::LabelStmtClass:
+ return PGOHash::LabelStmt;
+ case Stmt::WhileStmtClass:
+ return PGOHash::WhileStmt;
+ case Stmt::DoStmtClass:
+ return PGOHash::DoStmt;
+ case Stmt::ForStmtClass:
+ return PGOHash::ForStmt;
+ case Stmt::CXXForRangeStmtClass:
+ return PGOHash::CXXForRangeStmt;
+ case Stmt::ObjCForCollectionStmtClass:
+ return PGOHash::ObjCForCollectionStmt;
+ case Stmt::SwitchStmtClass:
+ return PGOHash::SwitchStmt;
+ case Stmt::CaseStmtClass:
+ return PGOHash::CaseStmt;
+ case Stmt::DefaultStmtClass:
+ return PGOHash::DefaultStmt;
+ case Stmt::IfStmtClass:
+ return PGOHash::IfStmt;
+ case Stmt::CXXTryStmtClass:
+ return PGOHash::CXXTryStmt;
+ case Stmt::CXXCatchStmtClass:
+ return PGOHash::CXXCatchStmt;
+ case Stmt::ConditionalOperatorClass:
+ return PGOHash::ConditionalOperator;
+ case Stmt::BinaryConditionalOperatorClass:
+ return PGOHash::BinaryConditionalOperator;
+ case Stmt::BinaryOperatorClass: {
+ const BinaryOperator *BO = cast<BinaryOperator>(S);
+ if (BO->getOpcode() == BO_LAnd)
+ return PGOHash::BinaryOperatorLAnd;
+ if (BO->getOpcode() == BO_LOr)
+ return PGOHash::BinaryOperatorLOr;
+ break;
+ }
+ }
+ return PGOHash::None;
}
};
@@ -476,7 +357,7 @@ namespace {
/// The map of statements to count values.
llvm::DenseMap<const Stmt *, uint64_t> &CountMap;
- /// BreakContinueStack - Keep counts of breaks and continues inside loops.
+ /// BreakContinueStack - Keep counts of breaks and continues inside loops.
struct BreakContinue {
uint64_t BreakCount;
uint64_t ContinueCount;
@@ -503,25 +384,41 @@ namespace {
}
}
- void VisitFunctionDecl(const FunctionDecl *S) {
- RegionCounter Cnt(PGO, S->getBody());
+ void VisitFunctionDecl(const FunctionDecl *D) {
+ // Counter tracks entry to the function body.
+ RegionCounter Cnt(PGO, D->getBody());
Cnt.beginRegion();
- CountMap[S->getBody()] = PGO.getCurrentRegionCount();
- Visit(S->getBody());
+ CountMap[D->getBody()] = PGO.getCurrentRegionCount();
+ Visit(D->getBody());
}
- void VisitObjCMethodDecl(const ObjCMethodDecl *S) {
- RegionCounter Cnt(PGO, S->getBody());
+ // Skip lambda expressions. We visit these as FunctionDecls when we're
+ // generating them and aren't interested in the body when generating a
+ // parent context.
+ void VisitLambdaExpr(const LambdaExpr *LE) {}
+
+ void VisitCapturedDecl(const CapturedDecl *D) {
+ // Counter tracks entry to the capture body.
+ RegionCounter Cnt(PGO, D->getBody());
Cnt.beginRegion();
- CountMap[S->getBody()] = PGO.getCurrentRegionCount();
- Visit(S->getBody());
+ CountMap[D->getBody()] = PGO.getCurrentRegionCount();
+ Visit(D->getBody());
}
- void VisitBlockDecl(const BlockDecl *S) {
- RegionCounter Cnt(PGO, S->getBody());
+ void VisitObjCMethodDecl(const ObjCMethodDecl *D) {
+ // Counter tracks entry to the method body.
+ RegionCounter Cnt(PGO, D->getBody());
Cnt.beginRegion();
- CountMap[S->getBody()] = PGO.getCurrentRegionCount();
- Visit(S->getBody());
+ CountMap[D->getBody()] = PGO.getCurrentRegionCount();
+ Visit(D->getBody());
+ }
+
+ void VisitBlockDecl(const BlockDecl *D) {
+ // Counter tracks entry to the block body.
+ RegionCounter Cnt(PGO, D->getBody());
+ Cnt.beginRegion();
+ CountMap[D->getBody()] = PGO.getCurrentRegionCount();
+ Visit(D->getBody());
}
void VisitReturnStmt(const ReturnStmt *S) {
@@ -540,6 +437,7 @@ namespace {
void VisitLabelStmt(const LabelStmt *S) {
RecordNextStmtCount = false;
+ // Counter tracks the block following the label.
RegionCounter Cnt(PGO, S);
Cnt.beginRegion();
CountMap[S] = PGO.getCurrentRegionCount();
@@ -564,6 +462,7 @@ namespace {
void VisitWhileStmt(const WhileStmt *S) {
RecordStmtCount(S);
+ // Counter tracks the body of the loop.
RegionCounter Cnt(PGO, S);
BreakContinueStack.push_back(BreakContinue());
// Visit the body region first so the break/continue adjustments can be
@@ -589,6 +488,7 @@ namespace {
void VisitDoStmt(const DoStmt *S) {
RecordStmtCount(S);
+ // Counter tracks the body of the loop.
RegionCounter Cnt(PGO, S);
BreakContinueStack.push_back(BreakContinue());
Cnt.beginRegion(/*AddIncomingFallThrough=*/true);
@@ -615,6 +515,7 @@ namespace {
RecordStmtCount(S);
if (S->getInit())
Visit(S->getInit());
+ // Counter tracks the body of the loop.
RegionCounter Cnt(PGO, S);
BreakContinueStack.push_back(BreakContinue());
// Visit the body region first. (This is basically the same as a while
@@ -653,6 +554,7 @@ namespace {
RecordStmtCount(S);
Visit(S->getRangeStmt());
Visit(S->getBeginEndStmt());
+ // Counter tracks the body of the loop.
RegionCounter Cnt(PGO, S);
BreakContinueStack.push_back(BreakContinue());
// Visit the body region first. (This is basically the same as a while
@@ -687,6 +589,7 @@ namespace {
void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
RecordStmtCount(S);
Visit(S->getElement());
+ // Counter tracks the body of the loop.
RegionCounter Cnt(PGO, S);
BreakContinueStack.push_back(BreakContinue());
Cnt.beginRegion();
@@ -708,6 +611,7 @@ namespace {
BreakContinue BC = BreakContinueStack.pop_back_val();
if (!BreakContinueStack.empty())
BreakContinueStack.back().ContinueCount += BC.ContinueCount;
+ // Counter tracks the exit block of the switch.
RegionCounter ExitCnt(PGO, S);
ExitCnt.beginRegion();
RecordNextStmtCount = true;
@@ -715,6 +619,9 @@ namespace {
void VisitCaseStmt(const CaseStmt *S) {
RecordNextStmtCount = false;
+ // Counter for this particular case. This counts only jumps from the
+ // switch header and does not include fallthrough from the case before
+ // this one.
RegionCounter Cnt(PGO, S);
Cnt.beginRegion(/*AddIncomingFallThrough=*/true);
CountMap[S] = Cnt.getCount();
@@ -724,6 +631,8 @@ namespace {
void VisitDefaultStmt(const DefaultStmt *S) {
RecordNextStmtCount = false;
+ // Counter for this default case. This does not include fallthrough from
+ // the previous case.
RegionCounter Cnt(PGO, S);
Cnt.beginRegion(/*AddIncomingFallThrough=*/true);
CountMap[S] = Cnt.getCount();
@@ -733,6 +642,8 @@ namespace {
void VisitIfStmt(const IfStmt *S) {
RecordStmtCount(S);
+ // Counter tracks the "then" part of an if statement. The count for
+ // the "else" part, if it exists, will be calculated from this counter.
RegionCounter Cnt(PGO, S);
Visit(S->getCond());
@@ -756,6 +667,7 @@ namespace {
Visit(S->getTryBlock());
for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
Visit(S->getHandler(I));
+ // Counter tracks the continuation block of the try statement.
RegionCounter Cnt(PGO, S);
Cnt.beginRegion();
RecordNextStmtCount = true;
@@ -763,14 +675,18 @@ namespace {
void VisitCXXCatchStmt(const CXXCatchStmt *S) {
RecordNextStmtCount = false;
+ // Counter tracks the catch statement's handler block.
RegionCounter Cnt(PGO, S);
Cnt.beginRegion();
CountMap[S] = PGO.getCurrentRegionCount();
Visit(S->getHandlerBlock());
}
- void VisitConditionalOperator(const ConditionalOperator *E) {
+ void VisitAbstractConditionalOperator(
+ const AbstractConditionalOperator *E) {
RecordStmtCount(E);
+ // Counter tracks the "true" part of a conditional operator. The
+ // count in the "false" part will be calculated from this counter.
RegionCounter Cnt(PGO, E);
Visit(E->getCond());
@@ -790,6 +706,7 @@ namespace {
void VisitBinLAnd(const BinaryOperator *E) {
RecordStmtCount(E);
+ // Counter tracks the right hand side of a logical and operator.
RegionCounter Cnt(PGO, E);
Visit(E->getLHS());
Cnt.beginRegion();
@@ -802,6 +719,7 @@ namespace {
void VisitBinLOr(const BinaryOperator *E) {
RecordStmtCount(E);
+ // Counter tracks the right hand side of a logical or operator.
RegionCounter Cnt(PGO, E);
Visit(E->getLHS());
Cnt.beginRegion();
@@ -814,9 +732,46 @@ namespace {
};
}
+void PGOHash::combine(HashType Type) {
+ // Check that we never combine 0 and only have six bits.
+ assert(Type && "Hash is invalid: unexpected type 0");
+ assert(unsigned(Type) < TooBig && "Hash is invalid: too many types");
+
+ // Pass through MD5 if enough work has built up.
+ if (Count && Count % NumTypesPerWord == 0) {
+ using namespace llvm::support;
+ uint64_t Swapped = endian::byte_swap<uint64_t, little>(Working);
+ MD5.update(llvm::makeArrayRef((uint8_t *)&Swapped, sizeof(Swapped)));
+ Working = 0;
+ }
+
+ // Accumulate the current type.
+ ++Count;
+ Working = Working << NumBitsPerType | Type;
+}
+
+uint64_t PGOHash::finalize() {
+ // Use Working as the hash directly if we never used MD5.
+ if (Count <= NumTypesPerWord)
+ // No need to byte swap here, since none of the math was endian-dependent.
+ // This number will be byte-swapped as required on endianness transitions,
+ // so we will see the same value on the other side.
+ return Working;
+
+ // Check for remaining work in Working.
+ if (Working)
+ MD5.update(Working);
+
+ // Finalize the MD5 and return the hash.
+ llvm::MD5::MD5Result Result;
+ MD5.final(Result);
+ using namespace llvm::support;
+ return endian::read<uint64_t, little, unaligned>(Result);
+}
+
static void emitRuntimeHook(CodeGenModule &CGM) {
- LLVM_CONSTEXPR const char *RuntimeVarName = "__llvm_profile_runtime";
- LLVM_CONSTEXPR const char *RuntimeUserName = "__llvm_profile_runtime_user";
+ const char *const RuntimeVarName = "__llvm_profile_runtime";
+ const char *const RuntimeUserName = "__llvm_profile_runtime_user";
if (CGM.getModule().getGlobalVariable(RuntimeVarName))
return;
@@ -845,10 +800,10 @@ static void emitRuntimeHook(CodeGenModule &CGM) {
void CodeGenPGO::assignRegionCounters(const Decl *D, llvm::Function *Fn) {
bool InstrumentRegions = CGM.getCodeGenOpts().ProfileInstrGenerate;
- PGOProfileData *PGOData = CGM.getPGOData();
- if (!InstrumentRegions && !PGOData)
+ llvm::IndexedInstrProfReader *PGOReader = CGM.getPGOReader();
+ if (!InstrumentRegions && !PGOReader)
return;
- if (!D)
+ if (D->isImplicit())
return;
setFuncName(Fn);
@@ -872,10 +827,10 @@ void CodeGenPGO::assignRegionCounters(const Decl *D, llvm::Function *Fn) {
emitRuntimeHook(CGM);
emitCounterVariables();
}
- if (PGOData) {
- loadRegionCounts(PGOData);
+ if (PGOReader) {
+ loadRegionCounts(PGOReader);
computeRegionCounts(D);
- applyFunctionAttributes(PGOData, Fn);
+ applyFunctionAttributes(PGOReader, Fn);
}
}
@@ -883,14 +838,16 @@ void CodeGenPGO::mapRegionCounters(const Decl *D) {
RegionCounterMap.reset(new llvm::DenseMap<const Stmt *, unsigned>);
MapRegionCounters Walker(*RegionCounterMap);
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
- Walker.VisitFunctionDecl(FD);
+ Walker.TraverseDecl(const_cast<FunctionDecl *>(FD));
else if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))
- Walker.VisitObjCMethodDecl(MD);
+ Walker.TraverseDecl(const_cast<ObjCMethodDecl *>(MD));
else if (const BlockDecl *BD = dyn_cast_or_null<BlockDecl>(D))
- Walker.VisitBlockDecl(BD);
+ Walker.TraverseDecl(const_cast<BlockDecl *>(BD));
+ else if (const CapturedDecl *CD = dyn_cast_or_null<CapturedDecl>(D))
+ Walker.TraverseDecl(const_cast<CapturedDecl *>(CD));
+ assert(Walker.NextCounter > 0 && "no entry counter mapped for decl");
NumRegionCounters = Walker.NextCounter;
- // FIXME: The number of counters isn't sufficient for the hash
- FunctionHash = NumRegionCounters;
+ FunctionHash = Walker.Hash.finalize();
}
void CodeGenPGO::computeRegionCounts(const Decl *D) {
@@ -902,14 +859,17 @@ void CodeGenPGO::computeRegionCounts(const Decl *D) {
Walker.VisitObjCMethodDecl(MD);
else if (const BlockDecl *BD = dyn_cast_or_null<BlockDecl>(D))
Walker.VisitBlockDecl(BD);
+ else if (const CapturedDecl *CD = dyn_cast_or_null<CapturedDecl>(D))
+ Walker.VisitCapturedDecl(const_cast<CapturedDecl *>(CD));
}
-void CodeGenPGO::applyFunctionAttributes(PGOProfileData *PGOData,
- llvm::Function *Fn) {
+void
+CodeGenPGO::applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader,
+ llvm::Function *Fn) {
if (!haveRegionCounts())
return;
- uint64_t MaxFunctionCount = PGOData->getMaximumFunctionCount();
+ uint64_t MaxFunctionCount = PGOReader->getMaximumFunctionCount();
uint64_t FunctionCount = getRegionCount(0);
if (FunctionCount >= (uint64_t)(0.3 * (double)MaxFunctionCount))
// Turn on InlineHint attribute for hot functions.
@@ -943,22 +903,25 @@ void CodeGenPGO::emitCounterIncrement(CGBuilderTy &Builder, unsigned Counter) {
Builder.CreateStore(Count, Addr);
}
-void CodeGenPGO::loadRegionCounts(PGOProfileData *PGOData) {
- // For now, ignore the counts from the PGO data file only if the number of
- // counters does not match. This could be tightened down in the future to
- // ignore counts when the input changes in various ways, e.g., by comparing a
- // hash value based on some characteristics of the input.
+void CodeGenPGO::loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader) {
+ CGM.getPGOStats().Visited++;
RegionCounts.reset(new std::vector<uint64_t>);
uint64_t Hash;
- if (PGOData->getFunctionCounts(getFuncName(), Hash, *RegionCounts) ||
- Hash != FunctionHash || RegionCounts->size() != NumRegionCounters)
+ if (PGOReader->getFunctionCounts(getFuncName(), Hash, *RegionCounts)) {
+ CGM.getPGOStats().Missing++;
+ RegionCounts.reset();
+ } else if (Hash != FunctionHash ||
+ RegionCounts->size() != NumRegionCounters) {
+ CGM.getPGOStats().Mismatched++;
RegionCounts.reset();
+ }
}
void CodeGenPGO::destroyRegionCounters() {
RegionCounterMap.reset();
StmtCountMap.reset();
RegionCounts.reset();
+ RegionCounters = nullptr;
}
/// \brief Calculate what to divide by to scale weights.
@@ -1004,9 +967,13 @@ llvm::MDNode *CodeGenPGO::createBranchWeights(ArrayRef<uint64_t> Weights) {
if (Weights.size() < 2)
return nullptr;
+ // Check for empty weights.
+ uint64_t MaxWeight = *std::max_element(Weights.begin(), Weights.end());
+ if (MaxWeight == 0)
+ return nullptr;
+
// Calculate how to scale down to 32-bits.
- uint64_t Scale = calculateWeightScale(*std::max_element(Weights.begin(),
- Weights.end()));
+ uint64_t Scale = calculateWeightScale(MaxWeight);
SmallVector<uint32_t, 16> ScaledWeights;
ScaledWeights.reserve(Weights.size());
diff --git a/lib/CodeGen/CodeGenPGO.h b/lib/CodeGen/CodeGenPGO.h
index c59a58e3f8..98e5b1fd1a 100644
--- a/lib/CodeGen/CodeGenPGO.h
+++ b/lib/CodeGen/CodeGenPGO.h
@@ -26,28 +26,6 @@ namespace clang {
namespace CodeGen {
class RegionCounter;
-/// The raw counter data from an instrumented PGO binary
-class PGOProfileData {
-private:
- /// The PGO data
- std::unique_ptr<llvm::MemoryBuffer> DataBuffer;
- /// Offsets into DataBuffer for each function's counters
- llvm::StringMap<unsigned> DataOffsets;
- /// Execution counts for each function.
- llvm::StringMap<uint64_t> FunctionCounts;
- /// The maximal execution count among all functions.
- uint64_t MaxFunctionCount;
- CodeGenModule &CGM;
-public:
- PGOProfileData(CodeGenModule &CGM, std::string Path);
- /// Fill Counts with the profile data for the given function name. Returns
- /// false on success.
- bool getFunctionCounts(StringRef FuncName, uint64_t &FuncHash,
- std::vector<uint64_t> &Counts);
- /// Return the maximum of all known function counts.
- uint64_t getMaximumFunctionCount() { return MaxFunctionCount; }
-};
-
/// Per-function PGO state. This class should generally not be used directly,
/// but instead through the CodeGenFunction and RegionCounter types.
class CodeGenPGO {
@@ -138,8 +116,9 @@ private:
void setFuncName(llvm::Function *Fn);
void mapRegionCounters(const Decl *D);
void computeRegionCounts(const Decl *D);
- void applyFunctionAttributes(PGOProfileData *PGOData, llvm::Function *Fn);
- void loadRegionCounts(PGOProfileData *PGOData);
+ void applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader,
+ llvm::Function *Fn);
+ void loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader);
void emitCounterVariables();
llvm::GlobalVariable *buildDataVar();
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 27825ab85d..4b1c1c255a 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -1393,25 +1393,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
}
// Test whether the variable has completed initialization.
- llvm::Value *isInitialized;
-
- // ARM C++ ABI 3.2.3.1:
- // To support the potential use of initialization guard variables
- // as semaphores that are the target of ARM SWP and LDREX/STREX
- // synchronizing instructions we define a static initialization
- // guard variable to be a 4-byte aligned, 4- byte word with the
- // following inline access protocol.
- // #define INITIALIZED 1
- // if ((obj_guard & INITIALIZED) != INITIALIZED) {
- // if (__cxa_guard_acquire(&obj_guard))
- // ...
- // }
- if (UseARMGuardVarABI && !useInt8GuardVariable) {
- llvm::Value *V = Builder.CreateLoad(guard);
- llvm::Value *Test1 = llvm::ConstantInt::get(guardTy, 1);
- V = Builder.CreateAnd(V, Test1);
- isInitialized = Builder.CreateIsNull(V, "guard.uninitialized");
-
+ //
// Itanium C++ ABI 3.3.2:
// The following is pseudo-code showing how these functions can be used:
// if (obj_guard.first_byte == 0) {
@@ -1427,29 +1409,45 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// }
// }
- // ARM64 C++ ABI 3.2.2:
- // This ABI instead only specifies the value bit 0 of the static guard
- // variable; all other bits are platform defined. Bit 0 shall be 0 when the
- // variable is not initialized and 1 when it is.
- // FIXME: Reading one bit is no more efficient than reading one byte so
- // the codegen is same as generic Itanium ABI.
- } else {
- // Load the first byte of the guard variable.
- llvm::LoadInst *LI =
+ // Load the first byte of the guard variable.
+ llvm::LoadInst *LI =
Builder.CreateLoad(Builder.CreateBitCast(guard, CGM.Int8PtrTy));
- LI->setAlignment(1);
-
- // Itanium ABI:
- // An implementation supporting thread-safety on multiprocessor
- // systems must also guarantee that references to the initialized
- // object do not occur before the load of the initialization flag.
- //
- // In LLVM, we do this by marking the load Acquire.
- if (threadsafe)
- LI->setAtomic(llvm::Acquire);
-
- isInitialized = Builder.CreateIsNull(LI, "guard.uninitialized");
- }
+ LI->setAlignment(1);
+
+ // Itanium ABI:
+ // An implementation supporting thread-safety on multiprocessor
+ // systems must also guarantee that references to the initialized
+ // object do not occur before the load of the initialization flag.
+ //
+ // In LLVM, we do this by marking the load Acquire.
+ if (threadsafe)
+ LI->setAtomic(llvm::Acquire);
+
+ // For ARM, we should only check the first bit, rather than the entire byte:
+ //
+ // ARM C++ ABI 3.2.3.1:
+ // To support the potential use of initialization guard variables
+ // as semaphores that are the target of ARM SWP and LDREX/STREX
+ // synchronizing instructions we define a static initialization
+ // guard variable to be a 4-byte aligned, 4-byte word with the
+ // following inline access protocol.
+ // #define INITIALIZED 1
+ // if ((obj_guard & INITIALIZED) != INITIALIZED) {
+ // if (__cxa_guard_acquire(&obj_guard))
+ // ...
+ // }
+ //
+ // and similarly for ARM64:
+ //
+ // ARM64 C++ ABI 3.2.2:
+ // This ABI instead only specifies the value bit 0 of the static guard
+ // variable; all other bits are platform defined. Bit 0 shall be 0 when the
+ // variable is not initialized and 1 when it is.
+ llvm::Value *V =
+ (UseARMGuardVarABI && !useInt8GuardVariable)
+ ? Builder.CreateAnd(LI, llvm::ConstantInt::get(CGM.Int8Ty, 1))
+ : LI;
+ llvm::Value *isInitialized = Builder.CreateIsNull(V, "guard.uninitialized");
llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check");
llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 9832969b57..528cdf6238 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -1273,10 +1273,14 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::ConstantInt *Zero = llvm::ConstantInt::get(GuardTy, 0);
// Get the guard variable for this function if we have one already.
- GuardInfo &GI = GuardVariableMap[D.getDeclContext()];
+ GuardInfo EmptyGuardInfo;
+ GuardInfo *GI = &EmptyGuardInfo;
+ if (isa<FunctionDecl>(D.getDeclContext())) {
+ GI = &GuardVariableMap[D.getDeclContext()];
+ }
unsigned BitIndex;
- if (D.isExternallyVisible()) {
+ if (D.isStaticLocal() && D.isExternallyVisible()) {
// Externally visible variables have to be numbered in Sema to properly
// handle unreachable VarDecls.
BitIndex = getContext().getStaticLocalNumber(&D);
@@ -1284,18 +1288,18 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
BitIndex--;
} else {
// Non-externally visible variables are numbered here in CodeGen.
- BitIndex = GI.BitIndex++;
+ BitIndex = GI->BitIndex++;
}
if (BitIndex >= 32) {
if (D.isExternallyVisible())
ErrorUnsupportedABI(CGF, "more than 32 guarded initializations");
BitIndex %= 32;
- GI.Guard = 0;
+ GI->Guard = 0;
}
// Lazily create the i32 bitfield for this function.
- if (!GI.Guard) {
+ if (!GI->Guard) {
// Mangle the name for the guard.
SmallString<256> GuardName;
{
@@ -1306,11 +1310,12 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
// Create the guard variable with a zero-initializer. Just absorb linkage
// and visibility from the guarded variable.
- GI.Guard = new llvm::GlobalVariable(CGM.getModule(), GuardTy, false,
- GV->getLinkage(), Zero, GuardName.str());
- GI.Guard->setVisibility(GV->getVisibility());
+ GI->Guard =
+ new llvm::GlobalVariable(CGM.getModule(), GuardTy, false,
+ GV->getLinkage(), Zero, GuardName.str());
+ GI->Guard->setVisibility(GV->getVisibility());
} else {
- assert(GI.Guard->getLinkage() == GV->getLinkage() &&
+ assert(GI->Guard->getLinkage() == GV->getLinkage() &&
"static local from the same function had different linkage");
}
@@ -1322,7 +1327,7 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
// Test our bit from the guard variable.
llvm::ConstantInt *Bit = llvm::ConstantInt::get(GuardTy, 1U << BitIndex);
- llvm::LoadInst *LI = Builder.CreateLoad(GI.Guard);
+ llvm::LoadInst *LI = Builder.CreateLoad(GI->Guard);
llvm::Value *IsInitialized =
Builder.CreateICmpNE(Builder.CreateAnd(LI, Bit), Zero);
llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
@@ -1332,7 +1337,7 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
// Set our bit in the guard variable and emit the initializer and add a global
// destructor if appropriate.
CGF.EmitBlock(InitBlock);
- Builder.CreateStore(Builder.CreateOr(LI, Bit), GI.Guard);
+ Builder.CreateStore(Builder.CreateOr(LI, Bit), GI->Guard);
CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit);
Builder.CreateBr(EndBlock);
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index c602b1f1db..5819f104bf 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -1013,24 +1013,22 @@ void
X86_32ABIInfo::addFieldToArgStruct(SmallVector<llvm::Type *, 6> &FrameFields,
unsigned &StackOffset,
ABIArgInfo &Info, QualType Type) const {
+ assert(StackOffset % 4U == 0 && "unaligned inalloca struct");
+ Info = ABIArgInfo::getInAlloca(FrameFields.size());
+ FrameFields.push_back(CGT.ConvertTypeForMem(Type));
+ StackOffset += getContext().getTypeSizeInChars(Type).getQuantity();
+
// Insert padding bytes to respect alignment. For x86_32, each argument is 4
// byte aligned.
- unsigned Align = 4U;
- if (Info.getKind() == ABIArgInfo::Indirect && Info.getIndirectByVal())
- Align = std::max(Align, Info.getIndirectAlign());
- if (StackOffset & (Align - 1)) {
+ if (StackOffset % 4U) {
unsigned OldOffset = StackOffset;
- StackOffset = llvm::RoundUpToAlignment(StackOffset, Align);
+ StackOffset = llvm::RoundUpToAlignment(StackOffset, 4U);
unsigned NumBytes = StackOffset - OldOffset;
assert(NumBytes);
llvm::Type *Ty = llvm::Type::getInt8Ty(getVMContext());
Ty = llvm::ArrayType::get(Ty, NumBytes);
FrameFields.push_back(Ty);
}
-
- Info = ABIArgInfo::getInAlloca(FrameFields.size());
- FrameFields.push_back(CGT.ConvertTypeForMem(Type));
- StackOffset += getContext().getTypeSizeInChars(Type).getQuantity();
}
void X86_32ABIInfo::rewriteWithInAlloca(CGFunctionInfo &FI) const {
@@ -3160,7 +3158,7 @@ private:
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &AllocatedVFP,
bool &IsHA, unsigned &AllocatedGPR,
- bool &IsSmallAggr) const;
+ bool &IsSmallAggr, bool IsNamedArg) const;
bool isIllegalVectorType(QualType Ty) const;
virtual void computeInfo(CGFunctionInfo &FI) const {
@@ -3171,11 +3169,19 @@ private:
// and Floating-point Registers (with one register per member of the HFA or
// HVA). Otherwise, the NSRN is set to 8.
unsigned AllocatedVFP = 0;
+
// To correctly handle small aggregates, we need to keep track of the number
// of GPRs allocated so far. If the small aggregate can't all fit into
// registers, it will be on stack. We don't allow the aggregate to be
// partially in registers.
unsigned AllocatedGPR = 0;
+
+ // Find the number of named arguments. Variadic arguments get special
+ // treatment with the Darwin ABI.
+ unsigned NumRequiredArgs = (FI.isVariadic() ?
+ FI.getRequiredArgs().getNumRequiredArgs() :
+ FI.arg_size());
+
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
it != ie; ++it) {
@@ -3183,28 +3189,33 @@ private:
bool IsHA = false, IsSmallAggr = false;
const unsigned NumVFPs = 8;
const unsigned NumGPRs = 8;
+ bool IsNamedArg = ((it - FI.arg_begin()) <
+ static_cast<signed>(NumRequiredArgs));
it->info = classifyArgumentType(it->type, AllocatedVFP, IsHA,
- AllocatedGPR, IsSmallAggr);
+ AllocatedGPR, IsSmallAggr, IsNamedArg);
+
+ // Under AAPCS the 64-bit stack slot alignment means we can't pass HAs
+ // as sequences of floats since they'll get "holes" inserted as
+ // padding by the back end.
+ if (IsHA && AllocatedVFP > NumVFPs && !isDarwinPCS() &&
+ getContext().getTypeAlign(it->type) < 64) {
+ uint32_t NumStackSlots = getContext().getTypeSize(it->type);
+ NumStackSlots = llvm::RoundUpToAlignment(NumStackSlots, 64) / 64;
+
+ llvm::Type *CoerceTy = llvm::ArrayType::get(
+ llvm::Type::getDoubleTy(getVMContext()), NumStackSlots);
+ it->info = ABIArgInfo::getDirect(CoerceTy);
+ }
+
// If we do not have enough VFP registers for the HA, any VFP registers
// that are unallocated are marked as unavailable. To achieve this, we add
// padding of (NumVFPs - PreAllocation) floats.
if (IsHA && AllocatedVFP > NumVFPs && PreAllocation < NumVFPs) {
llvm::Type *PaddingTy = llvm::ArrayType::get(
llvm::Type::getFloatTy(getVMContext()), NumVFPs - PreAllocation);
- if (isDarwinPCS())
- it->info = ABIArgInfo::getExpandWithPadding(false, PaddingTy);
- else {
- // Under AAPCS the 64-bit stack slot alignment means we can't pass HAs
- // as sequences of floats since they'll get "holes" inserted as
- // padding by the back end.
- uint32_t NumStackSlots = getContext().getTypeSize(it->type);
- NumStackSlots = llvm::RoundUpToAlignment(NumStackSlots, 64) / 64;
-
- llvm::Type *CoerceTy = llvm::ArrayType::get(
- llvm::Type::getDoubleTy(getVMContext()), NumStackSlots);
- it->info = ABIArgInfo::getDirect(CoerceTy, 0, PaddingTy);
- }
+ it->info.setPaddingType(PaddingTy);
}
+
// If we do not have enough GPRs for the small aggregate, any GPR regs
// that are unallocated are marked as unavailable.
if (IsSmallAggr && AllocatedGPR > NumGPRs && PreGPR < NumGPRs) {
@@ -3252,7 +3263,8 @@ ABIArgInfo ARM64ABIInfo::classifyArgumentType(QualType Ty,
unsigned &AllocatedVFP,
bool &IsHA,
unsigned &AllocatedGPR,
- bool &IsSmallAggr) const {
+ bool &IsSmallAggr,
+ bool IsNamedArg) const {
// Handle illegal vector types here.
if (isIllegalVectorType(Ty)) {
uint64_t Size = getContext().getTypeSize(Ty);
@@ -3293,6 +3305,10 @@ ABIArgInfo ARM64ABIInfo::classifyArgumentType(QualType Ty,
Ty = EnumTy->getDecl()->getIntegerType();
if (!Ty->isFloatingType() && !Ty->isVectorType()) {
+ unsigned Alignment = getContext().getTypeAlign(Ty);
+ if (!isDarwinPCS() && Alignment > 64)
+ AllocatedGPR = llvm::RoundUpToAlignment(AllocatedGPR, Alignment / 64);
+
int RegsNeeded = getContext().getTypeSize(Ty) > 64 ? 2 : 1;
AllocatedGPR += RegsNeeded;
}
@@ -3322,20 +3338,31 @@ ABIArgInfo ARM64ABIInfo::classifyArgumentType(QualType Ty,
const Type *Base = 0;
uint64_t Members = 0;
if (isHomogeneousAggregate(Ty, Base, getContext(), &Members)) {
- AllocatedVFP += Members;
IsHA = true;
+ if (!IsNamedArg && isDarwinPCS()) {
+ // With the Darwin ABI, variadic arguments are always passed on the stack
+ // and should not be expanded. Treat variadic HFAs as arrays of doubles.
+ uint64_t Size = getContext().getTypeSize(Ty);
+ llvm::Type *BaseTy = llvm::Type::getDoubleTy(getVMContext());
+ return ABIArgInfo::getDirect(llvm::ArrayType::get(BaseTy, Size / 64));
+ }
+ AllocatedVFP += Members;
return ABIArgInfo::getExpand();
}
// Aggregates <= 16 bytes are passed directly in registers or on the stack.
uint64_t Size = getContext().getTypeSize(Ty);
if (Size <= 128) {
+ unsigned Alignment = getContext().getTypeAlign(Ty);
+ if (!isDarwinPCS() && Alignment > 64)
+ AllocatedGPR = llvm::RoundUpToAlignment(AllocatedGPR, Alignment / 64);
+
Size = 64 * ((Size + 63) / 64); // round up to multiple of 8 bytes
AllocatedGPR += Size / 64;
IsSmallAggr = true;
// We use a pair of i64 for 16-byte aggregate with 8-byte alignment.
// For aggregates with 16-byte alignment, we use i128.
- if (getContext().getTypeAlign(Ty) < 128 && Size == 128) {
+ if (Alignment < 128 && Size == 128) {
llvm::Type *BaseTy = llvm::Type::getInt64Ty(getVMContext());
return ABIArgInfo::getDirect(llvm::ArrayType::get(BaseTy, Size / 64));
}
@@ -3359,8 +3386,9 @@ ABIArgInfo ARM64ABIInfo::classifyReturnType(QualType RetTy) const {
if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
RetTy = EnumTy->getDecl()->getIntegerType();
- return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend()
- : ABIArgInfo::getDirect());
+ return (RetTy->isPromotableIntegerType() && isDarwinPCS()
+ ? ABIArgInfo::getExtend()
+ : ABIArgInfo::getDirect());
}
// Structures with either a non-trivial destructor or a non-trivial
@@ -3454,7 +3482,7 @@ static llvm::Value *EmitAArch64VAArg(llvm::Value *VAListAddr, QualType Ty,
CGF.Builder.CreateCondBr(UsingStack, OnStackBlock, MaybeRegBlock);
// Otherwise, at least some kind of argument could go in these registers, the
- // quesiton is whether this particular type is too big.
+ // question is whether this particular type is too big.
CGF.EmitBlock(MaybeRegBlock);
// Integer arguments may need to correct register alignment (for example a
@@ -3631,8 +3659,8 @@ llvm::Value *ARM64ABIInfo::EmitAAPCSVAArg(llvm::Value *VAListAddr, QualType Ty,
unsigned AllocatedGPR = 0, AllocatedVFP = 0;
bool IsHA = false, IsSmallAggr = false;
- ABIArgInfo AI =
- classifyArgumentType(Ty, AllocatedVFP, IsHA, AllocatedGPR, IsSmallAggr);
+ ABIArgInfo AI = classifyArgumentType(Ty, AllocatedVFP, IsHA, AllocatedGPR,
+ IsSmallAggr, false /*IsNamedArg*/);
return EmitAArch64VAArg(VAListAddr, Ty, AllocatedGPR, AllocatedVFP,
AI.isIndirect(), CGF);
@@ -4761,7 +4789,9 @@ public:
void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &M) const override;
private:
- static void addKernelMetadata(llvm::Function *F);
+ // Adds a NamedMDNode with F, Name, and Operand as operands, and adds the
+ // resulting MDNode to the nvvm.annotations MDNode.
+ static void addNVVMMetadata(llvm::Function *F, StringRef Name, int Operand);
};
ABIArgInfo NVPTXABIInfo::classifyReturnType(QualType RetTy) const {
@@ -4820,7 +4850,8 @@ SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
// By default, all functions are device functions
if (FD->hasAttr<OpenCLKernelAttr>()) {
// OpenCL __kernel functions get kernel metadata
- addKernelMetadata(F);
+ // Create !{<func-ref>, metadata !"kernel", i32 1} node
+ addNVVMMetadata(F, "kernel", 1);
// And kernel functions are not subject to inlining
F->addFnAttr(llvm::Attribute::NoInline);
}
@@ -4831,28 +4862,41 @@ SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
// CUDA __global__ functions get a kernel metadata entry. Since
// __global__ functions cannot be called from the device, we do not
// need to set the noinline attribute.
- if (FD->hasAttr<CUDAGlobalAttr>())
- addKernelMetadata(F);
+ if (FD->hasAttr<CUDAGlobalAttr>()) {
+ // Create !{<func-ref>, metadata !"kernel", i32 1} node
+ addNVVMMetadata(F, "kernel", 1);
+ }
+ if (FD->hasAttr<CUDALaunchBoundsAttr>()) {
+ // Create !{<func-ref>, metadata !"maxntidx", i32 <val>} node
+ addNVVMMetadata(F, "maxntidx",
+ FD->getAttr<CUDALaunchBoundsAttr>()->getMaxThreads());
+ // min blocks is a default argument for CUDALaunchBoundsAttr, so getting a
+ // zero value from getMinBlocks either means it was not specified in
+ // __launch_bounds__ or the user specified a 0 value. In both cases, we
+ // don't have to add a PTX directive.
+ int MinCTASM = FD->getAttr<CUDALaunchBoundsAttr>()->getMinBlocks();
+ if (MinCTASM > 0) {
+ // Create !{<func-ref>, metadata !"minctasm", i32 <val>} node
+ addNVVMMetadata(F, "minctasm", MinCTASM);
+ }
+ }
}
}
-void NVPTXTargetCodeGenInfo::addKernelMetadata(llvm::Function *F) {
+void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::Function *F, StringRef Name,
+ int Operand) {
llvm::Module *M = F->getParent();
llvm::LLVMContext &Ctx = M->getContext();
// Get "nvvm.annotations" metadata node
llvm::NamedMDNode *MD = M->getOrInsertNamedMetadata("nvvm.annotations");
- // Create !{<func-ref>, metadata !"kernel", i32 1} node
- llvm::SmallVector<llvm::Value *, 3> MDVals;
- MDVals.push_back(F);
- MDVals.push_back(llvm::MDString::get(Ctx, "kernel"));
- MDVals.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), 1));
-
+ llvm::Value *MDVals[] = {
+ F, llvm::MDString::get(Ctx, Name),
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), Operand)};
// Append metadata to nvvm.annotations
MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
}
-
}
//===----------------------------------------------------------------------===//
@@ -6135,7 +6179,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::mips64el:
return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, false));
- case llvm::Triple::arm64: {
+ case llvm::Triple::arm64:
+ case llvm::Triple::arm64_be: {
ARM64ABIInfo::ABIKind Kind = ARM64ABIInfo::AAPCS;
if (strcmp(getTarget().getABI(), "darwinpcs") == 0)
Kind = ARM64ABIInfo::DarwinPCS;
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 317b822095..be83713b60 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -1862,18 +1862,28 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple,
}
}
- // Handle pseudo-target flags '-EL' and '-EB'.
- if (Arg *A = Args.getLastArg(options::OPT_EL, options::OPT_EB)) {
- if (A->getOption().matches(options::OPT_EL)) {
+ // Handle pseudo-target flags '-mlittle-endian'/'-EL' and
+ // '-mbig-endian'/'-EB'.
+ if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian,
+ options::OPT_mbig_endian)) {
+ if (A->getOption().matches(options::OPT_mlittle_endian)) {
if (Target.getArch() == llvm::Triple::mips)
Target.setArch(llvm::Triple::mipsel);
else if (Target.getArch() == llvm::Triple::mips64)
Target.setArch(llvm::Triple::mips64el);
+ else if (Target.getArch() == llvm::Triple::aarch64_be)
+ Target.setArch(llvm::Triple::aarch64);
+ else if (Target.getArch() == llvm::Triple::arm64_be)
+ Target.setArch(llvm::Triple::arm64);
} else {
if (Target.getArch() == llvm::Triple::mipsel)
Target.setArch(llvm::Triple::mips);
else if (Target.getArch() == llvm::Triple::mips64el)
Target.setArch(llvm::Triple::mips64);
+ else if (Target.getArch() == llvm::Triple::aarch64)
+ Target.setArch(llvm::Triple::aarch64_be);
+ else if (Target.getArch() == llvm::Triple::arm64)
+ Target.setArch(llvm::Triple::arm64_be);
}
}
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 2775d892f7..e5292719df 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -62,7 +62,8 @@ static int skipArgs(const char *Flag) {
// These flags are treated as a single argument (e.g., -F<Dir>).
StringRef FlagRef(Flag);
- if (FlagRef.startswith("-F") || FlagRef.startswith("-I"))
+ if (FlagRef.startswith("-F") || FlagRef.startswith("-I") ||
+ FlagRef.startswith("-fmodules-cache-path="))
return 1;
return 0;
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index d164edd734..eefe487b32 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -205,6 +205,16 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
bool IsBigEndian = getTriple().getArch() == llvm::Triple::armeb ||
getTriple().getArch() == llvm::Triple::thumbeb;
+ // Handle pseudo-target flags '-mlittle-endian'/'-EL' and
+ // '-mbig-endian'/'-EB'.
+ if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian,
+ options::OPT_mbig_endian)) {
+ if (A->getOption().matches(options::OPT_mlittle_endian))
+ IsBigEndian = false;
+ else
+ IsBigEndian = true;
+ }
+
// Thumb2 is the default for V7 on Darwin.
//
// FIXME: Thumb should just be another -target-feaure, not in the triple.
@@ -214,6 +224,9 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
bool ThumbDefault = Suffix.startswith("v6m") || Suffix.startswith("v7m") ||
Suffix.startswith("v7em") ||
(Suffix.startswith("v7") && getTriple().isOSBinFormatMachO());
+ // FIXME: this is invalid for WindowsCE
+ if (getTriple().isOSWindows())
+ ThumbDefault = true;
std::string ArchName;
if (IsBigEndian)
ArchName = "armeb";
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index c1f7cccaac..9465be8778 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -1322,7 +1322,8 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
// lifetime or initialization issues.
static const char *const AArch64LibDirs[] = { "/lib" };
static const char *const AArch64Triples[] = { "aarch64-none-linux-gnu",
- "aarch64-linux-gnu" };
+ "aarch64-linux-gnu",
+ "aarch64-linux-android" };
static const char *const AArch64beLibDirs[] = { "/lib" };
static const char *const AArch64beTriples[] = { "aarch64_be-none-linux-gnu",
"aarch64_be-linux-gnu" };
@@ -1409,6 +1410,7 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
BiarchTripleAliases.append(
AArch64Triples, AArch64Triples + llvm::array_lengthof(AArch64Triples));
break;
+ case llvm::Triple::arm64_be:
case llvm::Triple::aarch64_be:
LibDirs.append(AArch64beLibDirs,
AArch64beLibDirs + llvm::array_lengthof(AArch64beLibDirs));
@@ -2104,6 +2106,7 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const {
getTriple().getArch() == llvm::Triple::aarch64 ||
getTriple().getArch() == llvm::Triple::aarch64_be ||
getTriple().getArch() == llvm::Triple::arm64 ||
+ getTriple().getArch() == llvm::Triple::arm64_be ||
getTriple().getArch() == llvm::Triple::arm ||
getTriple().getArch() == llvm::Triple::armeb ||
getTriple().getArch() == llvm::Triple::thumb ||
@@ -2117,6 +2120,7 @@ void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs,
getTriple().getArch() == llvm::Triple::aarch64 ||
getTriple().getArch() == llvm::Triple::aarch64_be ||
getTriple().getArch() == llvm::Triple::arm64 ||
+ getTriple().getArch() == llvm::Triple::arm64_be ||
(getTriple().getOS() == llvm::Triple::Linux &&
(!V.isOlderThan(4, 7, 0) ||
getTriple().getEnvironment() == llvm::Triple::Android));
@@ -2566,6 +2570,9 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
else if (tools::mips::hasMipsAbiArg(Args, "64"))
getFilePaths().push_back("=/usr/lib/64");
break;
+ case llvm::Triple::sparc:
+ getFilePaths().push_back("=/usr/lib/sparc");
+ break;
default:
break;
}
@@ -2860,6 +2867,7 @@ static std::string getMultiarchTriple(const llvm::Triple &TargetTriple,
if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64-linux-gnu"))
return "aarch64-linux-gnu";
return TargetTriple.str();
+ case llvm::Triple::arm64_be:
case llvm::Triple::aarch64_be:
if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64_be-linux-gnu"))
return "aarch64_be-linux-gnu";
@@ -3234,7 +3242,8 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
MultiarchIncludeDirs = X86MultiarchIncludeDirs;
} else if (getTriple().getArch() == llvm::Triple::aarch64 ||
getTriple().getArch() == llvm::Triple::aarch64_be ||
- getTriple().getArch() == llvm::Triple::arm64) {
+ getTriple().getArch() == llvm::Triple::arm64 ||
+ getTriple().getArch() == llvm::Triple::arm64_be) {
MultiarchIncludeDirs = AArch64MultiarchIncludeDirs;
} else if (getTriple().getArch() == llvm::Triple::arm) {
if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 6acc3d5f58..a8d3f010bd 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -473,8 +473,13 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
case llvm::Triple::arm64:
+ case llvm::Triple::arm64_be:
case llvm::Triple::arm:
case llvm::Triple::armeb:
+ if (Triple.isOSDarwin() || Triple.isOSWindows())
+ return true;
+ return false;
+
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
if (Triple.isOSDarwin())
@@ -645,6 +650,11 @@ StringRef tools::arm::getARMFloatABI(const Driver &D, const ArgList &Args,
break;
}
+ // FIXME: this is invalid for WindowsCE
+ case llvm::Triple::Win32:
+ FloatABI = "hard";
+ break;
+
case llvm::Triple::FreeBSD:
switch(Triple.getEnvironment()) {
case llvm::Triple::GNUEABIHF:
@@ -772,6 +782,9 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
} else {
ABIName = "apcs-gnu";
}
+ } else if (Triple.isOSWindows()) {
+ // FIXME: this is invalid for WindowsCE
+ ABIName = "aapcs";
} else {
// Select the default based on the platform.
switch(Triple.getEnvironment()) {
@@ -863,8 +876,12 @@ static std::string getARM64TargetCPU(const ArgList &Args) {
// At some point, we may need to check -march here, but for now we only
// one arm64 architecture.
- // Default to "cyclone" CPU.
- return "cyclone";
+ // Make sure we pick "cyclone" if -arch is used.
+ // FIXME: Should this be picked by checking the target triple instead?
+ if (Args.getLastArg(options::OPT_arch))
+ return "cyclone";
+
+ return "generic";
}
void Clang::AddARM64TargetArgs(const ArgList &Args,
@@ -1324,6 +1341,10 @@ static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) {
case llvm::Triple::aarch64_be:
return getAArch64TargetCPU(Args, T);
+ case llvm::Triple::arm64:
+ case llvm::Triple::arm64_be:
+ return getARM64TargetCPU(Args);
+
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
@@ -1552,6 +1573,8 @@ static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple,
break;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
+ case llvm::Triple::arm64:
+ case llvm::Triple::arm64_be:
getAArch64TargetFeatures(D, Args, Features);
break;
case llvm::Triple::x86:
@@ -2198,6 +2221,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
CmdArgs.push_back(Args.MakeArgString(TripleStr));
+ const llvm::Triple TT(TripleStr);
+ if (TT.isOSWindows() && (TT.getArch() == llvm::Triple::arm ||
+ TT.getArch() == llvm::Triple::thumb)) {
+ unsigned Offset = TT.getArch() == llvm::Triple::arm ? 4 : 6;
+ unsigned Version;
+ TT.getArchName().substr(Offset).getAsInteger(10, Version);
+ if (Version < 7)
+ D.Diag(diag::err_target_unsupported_arch) << TT.getArchName() << TripleStr;
+ }
+
// Push all default warning arguments that are specific to
// the given target. These come before user provided warning options
// are provided.
@@ -2486,8 +2519,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// enabled. This alias option is being used to simplify the hasFlag logic.
OptSpecifier StrictAliasingAliasOption = OFastEnabled ? options::OPT_Ofast :
options::OPT_fstrict_aliasing;
+ // We turn strict aliasing off by default if we're in CL mode, since MSVC
+ // doesn't do any TBAA.
+ bool TBAAOnByDefault = !getToolChain().getDriver().IsCLMode();
if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption,
- options::OPT_fno_strict_aliasing, true))
+ options::OPT_fno_strict_aliasing, TBAAOnByDefault))
CmdArgs.push_back("-relaxed-aliasing");
if (!Args.hasFlag(options::OPT_fstruct_path_tbaa,
options::OPT_fno_struct_path_tbaa))
@@ -2732,6 +2768,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
break;
case llvm::Triple::arm64:
+ case llvm::Triple::arm64_be:
AddARM64TargetArgs(Args, CmdArgs);
break;
@@ -3387,6 +3424,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
A->render(Args, CmdArgs);
}
+ if (Arg *A = Args.getLastArg(options::OPT_Rpass_EQ))
+ A->render(Args, CmdArgs);
+
if (Args.hasArg(options::OPT_mkernel)) {
if (!Args.hasArg(options::OPT_fapple_kext) && types::isCXX(InputType))
CmdArgs.push_back("-fapple-kext");
@@ -3444,6 +3484,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fmodules-decluse");
}
+ // -fmodules-strict-decluse is like -fmodule-decluse, but also checks that
+ // all #included headers are part of modules.
+ if (Args.hasFlag(options::OPT_fmodules_strict_decluse,
+ options::OPT_fno_modules_strict_decluse,
+ false)) {
+ CmdArgs.push_back("-fmodules-strict-decluse");
+ }
+
// -fmodule-name specifies the module that is currently being built (or
// used for header checking by -fmodule-maps).
if (Arg *A = Args.getLastArg(options::OPT_fmodule_name)) {
@@ -3864,9 +3912,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_vectorize, EnableVec))
CmdArgs.push_back("-vectorize-loops");
- // -fslp-vectorize is default.
- if (Args.hasFlag(options::OPT_fslp_vectorize,
- options::OPT_fno_slp_vectorize, true))
+ // -fslp-vectorize is enabled based on the optimization level selected.
+ OptSpecifier SLPVectAliasOption = EnableVec ? options::OPT_O_Group :
+ options::OPT_fslp_vectorize;
+ if (Args.hasFlag(options::OPT_fslp_vectorize, SLPVectAliasOption,
+ options::OPT_fno_slp_vectorize, EnableVec))
CmdArgs.push_back("-vectorize-slp");
// -fno-slp-vectorize-aggressive is default.
@@ -4018,7 +4068,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Finally add the compile command to the compilation.
if (Args.hasArg(options::OPT__SLASH_fallback) &&
- Output.getType() == types::TY_Object) {
+ Output.getType() == types::TY_Object &&
+ (InputType == types::TY_C || InputType == types::TY_CXX)) {
tools::visualstudio::Compile CL(getToolChain());
Command *CLCommand = CL.GetCommand(C, JA, Output, Inputs, Args,
LinkingOutput);
@@ -4232,12 +4283,6 @@ void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
if (!Args.hasArg(options::OPT_frtti, options::OPT_fno_rtti))
CmdArgs.push_back("-fno-rtti");
- // Let -ffunction-sections imply -fdata-sections.
- if (Arg * A = Args.getLastArg(options::OPT_ffunction_sections,
- options::OPT_fno_function_sections))
- if (A->getOption().matches(options::OPT_ffunction_sections))
- CmdArgs.push_back("-fdata-sections");
-
const Driver &D = getToolChain().getDriver();
Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg);
Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb);
@@ -4835,9 +4880,16 @@ const char *arm::getARMCPUForMArch(const ArgList &Args,
}
}
- if (Triple.getOS() == llvm::Triple::NetBSD) {
+ switch (Triple.getOS()) {
+ case llvm::Triple::NetBSD:
if (MArch == "armv6")
return "arm1176jzf-s";
+ break;
+ case llvm::Triple::Win32:
+ // FIXME: this is invalid for WindowsCE
+ return "cortex-a9";
+ default:
+ break;
}
const char *result = llvm::StringSwitch<const char *>(MArch)
@@ -6802,7 +6854,8 @@ static StringRef getLinuxDynamicLinker(const ArgList &Args,
else if (ToolChain.getArch() == llvm::Triple::aarch64 ||
ToolChain.getArch() == llvm::Triple::arm64)
return "/lib/ld-linux-aarch64.so.1";
- else if (ToolChain.getArch() == llvm::Triple::aarch64_be)
+ else if (ToolChain.getArch() == llvm::Triple::aarch64_be ||
+ ToolChain.getArch() == llvm::Triple::arm64_be)
return "/lib/ld-linux-aarch64_be.so.1";
else if (ToolChain.getArch() == llvm::Triple::arm ||
ToolChain.getArch() == llvm::Triple::thumb) {
@@ -6903,7 +6956,8 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
else if (ToolChain.getArch() == llvm::Triple::aarch64 ||
ToolChain.getArch() == llvm::Triple::arm64)
CmdArgs.push_back("aarch64linux");
- else if (ToolChain.getArch() == llvm::Triple::aarch64_be)
+ else if (ToolChain.getArch() == llvm::Triple::aarch64_be ||
+ ToolChain.getArch() == llvm::Triple::arm64_be)
CmdArgs.push_back("aarch64_be_linux");
else if (ToolChain.getArch() == llvm::Triple::arm
|| ToolChain.getArch() == llvm::Triple::thumb)
@@ -7384,6 +7438,10 @@ void visualstudio::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-nologo");
+ if (Args.hasArg(options::OPT_g_Group)) {
+ CmdArgs.push_back("-debug");
+ }
+
bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd);
if (DLL) {
@@ -7509,6 +7567,10 @@ Command *visualstudio::Compile::GetCommand(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getOption().getID() == options::OPT_ffunction_sections
? "/Gy"
: "/Gy-");
+ if (Arg *A = Args.getLastArg(options::OPT_fdata_sections,
+ options::OPT_fno_data_sections))
+ CmdArgs.push_back(
+ A->getOption().getID() == options::OPT_fdata_sections ? "/Gw" : "/Gw-");
if (Args.hasArg(options::OPT_fsyntax_only))
CmdArgs.push_back("/Zs");
if (Args.hasArg(options::OPT_g_Flag, options::OPT_gline_tables_only))
diff --git a/lib/Driver/WindowsToolChain.cpp b/lib/Driver/WindowsToolChain.cpp
index a32a7bfe07..cd6d7e16fc 100644
--- a/lib/Driver/WindowsToolChain.cpp
+++ b/lib/Driver/WindowsToolChain.cpp
@@ -297,17 +297,12 @@ void Windows::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// Honor %INCLUDE%. It should know essential search paths with vcvarsall.bat.
if (const char *cl_include_dir = getenv("INCLUDE")) {
SmallVector<StringRef, 8> Dirs;
- StringRef(cl_include_dir).split(Dirs, ";");
- int n = 0;
- for (SmallVectorImpl<StringRef>::iterator I = Dirs.begin(), E = Dirs.end();
- I != E; ++I) {
- StringRef d = *I;
- if (d.size() == 0)
- continue;
- ++n;
- addSystemInclude(DriverArgs, CC1Args, d);
- }
- if (n) return;
+ StringRef(cl_include_dir)
+ .split(Dirs, ";", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ for (StringRef Dir : Dirs)
+ addSystemInclude(DriverArgs, CC1Args, Dir);
+ if (!Dirs.empty())
+ return;
}
std::string VSDir;
@@ -316,12 +311,19 @@ void Windows::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// When built with access to the proper Windows APIs, try to actually find
// the correct include paths first.
if (getVisualStudioDir(VSDir)) {
- addSystemInclude(DriverArgs, CC1Args, VSDir + "\\VC\\include");
- if (getWindowsSDKDir(WindowsSDKDir))
- addSystemInclude(DriverArgs, CC1Args, WindowsSDKDir + "\\include");
- else
- addSystemInclude(DriverArgs, CC1Args,
- VSDir + "\\VC\\PlatformSDK\\Include");
+ SmallString<128> P;
+ P = VSDir;
+ llvm::sys::path::append(P, "VC\\include");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ if (getWindowsSDKDir(WindowsSDKDir)) {
+ P = WindowsSDKDir;
+ llvm::sys::path::append(P, "include");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ } else {
+ P = VSDir;
+ llvm::sys::path::append(P, "VC\\PlatformSDK\\Include");
+ addSystemInclude(DriverArgs, CC1Args, P.str());
+ }
return;
}
diff --git a/lib/Edit/Commit.cpp b/lib/Edit/Commit.cpp
index 706c732dba..9c08cc28ac 100644
--- a/lib/Edit/Commit.cpp
+++ b/lib/Edit/Commit.cpp
@@ -38,9 +38,7 @@ CharSourceRange Commit::Edit::getInsertFromRange(SourceManager &SM) const {
Commit::Commit(EditedSource &Editor)
: SourceMgr(Editor.getSourceManager()), LangOpts(Editor.getLangOpts()),
PPRec(Editor.getPPCondDirectiveRecord()),
- Editor(&Editor),
- ForceCommitInSystemHeader(Editor.getForceCommitInSystemHeader()),
- IsCommitable(true) { }
+ Editor(&Editor), IsCommitable(true) { }
bool Commit::insert(SourceLocation loc, StringRef text,
bool afterToken, bool beforePreviousInsertions) {
@@ -234,7 +232,7 @@ bool Commit::canInsert(SourceLocation loc, FileOffset &offs) {
if (!isAtStartOfMacroExpansion(loc, &loc))
return false;
- if (SM.isInSystemHeader(loc) && ForceCommitInSystemHeader)
+ if (SM.isInSystemHeader(loc))
return false;
std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
@@ -265,7 +263,7 @@ bool Commit::canInsertAfterToken(SourceLocation loc, FileOffset &offs,
if (!isAtEndOfMacroExpansion(loc, &loc))
return false;
- if (SM.isInSystemHeader(loc) && ForceCommitInSystemHeader)
+ if (SM.isInSystemHeader(loc))
return false;
loc = Lexer::getLocForEndOfToken(loc, 0, SourceMgr, LangOpts);
@@ -303,8 +301,8 @@ bool Commit::canRemoveRange(CharSourceRange range,
if (range.getBegin().isMacroID() || range.getEnd().isMacroID())
return false;
- if ((SM.isInSystemHeader(range.getBegin()) ||
- SM.isInSystemHeader(range.getEnd())) && ForceCommitInSystemHeader)
+ if (SM.isInSystemHeader(range.getBegin()) ||
+ SM.isInSystemHeader(range.getEnd()))
return false;
if (PPRec && PPRec->rangeIntersectsConditionalDirective(range.getAsRange()))
diff --git a/lib/Format/BreakableToken.cpp b/lib/Format/BreakableToken.cpp
index d43a774c9c..93cca66634 100644
--- a/lib/Format/BreakableToken.cpp
+++ b/lib/Format/BreakableToken.cpp
@@ -13,8 +13,6 @@
///
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "format-token-breaker"
-
#include "BreakableToken.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Format/Format.h"
@@ -22,6 +20,8 @@
#include "llvm/Support/Debug.h"
#include <algorithm>
+#define DEBUG_TYPE "format-token-breaker"
+
namespace clang {
namespace format {
@@ -350,10 +350,9 @@ void BreakableBlockComment::adjustWhitespace(unsigned LineIndex,
Lines[LineIndex].begin() - Lines[LineIndex - 1].end();
// Adjust the start column uniformly across all lines.
- StartOfLineColumn[LineIndex] = std::max<int>(
- 0,
+ StartOfLineColumn[LineIndex] =
encoding::columnWidthWithTabs(Whitespace, 0, Style.TabWidth, Encoding) +
- IndentDelta);
+ IndentDelta;
}
unsigned BreakableBlockComment::getLineCount() const { return Lines.size(); }
@@ -437,7 +436,6 @@ BreakableBlockComment::replaceWhitespaceBefore(unsigned LineIndex,
unsigned WhitespaceOffsetInToken = Lines[LineIndex].data() -
Tok.TokenText.data() -
LeadingWhitespace[LineIndex];
- assert(StartOfLineColumn[LineIndex] >= Prefix.size());
Whitespaces.replaceWhitespaceInToken(
Tok, WhitespaceOffsetInToken, LeadingWhitespace[LineIndex], "", Prefix,
InPPDirective, 1, IndentLevel,
@@ -450,7 +448,7 @@ BreakableBlockComment::getContentStartColumn(unsigned LineIndex,
// If we break, we always break at the predefined indent.
if (TailOffset != 0)
return IndentAtLineBreak;
- return StartOfLineColumn[LineIndex];
+ return std::max(0, StartOfLineColumn[LineIndex]);
}
} // namespace format
diff --git a/lib/Format/BreakableToken.h b/lib/Format/BreakableToken.h
index e294a50580..72bb1e4404 100644
--- a/lib/Format/BreakableToken.h
+++ b/lib/Format/BreakableToken.h
@@ -212,7 +212,7 @@ private:
// StartOfLineColumn[i] is the target column at which Line[i] should be.
// Note that this excludes a leading "* " or "*" in case all lines have
// a "*" prefix.
- SmallVector<unsigned, 16> StartOfLineColumn;
+ SmallVector<int, 16> StartOfLineColumn;
// The column at which the text of a broken line should start.
// Note that an optional decoration would go before that column.
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index 5a3dee6387..445fc41ad2 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -12,8 +12,6 @@
///
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "format-formatter"
-
#include "BreakableToken.h"
#include "ContinuationIndenter.h"
#include "WhitespaceManager.h"
@@ -23,6 +21,8 @@
#include "llvm/Support/Debug.h"
#include <string>
+#define DEBUG_TYPE "format-formatter"
+
namespace clang {
namespace format {
@@ -142,10 +142,11 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
return true;
if (((Previous.Type == TT_DictLiteral && Previous.is(tok::l_brace)) ||
Previous.Type == TT_ArrayInitializerLSquare) &&
+ Style.ColumnLimit > 0 &&
getLengthToMatchingParen(Previous) + State.Column > getColumnLimit(State))
return true;
if (Current.Type == TT_CtorInitializerColon &&
- (!Style.AllowShortFunctionsOnASingleLine ||
+ ((Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All) ||
Style.BreakConstructorInitializersBeforeComma || Style.ColumnLimit != 0))
return true;
@@ -173,8 +174,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
if (Previous.Type == TT_BinaryOperator &&
(!IsComparison || LHSIsBinaryExpr) &&
Current.Type != TT_BinaryOperator && // For >>.
- !Current.isTrailingComment() &&
- !Previous.isOneOf(tok::lessless, tok::question) &&
+ !Current.isTrailingComment() && !Previous.is(tok::lessless) &&
Previous.getPrecedence() != prec::Assignment &&
State.Stack.back().BreakBeforeParameter)
return true;
@@ -301,7 +301,9 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
else if ((Previous.Type == TT_BinaryOperator ||
Previous.Type == TT_ConditionalExpr ||
Previous.Type == TT_CtorInitializerColon) &&
- (Previous.getPrecedence() != prec::Assignment ||
+ ((Previous.getPrecedence() != prec::Assignment &&
+ (Previous.isNot(tok::lessless) || Previous.OperatorIndex != 0 ||
+ !Previous.LastOperator)) ||
Current.StartsBinaryExpression))
// Always indent relative to the RHS of the expression unless this is a
// simple assignment without binary expression on the RHS. Also indent
@@ -472,6 +474,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
else
return State.FirstIndent;
}
+ if (Current.is(tok::identifier) && Current.Next &&
+ Current.Next->Type == TT_DictLiteral)
+ return State.Stack.back().Indent;
if (NextNonComment->isStringLiteral() && State.StartOfStringLiteral != 0)
return State.StartOfStringLiteral;
if (NextNonComment->is(tok::lessless) &&
@@ -485,7 +490,8 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
}
}
if (State.Stack.back().QuestionColumn != 0 &&
- (NextNonComment->Type == TT_ConditionalExpr ||
+ ((NextNonComment->is(tok::colon) &&
+ NextNonComment->Type == TT_ConditionalExpr) ||
Previous.Type == TT_ConditionalExpr))
return State.Stack.back().QuestionColumn;
if (Previous.is(tok::comma) && State.Stack.back().VariablePos != 0)
@@ -547,9 +553,15 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
if (Current.Type == TT_InheritanceColon)
State.Stack.back().AvoidBinPacking = true;
- if (Current.is(tok::lessless) && Current.Type != TT_OverloadedOperator &&
- State.Stack.back().FirstLessLess == 0)
- State.Stack.back().FirstLessLess = State.Column;
+ if (Current.is(tok::lessless) && Current.Type != TT_OverloadedOperator) {
+ if (State.Stack.back().FirstLessLess == 0)
+ State.Stack.back().FirstLessLess = State.Column;
+ else
+ State.Stack.back().LastOperatorWrapped = Newline;
+ }
+ if ((Current.Type == TT_BinaryOperator && Current.isNot(tok::lessless)) ||
+ Current.Type == TT_ConditionalExpr)
+ State.Stack.back().LastOperatorWrapped = Newline;
if (Current.Type == TT_ArraySubscriptLSquare &&
State.Stack.back().StartOfArraySubscripts == 0)
State.Stack.back().StartOfArraySubscripts = State.Column;
@@ -563,9 +575,11 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
std::min(State.LowestLevelOnLine, State.ParenLevel);
if (Current.isMemberAccess())
State.Stack.back().StartOfFunctionCall =
- Current.LastInChainOfCalls ? 0 : State.Column + Current.ColumnWidth;
+ Current.LastOperator ? 0 : State.Column + Current.ColumnWidth;
if (Current.Type == TT_ObjCSelectorName)
State.Stack.back().ObjCSelectorNameFound = true;
+ if (Current.Type == TT_LambdaLSquare)
+ ++State.Stack.back().LambdasFound;
if (Current.Type == TT_CtorInitializerColon) {
// Indent 2 from the column, so:
// SomeClass::SomeClass()
@@ -613,13 +627,19 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
// there is a line-break right after the operator.
// Exclude relational operators, as there, it is always more desirable to
// have the LHS 'left' of the RHS.
- // FIXME: Implement this for '<<' and BreakBeforeBinaryOperators.
- if (!Newline && Previous && Previous->Type == TT_BinaryOperator &&
- !Previous->isOneOf(tok::lessless, tok::question, tok::colon) &&
- Previous->getPrecedence() > prec::Assignment &&
- Previous->getPrecedence() != prec::Relational &&
- !Style.BreakBeforeBinaryOperators)
- NewParenState.NoLineBreak = true;
+ if (Previous && Previous->getPrecedence() > prec::Assignment &&
+ (Previous->Type == TT_BinaryOperator ||
+ Previous->Type == TT_ConditionalExpr) &&
+ Previous->getPrecedence() != prec::Relational) {
+ bool BreakBeforeOperator = Previous->is(tok::lessless) ||
+ (Previous->Type == TT_BinaryOperator &&
+ Style.BreakBeforeBinaryOperators) ||
+ (Previous->Type == TT_ConditionalExpr &&
+ Style.BreakBeforeTernaryOperators);
+ if ((!Newline && !BreakBeforeOperator) ||
+ (!State.Stack.back().LastOperatorWrapped && BreakBeforeOperator))
+ NewParenState.NoLineBreak = true;
+ }
// Do not indent relative to the fake parentheses inserted for "." or "->".
// This is a special case to make the following to statements consistent:
@@ -654,7 +674,8 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
bool BreakBeforeParameter = false;
if (Current.is(tok::l_brace) ||
Current.Type == TT_ArrayInitializerLSquare) {
- if (Current.MatchingParen && Current.BlockKind == BK_Block) {
+ if (Current.MatchingParen && Current.BlockKind == BK_Block &&
+ State.Stack.back().LambdasFound <= 1) {
// If this is an l_brace starting a nested block, we pretend (wrt. to
// indentation) that we already consumed the corresponding r_brace.
// Thus, we remove all ParenStates caused by fake parentheses that end
@@ -670,6 +691,10 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
// SomeFunction(a, [] {
// f(); // break
// });
+ //
+ // If we have already found more than one lambda introducers on this
+ // level, we opt out of this because similarity between the lambdas is
+ // more important.
for (unsigned i = 0; i != Current.MatchingParen->FakeRParens; ++i) {
assert(State.Stack.size() > 1);
if (State.Stack.size() == 1) {
@@ -700,6 +725,7 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State,
AvoidBinPacking = Current.BlockKind == BK_Block ||
Current.Type == TT_ArrayInitializerLSquare ||
Current.Type == TT_DictLiteral ||
+ !Style.BinPackParameters ||
(NextNoComment &&
NextNoComment->Type == TT_DesignatedInitializerPeriod);
} else {
@@ -938,6 +964,12 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
break;
}
+ // When breaking before a tab character, it may be moved by a few columns,
+ // but will still be expanded to the next tab stop, so we don't save any
+ // columns.
+ if (NewRemainingTokenColumns == RemainingTokenColumns)
+ break;
+
assert(NewRemainingTokenColumns < RemainingTokenColumns);
if (!DryRun)
Token->insertBreak(LineIndex, TailOffset, Split, Whitespaces);
diff --git a/lib/Format/ContinuationIndenter.h b/lib/Format/ContinuationIndenter.h
index 9a3c118561..e8a9131e8b 100644
--- a/lib/Format/ContinuationIndenter.h
+++ b/lib/Format/ContinuationIndenter.h
@@ -135,11 +135,11 @@ struct ParenState {
: Indent(Indent), IndentLevel(IndentLevel), LastSpace(LastSpace),
FirstLessLess(0), BreakBeforeClosingBrace(false), QuestionColumn(0),
AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
- NoLineBreak(NoLineBreak), ColonPos(0), StartOfFunctionCall(0),
- StartOfArraySubscripts(0), NestedNameSpecifierContinuation(0),
- CallContinuation(0), VariablePos(0), ContainsLineBreak(false),
- ContainsUnwrappedBuilder(0), AlignColons(true),
- ObjCSelectorNameFound(false) {}
+ NoLineBreak(NoLineBreak), LastOperatorWrapped(true), ColonPos(0),
+ StartOfFunctionCall(0), StartOfArraySubscripts(0),
+ NestedNameSpecifierContinuation(0), CallContinuation(0), VariablePos(0),
+ ContainsLineBreak(false), ContainsUnwrappedBuilder(0),
+ AlignColons(true), ObjCSelectorNameFound(false), LambdasFound(0) {}
/// \brief The position to which a specific parenthesis level needs to be
/// indented.
@@ -182,6 +182,10 @@ struct ParenState {
/// \brief Line breaking in this context would break a formatting rule.
bool NoLineBreak;
+ /// \brief True if the last binary operator on this level was wrapped to the
+ /// next line.
+ bool LastOperatorWrapped;
+
/// \brief The position of the colon in an ObjC method declaration/call.
unsigned ColonPos;
@@ -230,6 +234,12 @@ struct ParenState {
/// the same token.
bool ObjCSelectorNameFound;
+ /// \brief Counts the number of lambda introducers found on this level.
+ ///
+ /// Not considered for memoization as it will always have the same value at
+ /// the same token.
+ unsigned LambdasFound;
+
bool operator<(const ParenState &Other) const {
if (Indent != Other.Indent)
return Indent < Other.Indent;
@@ -247,6 +257,8 @@ struct ParenState {
return BreakBeforeParameter;
if (NoLineBreak != Other.NoLineBreak)
return NoLineBreak;
+ if (LastOperatorWrapped != Other.LastOperatorWrapped)
+ return LastOperatorWrapped;
if (ColonPos != Other.ColonPos)
return ColonPos < Other.ColonPos;
if (StartOfFunctionCall != Other.StartOfFunctionCall)
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index cb07cb56a5..3544cff4dd 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -13,8 +13,6 @@
///
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "format-formatter"
-
#include "ContinuationIndenter.h"
#include "TokenAnnotator.h"
#include "UnwrappedLineParser.h"
@@ -31,6 +29,8 @@
#include <queue>
#include <string>
+#define DEBUG_TYPE "format-formatter"
+
using clang::format::FormatStyle;
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string)
@@ -65,6 +65,16 @@ template <> struct ScalarEnumerationTraits<FormatStyle::UseTabStyle> {
}
};
+template <> struct ScalarEnumerationTraits<FormatStyle::ShortFunctionStyle> {
+ static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) {
+ IO.enumCase(Value, "None", FormatStyle::SFS_None);
+ IO.enumCase(Value, "false", FormatStyle::SFS_None);
+ IO.enumCase(Value, "All", FormatStyle::SFS_All);
+ IO.enumCase(Value, "true", FormatStyle::SFS_All);
+ IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline);
+ }
+};
+
template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
static void enumeration(IO &IO, FormatStyle::BraceBreakingStyle &Value) {
IO.enumCase(Value, "Attach", FormatStyle::BS_Attach);
@@ -251,7 +261,7 @@ FormatStyle getLLVMStyle() {
LLVMStyle.AlignEscapedNewlinesLeft = false;
LLVMStyle.AlignTrailingComments = true;
LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
- LLVMStyle.AllowShortFunctionsOnASingleLine = true;
+ LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
LLVMStyle.AllowShortLoopsOnASingleLine = false;
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
@@ -332,7 +342,8 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
GoogleStyle.MaxEmptyLinesToKeep = 2;
GoogleStyle.SpacesInContainerLiterals = false;
} else if (Language == FormatStyle::LK_Proto) {
- GoogleStyle.AllowShortFunctionsOnASingleLine = false;
+ GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
+ GoogleStyle.SpacesInContainerLiterals = false;
}
return GoogleStyle;
@@ -341,6 +352,7 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) {
FormatStyle ChromiumStyle = getGoogleStyle(Language);
ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
+ ChromiumStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
ChromiumStyle.AllowShortIfStatementsOnASingleLine = false;
ChromiumStyle.AllowShortLoopsOnASingleLine = false;
ChromiumStyle.BinPackParameters = false;
@@ -523,11 +535,16 @@ public:
if (I + 1 == E || I[1]->Type == LT_Invalid)
return 0;
+ // FIXME: TheLine->Level != 0 might or might not be the right check to do.
+ // If necessary, change to something smarter.
+ bool MergeShortFunctions =
+ Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All ||
+ (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline &&
+ TheLine->Level != 0);
+
if (TheLine->Last->Type == TT_FunctionLBrace &&
TheLine->First != TheLine->Last) {
- return Style.AllowShortFunctionsOnASingleLine
- ? tryMergeSimpleBlock(I, E, Limit)
- : 0;
+ return MergeShortFunctions ? tryMergeSimpleBlock(I, E, Limit) : 0;
}
if (TheLine->Last->is(tok::l_brace)) {
return Style.BreakBeforeBraces == FormatStyle::BS_Attach
@@ -542,7 +559,7 @@ public:
Limit -= 2;
unsigned MergedLines = 0;
- if (Style.AllowShortFunctionsOnASingleLine) {
+ if (MergeShortFunctions) {
MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
// If we managed to merge the block, count the function header, which is
// on a separate line.
@@ -623,7 +640,7 @@ private:
AnnotatedLine &Line = **I;
if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::r_brace,
tok::kw_else, tok::kw_try, tok::kw_catch,
- tok::kw_for,
+ tok::kw_for, tok::kw_case,
// This gets rid of all ObjC @ keywords and methods.
tok::at, tok::minus, tok::plus))
return 0;
@@ -705,6 +722,13 @@ public:
unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,
int AdditionalIndent = 0, bool FixBadIndentation = false) {
+ // Try to look up already computed penalty in DryRun-mode.
+ std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned> CacheKey(
+ &Lines, AdditionalIndent);
+ auto CacheIt = PenaltyCache.find(CacheKey);
+ if (DryRun && CacheIt != PenaltyCache.end())
+ return CacheIt->second;
+
assert(!Lines.empty());
unsigned Penalty = 0;
std::vector<int> IndentForLevel;
@@ -828,6 +852,7 @@ public:
}
PreviousLine = *I;
}
+ PenaltyCache[CacheKey] = Penalty;
return Penalty;
}
@@ -897,6 +922,8 @@ private:
Newlines = std::min(Newlines, 1u);
if (Newlines == 0 && !RootToken.IsFirst)
Newlines = 1;
+ if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)
+ Newlines = 0;
// Remove empty lines after "{".
if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
@@ -1105,10 +1132,21 @@ private:
if (Previous.Children.size() > 1)
return false;
+ // Cannot merge into one line if this line ends on a comment.
+ if (Previous.is(tok::comment))
+ return false;
+
// We can't put the closing "}" on a line with a trailing comment.
if (Previous.Children[0]->Last->isTrailingComment())
return false;
+ // If the child line exceeds the column limit, we wouldn't want to merge it.
+ // We add +2 for the trailing " }".
+ if (Style.ColumnLimit > 0 &&
+ Previous.Children[0]->Last->TotalLength + State.Column + 2 >
+ Style.ColumnLimit)
+ return false;
+
if (!DryRun) {
Whitespaces->replaceWhitespace(
*Previous.Children[0]->First,
@@ -1127,6 +1165,12 @@ private:
LineJoiner Joiner;
llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
+
+ // Cache to store the penalty of formatting a vector of AnnotatedLines
+ // starting from a specific additional offset. Improves performance if there
+ // are many nested blocks.
+ std::map<std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned>,
+ unsigned> PenaltyCache;
};
class FormatTokenLexer {
@@ -1135,7 +1179,8 @@ public:
encoding::Encoding Encoding)
: FormatTok(NULL), IsFirstToken(true), GreaterStashed(false), Column(0),
TrailingWhitespace(0), Lex(Lex), SourceMgr(SourceMgr), Style(Style),
- IdentTable(getFormattingLangOpts()), Encoding(Encoding) {
+ IdentTable(getFormattingLangOpts()), Encoding(Encoding),
+ FirstInLineIndex(0) {
Lex.SetKeepWhitespaceMode(true);
for (const std::string& ForEachMacro : Style.ForEachMacros)
@@ -1145,9 +1190,12 @@ public:
ArrayRef<FormatToken *> lex() {
assert(Tokens.empty());
+ assert(FirstInLineIndex == 0);
do {
Tokens.push_back(getNextToken());
tryMergePreviousTokens();
+ if (Tokens.back()->NewlinesBefore > 0)
+ FirstInLineIndex = Tokens.size() - 1;
} while (Tokens.back()->Tok.isNot(tok::eof));
return Tokens;
}
@@ -1158,6 +1206,8 @@ private:
void tryMergePreviousTokens() {
if (tryMerge_TMacro())
return;
+ if (tryMergeConflictMarkers())
+ return;
if (Style.Language == FormatStyle::LK_JavaScript) {
static tok::TokenKind JSIdentity[] = { tok::equalequal, tok::equal };
@@ -1232,6 +1282,68 @@ private:
return true;
}
+ bool tryMergeConflictMarkers() {
+ if (Tokens.back()->NewlinesBefore == 0 && Tokens.back()->isNot(tok::eof))
+ return false;
+
+ // Conflict lines look like:
+ // <marker> <text from the vcs>
+ // For example:
+ // >>>>>>> /file/in/file/system at revision 1234
+ //
+ // We merge all tokens in a line that starts with a conflict marker
+ // into a single token with a special token type that the unwrapped line
+ // parser will use to correctly rebuild the underlying code.
+
+ FileID ID;
+ // Get the position of the first token in the line.
+ unsigned FirstInLineOffset;
+ std::tie(ID, FirstInLineOffset) = SourceMgr.getDecomposedLoc(
+ Tokens[FirstInLineIndex]->getStartOfNonWhitespace());
+ StringRef Buffer = SourceMgr.getBuffer(ID)->getBuffer();
+ // Calculate the offset of the start of the current line.
+ auto LineOffset = Buffer.rfind('\n', FirstInLineOffset);
+ if (LineOffset == StringRef::npos) {
+ LineOffset = 0;
+ } else {
+ ++LineOffset;
+ }
+
+ auto FirstSpace = Buffer.find_first_of(" \n", LineOffset);
+ StringRef LineStart;
+ if (FirstSpace == StringRef::npos) {
+ LineStart = Buffer.substr(LineOffset);
+ } else {
+ LineStart = Buffer.substr(LineOffset, FirstSpace - LineOffset);
+ }
+
+ TokenType Type = TT_Unknown;
+ if (LineStart == "<<<<<<<" || LineStart == ">>>>") {
+ Type = TT_ConflictStart;
+ } else if (LineStart == "|||||||" || LineStart == "=======" ||
+ LineStart == "====") {
+ Type = TT_ConflictAlternative;
+ } else if (LineStart == ">>>>>>>" || LineStart == "<<<<") {
+ Type = TT_ConflictEnd;
+ }
+
+ if (Type != TT_Unknown) {
+ FormatToken *Next = Tokens.back();
+
+ Tokens.resize(FirstInLineIndex + 1);
+ // We do not need to build a complete token here, as we will skip it
+ // during parsing anyway (as we must not touch whitespace around conflict
+ // markers).
+ Tokens.back()->Type = Type;
+ Tokens.back()->Tok.setKind(tok::kw___unknown_anytype);
+
+ Tokens.push_back(Next);
+ return true;
+ }
+
+ return false;
+ }
+
FormatToken *getNextToken() {
if (GreaterStashed) {
// Create a synthesized second '>' token.
@@ -1309,7 +1421,7 @@ private:
// FIXME: Add a more explicit test.
while (FormatTok->TokenText.size() > 1 && FormatTok->TokenText[0] == '\\' &&
FormatTok->TokenText[1] == '\n') {
- // FIXME: ++FormatTok->NewlinesBefore is missing...
+ ++FormatTok->NewlinesBefore;
WhitespaceLength += 2;
Column = 0;
FormatTok->TokenText = FormatTok->TokenText.substr(2);
@@ -1379,6 +1491,8 @@ private:
IdentifierTable IdentTable;
encoding::Encoding Encoding;
llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
+ // Index (in 'Tokens') of the last token that starts a new line.
+ unsigned FirstInLineIndex;
SmallVector<FormatToken *, 16> Tokens;
SmallVector<IdentifierInfo*, 8> ForEachMacros;
@@ -1735,6 +1849,7 @@ LangOptions getFormattingLangOpts(FormatStyle::LanguageStandard Standard) {
LangOptions LangOpts;
LangOpts.CPlusPlus = 1;
LangOpts.CPlusPlus11 = Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
+ LangOpts.CPlusPlus1y = Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.LineComment = 1;
LangOpts.Bool = 1;
LangOpts.ObjC1 = 1;
diff --git a/lib/Format/FormatToken.cpp b/lib/Format/FormatToken.cpp
index c147dbb6b1..a7c003bc18 100644
--- a/lib/Format/FormatToken.cpp
+++ b/lib/Format/FormatToken.cpp
@@ -132,6 +132,11 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
if (!Token->MatchingParen || Token->isNot(tok::l_brace))
return;
+ // In C++11 braced list style, we should not format in columns unless we allow
+ // bin-packing of function parameters.
+ if (Style.Cpp11BracedListStyle && !Style.BinPackParameters)
+ return;
+
FormatToken *ItemBegin = Token->Next;
SmallVector<bool, 8> MustBreakBeforeItem;
diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h
index a5aaa6f6de..749dfcb3e4 100644
--- a/lib/Format/FormatToken.h
+++ b/lib/Format/FormatToken.h
@@ -33,19 +33,22 @@ enum TokenType {
TT_BlockComment,
TT_CastRParen,
TT_ConditionalExpr,
+ TT_ConflictAlternative,
+ TT_ConflictEnd,
+ TT_ConflictStart,
TT_CtorInitializerColon,
TT_CtorInitializerComma,
TT_DesignatedInitializerPeriod,
TT_DictLiteral,
- TT_ImplicitStringLiteral,
- TT_InlineASMColon,
- TT_InheritanceColon,
TT_FunctionLBrace,
TT_FunctionTypeLParen,
+ TT_ImplicitStringLiteral,
+ TT_InheritanceColon,
+ TT_InlineASMColon,
TT_LambdaLSquare,
TT_LineComment,
- TT_ObjCBlockLParen,
TT_ObjCBlockLBrace,
+ TT_ObjCBlockLParen,
TT_ObjCDecl,
TT_ObjCForIn,
TT_ObjCMethodExpr,
@@ -103,8 +106,9 @@ struct FormatToken {
UnbreakableTailLength(0), BindingStrength(0), NestingLevel(0),
SplitPenalty(0), LongestObjCSelectorName(0), FakeRParens(0),
StartsBinaryExpression(false), EndsBinaryExpression(false),
- LastInChainOfCalls(false), PartOfMultiVariableDeclStmt(false),
- IsForEachMacro(false), MatchingParen(NULL), Previous(NULL), Next(NULL),
+ OperatorIndex(0), LastOperator(false),
+ PartOfMultiVariableDeclStmt(false), IsForEachMacro(false),
+ MatchingParen(NULL), Previous(NULL), Next(NULL),
Decision(FD_Unformatted), Finalized(false) {}
/// \brief The \c Token.
@@ -239,8 +243,13 @@ struct FormatToken {
/// \brief \c true if this token ends a binary expression.
bool EndsBinaryExpression;
- /// \brief Is this the last "." or "->" in a builder-type call?
- bool LastInChainOfCalls;
+ /// \brief Is this is an operator (or "."/"->") in a sequence of operators
+ /// with the same precedence, contains the 0-based operator index.
+ unsigned OperatorIndex;
+
+ /// \brief Is this the last operator (or "."/"->") in a sequence of operators
+ /// with the same precedence?
+ bool LastOperator;
/// \brief Is this token part of a \c DeclStmt defining multiple variables?
///
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 0034235c32..843d877718 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -17,6 +17,8 @@
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/Debug.h"
+#define DEBUG_TYPE "format-token-annotator"
+
namespace clang {
namespace format {
@@ -110,6 +112,11 @@ private:
Left->Previous->Type == TT_BinaryOperator)) {
// static_assert, if and while usually contain expressions.
Contexts.back().IsExpression = true;
+ } else if (Line.InPPDirective &&
+ (!Left->Previous ||
+ (Left->Previous->isNot(tok::identifier) &&
+ Left->Previous->Type != TT_OverloadedOperator))) {
+ Contexts.back().IsExpression = true;
} else if (Left->Previous && Left->Previous->is(tok::r_square) &&
Left->Previous->MatchingParen &&
Left->Previous->MatchingParen->Type == TT_LambdaLSquare) {
@@ -245,7 +252,7 @@ private:
StartsObjCMethodExpr = false;
Left->Type = TT_Unknown;
}
- if (StartsObjCMethodExpr) {
+ if (StartsObjCMethodExpr && CurrentToken->Previous != Left) {
CurrentToken->Type = TT_ObjCMethodExpr;
// determineStarAmpUsage() thinks that '*' '[' is allocating an
// array of pointers, but if '[' starts a selector then '*' is a
@@ -363,7 +370,8 @@ private:
if (Tok->Previous == NULL)
return false;
// Colons from ?: are handled in parseConditional().
- if (Tok->Previous->is(tok::r_paren) && Contexts.size() == 1) {
+ if (Tok->Previous->is(tok::r_paren) && Contexts.size() == 1 &&
+ Line.First->isNot(tok::kw_case)) {
Tok->Type = TT_CtorInitializerColon;
} else if (Contexts.back().ColonIsDictLiteral) {
Tok->Type = TT_DictLiteral;
@@ -674,7 +682,7 @@ private:
for (FormatToken *Previous = Current.Previous;
Previous && !Previous->isOneOf(tok::comma, tok::semi);
Previous = Previous->Previous) {
- if (Previous->is(tok::r_square))
+ if (Previous->isOneOf(tok::r_square, tok::r_paren))
Previous = Previous->MatchingParen;
if (Previous->Type == TT_BinaryOperator &&
Previous->isOneOf(tok::star, tok::amp)) {
@@ -727,15 +735,16 @@ private:
Contexts.back().InTemplateArgument);
} else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) {
Current.Type = determinePlusMinusCaretUsage(Current);
- if (Current.Type == TT_UnaryOperator) {
+ if (Current.Type == TT_UnaryOperator && Current.is(tok::caret)) {
++Contexts.back().NumBlockParameters;
- if (Current.is(tok::caret))
- Contexts.back().CaretFound = true;
+ Contexts.back().CaretFound = true;
}
} else if (Current.isOneOf(tok::minusminus, tok::plusplus)) {
Current.Type = determineIncrementUsage(Current);
} else if (Current.is(tok::exclaim)) {
Current.Type = TT_UnaryOperator;
+ } else if (Current.is(tok::question)) {
+ Current.Type = TT_ConditionalExpr;
} else if (Current.isBinaryOperator() &&
(!Current.Previous ||
Current.Previous->isNot(tok::l_square))) {
@@ -800,6 +809,7 @@ private:
PreviousNoComment->isOneOf(tok::comma, tok::l_brace))
Current.Type = TT_DesignatedInitializerPeriod;
} else if (Current.isOneOf(tok::identifier, tok::kw_const) &&
+ Current.Previous && Current.Previous->isNot(tok::equal) &&
Line.MightBeFunctionDecl && Contexts.size() == 1) {
// Line.MightBeFunctionDecl can only be true after the parentheses of a
// function declaration have been found.
@@ -858,6 +868,7 @@ private:
tok::comma, tok::semi, tok::kw_return, tok::colon,
tok::equal, tok::kw_delete, tok::kw_sizeof) ||
PrevToken->Type == TT_BinaryOperator ||
+ PrevToken->Type == TT_ConditionalExpr ||
PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen)
return TT_UnaryOperator;
@@ -970,6 +981,7 @@ public:
FormatToken *Start = Current;
FormatToken *LatestOperator = NULL;
+ unsigned OperatorIndex = 0;
while (Current) {
// Consume operators with higher precedence.
@@ -989,8 +1001,8 @@ public:
if (Current == NULL || Current->closesScope() ||
(CurrentPrecedence != -1 && CurrentPrecedence < Precedence)) {
if (LatestOperator) {
+ LatestOperator->LastOperator = true;
if (Precedence == PrecedenceArrowAndPeriod) {
- LatestOperator->LastInChainOfCalls = true;
// Call expressions don't have a binary operator precedence.
addFakeParenthesis(Start, prec::Unknown);
} else {
@@ -1009,8 +1021,11 @@ public:
next();
} else {
// Operator found.
- if (CurrentPrecedence == Precedence)
+ if (CurrentPrecedence == Precedence) {
LatestOperator = Current;
+ Current->OperatorIndex = OperatorIndex;
+ ++OperatorIndex;
+ }
next();
}
@@ -1235,7 +1250,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Left.is(tok::semi))
return 0;
- if (Left.is(tok::comma))
+ if (Left.is(tok::comma) || (Right.is(tok::identifier) && Right.Next &&
+ Right.Next->Type == TT_DictLiteral))
return 1;
if (Right.is(tok::l_square)) {
if (Style.Language == FormatStyle::LK_Proto)
@@ -1280,11 +1296,9 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
// annotations (i.e. "const", "final" and "override") on the same line.
// Use a slightly higher penalty after ")" so that annotations like
// "const override" are kept together.
- bool is_standard_annotation = Right.is(tok::kw_const) ||
- Right.TokenText == "override" ||
- Right.TokenText == "final";
+ bool is_short_annotation = Right.TokenText.size() < 10;
return (Left.is(tok::r_paren) ? 100 : 120) +
- (is_standard_annotation ? 50 : 0);
+ (is_short_annotation ? 50 : 0);
}
// In for-loops, prefer breaking at ',' and ';'.
@@ -1416,7 +1430,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
tok::semi) ||
(Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&
(Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while,
- tok::kw_switch, tok::kw_catch) ||
+ tok::kw_switch, tok::kw_catch, tok::kw_case) ||
Left.IsForEachMacro)) ||
(Style.SpaceBeforeParens == FormatStyle::SBPO_Always &&
Left.isOneOf(tok::identifier, tok::kw___attribute) &&
@@ -1496,7 +1510,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
Tok.getPrecedence() == prec::Assignment)
return false;
if ((Tok.Type == TT_BinaryOperator && !Tok.Previous->is(tok::l_paren)) ||
- Tok.Previous->Type == TT_BinaryOperator)
+ Tok.Previous->Type == TT_BinaryOperator ||
+ Tok.Previous->Type == TT_ConditionalExpr)
return true;
if (Tok.Previous->Type == TT_TemplateCloser && Tok.is(tok::l_paren))
return false;
@@ -1514,7 +1529,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
if (Right.is(tok::comment)) {
return Right.Previous->BlockKind != BK_BracedInit &&
Right.Previous->Type != TT_CtorInitializerColon &&
- Right.NewlinesBefore > 0;
+ (Right.NewlinesBefore > 0 && Right.HasUnescapedNewline);
} else if (Right.Previous->isTrailingComment() ||
(Right.isStringLiteral() && Right.Previous->isStringLiteral())) {
return true;
@@ -1547,14 +1562,20 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
Style.Language == FormatStyle::LK_Proto) {
// Don't enums onto single lines in protocol buffers.
return true;
- } else if ((Left.is(tok::l_brace) && Left.MatchingParen &&
- Left.MatchingParen->Previous &&
- Left.MatchingParen->Previous->is(tok::comma)) ||
- (Right.is(tok::r_brace) && Left.is(tok::comma))) {
- // If the last token before a '}' is a comma, the intention is to insert a
- // line break after it in order to make shuffling around entries easier.
- return true;
}
+
+ // If the last token before a '}' is a comma or a comment, the intention is to
+ // insert a line break after it in order to make shuffling around entries
+ // easier.
+ const FormatToken *BeforeClosingBrace = nullptr;
+ if (Left.is(tok::l_brace) && Left.MatchingParen)
+ BeforeClosingBrace = Left.MatchingParen->Previous;
+ else if (Right.is(tok::r_brace))
+ BeforeClosingBrace = Right.Previous;
+ if (BeforeClosingBrace &&
+ BeforeClosingBrace->isOneOf(tok::comma, tok::comment))
+ return true;
+
return false;
}
@@ -1563,6 +1584,8 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
const FormatToken &Left = *Right.Previous;
if (Left.is(tok::at))
return false;
+ if (Left.Tok.getObjCKeywordID() == tok::objc_interface)
+ return false;
if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator))
return true;
if (Right.isTrailingComment())
@@ -1622,11 +1645,11 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
if (Right.is(tok::r_brace))
return Right.MatchingParen && Right.MatchingParen->BlockKind == BK_Block;
- // Allow breaking after a trailing 'const', e.g. after a method declaration,
- // unless it is follow by ';', '{' or '='.
- if (Left.is(tok::kw_const) && Left.Previous != NULL &&
- Left.Previous->is(tok::r_paren))
- return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal);
+ // Allow breaking after a trailing annotation, e.g. after a method
+ // declaration.
+ if (Left.Type == TT_TrailingAnnotation)
+ return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal, tok::l_paren,
+ tok::less, tok::coloncolon);
if (Right.is(tok::kw___attribute))
return true;
@@ -1634,6 +1657,10 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
if (Left.is(tok::identifier) && Right.is(tok::string_literal))
return true;
+ if (Right.is(tok::identifier) && Right.Next &&
+ Right.Next->Type == TT_DictLiteral)
+ return true;
+
if (Left.Type == TT_CtorInitializerComma &&
Style.BreakConstructorInitializersBeforeComma)
return false;
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index 96d815572f..8dd32d5f71 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -13,11 +13,11 @@
///
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "format-parser"
-
#include "UnwrappedLineParser.h"
#include "llvm/Support/Debug.h"
+#define DEBUG_TYPE "format-parser"
+
namespace clang {
namespace format {
@@ -335,18 +335,25 @@ void UnwrappedLineParser::calculateBraceTypes() {
case tok::r_brace:
if (!LBraceStack.empty()) {
if (LBraceStack.back()->BlockKind == BK_Unknown) {
- // If there is a comma, semicolon or right paren after the closing
- // brace, we assume this is a braced initializer list. Note that
- // regardless how we mark inner braces here, we will overwrite the
- // BlockKind later if we parse a braced list (where all blocks inside
- // are by default braced lists), or when we explicitly detect blocks
- // (for example while parsing lambdas).
- //
- // We exclude + and - as they can be ObjC visibility modifiers.
- if (NextTok->isOneOf(tok::comma, tok::semi, tok::r_paren, tok::period,
- tok::r_square, tok::l_brace, tok::colon) ||
- (NextTok->isBinaryOperator() &&
- !NextTok->isOneOf(tok::plus, tok::minus))) {
+ bool ProbablyBracedList = false;
+ if (Style.Language == FormatStyle::LK_Proto) {
+ ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square);
+ } else {
+ // If there is a comma, semicolon or right paren after the closing
+ // brace, we assume this is a braced initializer list. Note that
+ // regardless how we mark inner braces here, we will overwrite the
+ // BlockKind later if we parse a braced list (where all blocks
+ // inside are by default braced lists), or when we explicitly detect
+ // blocks (for example while parsing lambdas).
+ //
+ // We exclude + and - as they can be ObjC visibility modifiers.
+ ProbablyBracedList =
+ NextTok->isOneOf(tok::comma, tok::semi, tok::period, tok::colon,
+ tok::r_paren, tok::r_square, tok::l_brace) ||
+ (NextTok->isBinaryOperator() &&
+ !NextTok->isOneOf(tok::plus, tok::minus));
+ }
+ if (ProbablyBracedList) {
Tok->BlockKind = BK_BracedInit;
LBraceStack.back()->BlockKind = BK_BracedInit;
} else {
@@ -458,14 +465,14 @@ void UnwrappedLineParser::parsePPDirective() {
}
}
-void UnwrappedLineParser::pushPPConditional() {
- if (!PPStack.empty() && PPStack.back() == PP_Unreachable)
+void UnwrappedLineParser::conditionalCompilationCondition(bool Unreachable) {
+ if (Unreachable || (!PPStack.empty() && PPStack.back() == PP_Unreachable))
PPStack.push_back(PP_Unreachable);
else
PPStack.push_back(PP_Conditional);
}
-void UnwrappedLineParser::parsePPIf(bool IfDef) {
+void UnwrappedLineParser::conditionalCompilationStart(bool Unreachable) {
++PPBranchLevel;
assert(PPBranchLevel >= 0 && PPBranchLevel <= (int)PPLevelBranchIndex.size());
if (PPBranchLevel == (int)PPLevelBranchIndex.size()) {
@@ -473,37 +480,22 @@ void UnwrappedLineParser::parsePPIf(bool IfDef) {
PPLevelBranchCount.push_back(0);
}
PPChainBranchIndex.push(0);
- nextToken();
- bool IsLiteralFalse = (FormatTok->Tok.isLiteral() &&
- StringRef(FormatTok->Tok.getLiteralData(),
- FormatTok->Tok.getLength()) == "0") ||
- FormatTok->Tok.is(tok::kw_false);
- if ((!IfDef && IsLiteralFalse) || PPLevelBranchIndex[PPBranchLevel] > 0) {
- PPStack.push_back(PP_Unreachable);
- } else {
- pushPPConditional();
- }
- parsePPUnknown();
+ bool Skip = PPLevelBranchIndex[PPBranchLevel] > 0;
+ conditionalCompilationCondition(Unreachable || Skip);
}
-void UnwrappedLineParser::parsePPElse() {
+void UnwrappedLineParser::conditionalCompilationAlternative() {
if (!PPStack.empty())
PPStack.pop_back();
assert(PPBranchLevel < (int)PPLevelBranchIndex.size());
if (!PPChainBranchIndex.empty())
++PPChainBranchIndex.top();
- if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty() &&
- PPLevelBranchIndex[PPBranchLevel] != PPChainBranchIndex.top()) {
- PPStack.push_back(PP_Unreachable);
- } else {
- pushPPConditional();
- }
- parsePPUnknown();
+ conditionalCompilationCondition(
+ PPBranchLevel >= 0 && !PPChainBranchIndex.empty() &&
+ PPLevelBranchIndex[PPBranchLevel] != PPChainBranchIndex.top());
}
-void UnwrappedLineParser::parsePPElIf() { parsePPElse(); }
-
-void UnwrappedLineParser::parsePPEndIf() {
+void UnwrappedLineParser::conditionalCompilationEnd() {
assert(PPBranchLevel < (int)PPLevelBranchIndex.size());
if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty()) {
if (PPChainBranchIndex.top() + 1 > PPLevelBranchCount[PPBranchLevel]) {
@@ -517,6 +509,27 @@ void UnwrappedLineParser::parsePPEndIf() {
PPChainBranchIndex.pop();
if (!PPStack.empty())
PPStack.pop_back();
+}
+
+void UnwrappedLineParser::parsePPIf(bool IfDef) {
+ nextToken();
+ bool IsLiteralFalse = (FormatTok->Tok.isLiteral() &&
+ StringRef(FormatTok->Tok.getLiteralData(),
+ FormatTok->Tok.getLength()) == "0") ||
+ FormatTok->Tok.is(tok::kw_false);
+ conditionalCompilationStart(!IfDef && IsLiteralFalse);
+ parsePPUnknown();
+}
+
+void UnwrappedLineParser::parsePPElse() {
+ conditionalCompilationAlternative();
+ parsePPUnknown();
+}
+
+void UnwrappedLineParser::parsePPElIf() { parsePPElse(); }
+
+void UnwrappedLineParser::parsePPEndIf() {
+ conditionalCompilationEnd();
parsePPUnknown();
}
@@ -1351,13 +1364,18 @@ void UnwrappedLineParser::addUnwrappedLine() {
bool UnwrappedLineParser::eof() const { return FormatTok->Tok.is(tok::eof); }
+bool UnwrappedLineParser::isOnNewLine(const FormatToken& FormatTok) {
+ return (Line->InPPDirective || FormatTok.HasUnescapedNewline) &&
+ FormatTok.NewlinesBefore > 0;
+}
+
void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
bool JustComments = Line->Tokens.empty();
for (SmallVectorImpl<FormatToken *>::const_iterator
I = CommentsBeforeNextToken.begin(),
E = CommentsBeforeNextToken.end();
I != E; ++I) {
- if ((*I)->NewlinesBefore && JustComments) {
+ if (isOnNewLine(**I) && JustComments) {
addUnwrappedLine();
}
pushToken(*I);
@@ -1371,7 +1389,7 @@ void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
void UnwrappedLineParser::nextToken() {
if (eof())
return;
- flushComments(FormatTok->NewlinesBefore > 0);
+ flushComments(isOnNewLine(*FormatTok));
pushToken(FormatTok);
readToken();
}
@@ -1391,9 +1409,22 @@ void UnwrappedLineParser::readToken() {
// Comments stored before the preprocessor directive need to be output
// before the preprocessor directive, at the same level as the
// preprocessor directive, as we consider them to apply to the directive.
- flushComments(FormatTok->NewlinesBefore > 0);
+ flushComments(isOnNewLine(*FormatTok));
parsePPDirective();
}
+ while (FormatTok->Type == TT_ConflictStart ||
+ FormatTok->Type == TT_ConflictEnd ||
+ FormatTok->Type == TT_ConflictAlternative) {
+ if (FormatTok->Type == TT_ConflictStart) {
+ conditionalCompilationStart(/*Unreachable=*/false);
+ } else if (FormatTok->Type == TT_ConflictAlternative) {
+ conditionalCompilationAlternative();
+ } else if(FormatTok->Type == TT_ConflictEnd) {
+ conditionalCompilationEnd();
+ }
+ FormatTok = Tokens->getNextToken();
+ FormatTok->MustBreakBefore = true;
+ }
if (!PPStack.empty() && (PPStack.back() == PP_Unreachable) &&
!Line->InPPDirective) {
@@ -1402,7 +1433,7 @@ void UnwrappedLineParser::readToken() {
if (!FormatTok->Tok.is(tok::comment))
return;
- if (FormatTok->NewlinesBefore > 0 || FormatTok->IsFirst) {
+ if (isOnNewLine(*FormatTok) || FormatTok->IsFirst) {
CommentsInCurrentLine = false;
}
if (CommentsInCurrentLine) {
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index 62e0b58ea1..8f0c5a3ef4 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -107,7 +107,17 @@ private:
void flushComments(bool NewlineBeforeNext);
void pushToken(FormatToken *Tok);
void calculateBraceTypes();
- void pushPPConditional();
+
+ // Marks a conditional compilation edge (for example, an '#if', '#ifdef',
+ // '#else' or merge conflict marker). If 'Unreachable' is true, assumes
+ // this branch either cannot be taken (for example '#if false'), or should
+ // not be taken in this round.
+ void conditionalCompilationCondition(bool Unreachable);
+ void conditionalCompilationStart(bool Unreachable);
+ void conditionalCompilationAlternative();
+ void conditionalCompilationEnd();
+
+ bool isOnNewLine(const FormatToken& FormatTok);
// FIXME: We are constantly running into bugs where Line.Level is incorrectly
// subtracted from beyond 0. Introduce a method to subtract from Line.Level
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index 4c393ed439..2906b17d7b 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -28,7 +28,7 @@ WhitespaceManager::Change::IsBeforeInFile::operator()(const Change &C1,
WhitespaceManager::Change::Change(
bool CreateReplacement, const SourceRange &OriginalWhitespaceRange,
- unsigned IndentLevel, unsigned Spaces, unsigned StartOfTokenColumn,
+ unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn,
unsigned NewlinesBefore, StringRef PreviousLinePostfix,
StringRef CurrentLinePrefix, tok::TokenKind Kind, bool ContinuesPPDirective)
: CreateReplacement(CreateReplacement),
@@ -69,14 +69,14 @@ void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
void WhitespaceManager::replaceWhitespaceInToken(
const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
- unsigned Newlines, unsigned IndentLevel, unsigned Spaces) {
+ unsigned Newlines, unsigned IndentLevel, int Spaces) {
if (Tok.Finalized)
return;
+ SourceLocation Start = Tok.getStartOfNonWhitespace().getLocWithOffset(Offset);
Changes.push_back(Change(
- true, SourceRange(Tok.getStartOfNonWhitespace().getLocWithOffset(Offset),
- Tok.getStartOfNonWhitespace().getLocWithOffset(
- Offset + ReplaceChars)),
- IndentLevel, Spaces, Spaces, Newlines, PreviousPostfix, CurrentPrefix,
+ true, SourceRange(Start, Start.getLocWithOffset(ReplaceChars)),
+ IndentLevel, Spaces, std::max(0, Spaces), Newlines, PreviousPostfix,
+ CurrentPrefix,
// If we don't add a newline this change doesn't start a comment. Thus,
// when we align line comments, we don't need to treat this change as one.
// FIXME: We still need to take this change in account to properly
@@ -122,6 +122,22 @@ void WhitespaceManager::calculateLineBreakInformation() {
// cases, setting TokenLength of the last token to 0 is wrong.
Changes.back().TokenLength = 0;
Changes.back().IsTrailingComment = Changes.back().Kind == tok::comment;
+
+ const WhitespaceManager::Change *LastBlockComment = nullptr;
+ for (auto &Change : Changes) {
+ Change.StartOfBlockComment = nullptr;
+ Change.IndentationOffset = 0;
+ if (Change.Kind == tok::comment) {
+ LastBlockComment = &Change;
+ } else if (Change.Kind == tok::unknown) {
+ if ((Change.StartOfBlockComment = LastBlockComment))
+ Change.IndentationOffset =
+ Change.StartOfTokenColumn -
+ Change.StartOfBlockComment->StartOfTokenColumn;
+ } else {
+ LastBlockComment = nullptr;
+ }
+ }
}
void WhitespaceManager::alignTrailingComments() {
@@ -131,58 +147,62 @@ void WhitespaceManager::alignTrailingComments() {
bool BreakBeforeNext = false;
unsigned Newlines = 0;
for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
+ if (Changes[i].StartOfBlockComment)
+ continue;
+ Newlines += Changes[i].NewlinesBefore;
+ if (!Changes[i].IsTrailingComment)
+ continue;
+
unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
- // FIXME: Correctly handle ChangeMaxColumn in PP directives.
unsigned ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
- Newlines += Changes[i].NewlinesBefore;
- if (Changes[i].IsTrailingComment) {
- // If this comment follows an } in column 0, it probably documents the
- // closing of a namespace and we don't want to align it.
- bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 &&
- Changes[i - 1].Kind == tok::r_brace &&
- Changes[i - 1].StartOfTokenColumn == 0;
- bool WasAlignedWithStartOfNextLine = false;
- if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
- for (unsigned j = i + 1; j != e; ++j) {
- if (Changes[j].Kind != tok::comment) { // Skip over comments.
- // The start of the next token was previously aligned with the
- // start of this comment.
- WasAlignedWithStartOfNextLine =
- (SourceMgr.getSpellingColumnNumber(
- Changes[i].OriginalWhitespaceRange.getEnd()) ==
- SourceMgr.getSpellingColumnNumber(
- Changes[j].OriginalWhitespaceRange.getEnd()));
- break;
- }
+ if (i + 1 != e && Changes[i + 1].ContinuesPPDirective)
+ ChangeMaxColumn -= 2;
+ // If this comment follows an } in column 0, it probably documents the
+ // closing of a namespace and we don't want to align it.
+ bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 &&
+ Changes[i - 1].Kind == tok::r_brace &&
+ Changes[i - 1].StartOfTokenColumn == 0;
+ bool WasAlignedWithStartOfNextLine = false;
+ if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
+ for (unsigned j = i + 1; j != e; ++j) {
+ if (Changes[j].Kind != tok::comment) { // Skip over comments.
+ // The start of the next token was previously aligned with the
+ // start of this comment.
+ WasAlignedWithStartOfNextLine =
+ (SourceMgr.getSpellingColumnNumber(
+ Changes[i].OriginalWhitespaceRange.getEnd()) ==
+ SourceMgr.getSpellingColumnNumber(
+ Changes[j].OriginalWhitespaceRange.getEnd()));
+ break;
}
}
- if (!Style.AlignTrailingComments || FollowsRBraceInColumn0) {
- alignTrailingComments(StartOfSequence, i, MinColumn);
- MinColumn = ChangeMinColumn;
- MaxColumn = ChangeMinColumn;
- StartOfSequence = i;
- } else if (BreakBeforeNext || Newlines > 1 ||
- (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
- // Break the comment sequence if the previous line did not end
- // in a trailing comment.
- (Changes[i].NewlinesBefore == 1 && i > 0 &&
- !Changes[i - 1].IsTrailingComment) ||
- WasAlignedWithStartOfNextLine) {
- alignTrailingComments(StartOfSequence, i, MinColumn);
- MinColumn = ChangeMinColumn;
- MaxColumn = ChangeMaxColumn;
- StartOfSequence = i;
- } else {
- MinColumn = std::max(MinColumn, ChangeMinColumn);
- MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
- }
- BreakBeforeNext =
- (i == 0) || (Changes[i].NewlinesBefore > 1) ||
- // Never start a sequence with a comment at the beginning of
- // the line.
- (Changes[i].NewlinesBefore == 1 && StartOfSequence == i);
- Newlines = 0;
}
+ if (!Style.AlignTrailingComments || FollowsRBraceInColumn0) {
+ alignTrailingComments(StartOfSequence, i, MinColumn);
+ MinColumn = ChangeMinColumn;
+ MaxColumn = ChangeMinColumn;
+ StartOfSequence = i;
+ } else if (BreakBeforeNext || Newlines > 1 ||
+ (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
+ // Break the comment sequence if the previous line did not end
+ // in a trailing comment.
+ (Changes[i].NewlinesBefore == 1 && i > 0 &&
+ !Changes[i - 1].IsTrailingComment) ||
+ WasAlignedWithStartOfNextLine) {
+ alignTrailingComments(StartOfSequence, i, MinColumn);
+ MinColumn = ChangeMinColumn;
+ MaxColumn = ChangeMaxColumn;
+ StartOfSequence = i;
+ } else {
+ MinColumn = std::max(MinColumn, ChangeMinColumn);
+ MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
+ }
+ BreakBeforeNext =
+ (i == 0) || (Changes[i].NewlinesBefore > 1) ||
+ // Never start a sequence with a comment at the beginning of
+ // the line.
+ (Changes[i].NewlinesBefore == 1 && StartOfSequence == i);
+ Newlines = 0;
}
alignTrailingComments(StartOfSequence, Changes.size(), MinColumn);
}
@@ -190,15 +210,20 @@ void WhitespaceManager::alignTrailingComments() {
void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,
unsigned Column) {
for (unsigned i = Start; i != End; ++i) {
+ int Shift = 0;
if (Changes[i].IsTrailingComment) {
- assert(Column >= Changes[i].StartOfTokenColumn);
- Changes[i].Spaces += Column - Changes[i].StartOfTokenColumn;
- if (i + 1 != End) {
- Changes[i + 1].PreviousEndOfTokenColumn +=
- Column - Changes[i].StartOfTokenColumn;
- }
- Changes[i].StartOfTokenColumn = Column;
+ Shift = Column - Changes[i].StartOfTokenColumn;
+ }
+ if (Changes[i].StartOfBlockComment) {
+ Shift = Changes[i].IndentationOffset +
+ Changes[i].StartOfBlockComment->StartOfTokenColumn -
+ Changes[i].StartOfTokenColumn;
}
+ assert(Shift >= 0);
+ Changes[i].Spaces += Shift;
+ if (i + 1 != End)
+ Changes[i + 1].PreviousEndOfTokenColumn += Shift;
+ Changes[i].StartOfTokenColumn += Shift;
}
}
@@ -245,8 +270,8 @@ void WhitespaceManager::generateChanges() {
C.PreviousEndOfTokenColumn, C.EscapedNewlineColumn);
else
appendNewlineText(ReplacementText, C.NewlinesBefore);
- appendIndentText(ReplacementText, C.IndentLevel, C.Spaces,
- C.StartOfTokenColumn - C.Spaces);
+ appendIndentText(ReplacementText, C.IndentLevel, std::max(0, C.Spaces),
+ C.StartOfTokenColumn - std::max(0, C.Spaces));
ReplacementText.append(C.CurrentLinePrefix);
storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
}
diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h
index f94464ff38..189b1aefa0 100644
--- a/lib/Format/WhitespaceManager.h
+++ b/lib/Format/WhitespaceManager.h
@@ -63,6 +63,12 @@ public:
/// (in this order) at \p Offset inside \p Tok, replacing \p ReplaceChars
/// characters.
///
+ /// Note: \p Spaces can be negative to retain information about initial
+ /// relative column offset between a line of a block comment and the start of
+ /// the comment. This negative offset may be compensated by trailing comment
+ /// alignment here. In all other cases negative \p Spaces will be truncated to
+ /// 0.
+ ///
/// When \p InPPDirective is true, escaped newlines are inserted. \p Spaces is
/// used to align backslashes correctly.
void replaceWhitespaceInToken(const FormatToken &Tok, unsigned Offset,
@@ -70,7 +76,7 @@ public:
StringRef PreviousPostfix,
StringRef CurrentPrefix, bool InPPDirective,
unsigned Newlines, unsigned IndentLevel,
- unsigned Spaces);
+ int Spaces);
/// \brief Returns all the \c Replacements created during formatting.
const tooling::Replacements &generateReplacements();
@@ -101,7 +107,7 @@ private:
/// \p StartOfTokenColumn and \p InPPDirective will be used to lay out
/// trailing comments and escaped newlines.
Change(bool CreateReplacement, const SourceRange &OriginalWhitespaceRange,
- unsigned IndentLevel, unsigned Spaces, unsigned StartOfTokenColumn,
+ unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn,
unsigned NewlinesBefore, StringRef PreviousLinePostfix,
StringRef CurrentLinePrefix, tok::TokenKind Kind,
bool ContinuesPPDirective);
@@ -128,7 +134,10 @@ private:
// The number of spaces in front of the token or broken part of the token.
// This will be adapted when aligning tokens.
- unsigned Spaces;
+ // Can be negative to retain information about the initial relative offset
+ // of the lines in a block comment. This is used when aligning trailing
+ // comments. Uncompensated negative offset is truncated to 0.
+ int Spaces;
// \c IsTrailingComment, \c TokenLength, \c PreviousEndOfTokenColumn and
// \c EscapedNewlineColumn will be calculated in
@@ -137,6 +146,17 @@ private:
unsigned TokenLength;
unsigned PreviousEndOfTokenColumn;
unsigned EscapedNewlineColumn;
+
+ // These fields are used to retain correct relative line indentation in a
+ // block comment when aligning trailing comments.
+ //
+ // If this Change represents a continuation of a block comment,
+ // \c StartOfBlockComment is pointer to the first Change in the block
+ // comment. \c IndentationOffset is a relative column offset to this
+ // change, so that the correct column can be reconstructed at the end of
+ // the alignment process.
+ const Change *StartOfBlockComment;
+ int IndentationOffset;
};
/// \brief Calculate \c IsTrailingComment, \c TokenLength for the last tokens
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index c4f7596e00..009b200472 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -692,7 +692,8 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->Diagnostics = Diags;
- AST->FileMgr = new FileManager(FileSystemOpts);
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem();
+ AST->FileMgr = new FileManager(FileSystemOpts, VFS);
AST->UserFilesAreVolatile = UserFilesAreVolatile;
AST->SourceMgr = new SourceManager(AST->getDiagnostics(),
AST->getFileManager(),
@@ -1093,10 +1094,9 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
"IR inputs not support here!");
// Configure the various subsystems.
- // FIXME: Should we retain the previous file manager?
LangOpts = &Clang->getLangOpts();
FileSystemOpts = Clang->getFileSystemOpts();
- FileMgr = new FileManager(FileSystemOpts);
+ // Re-use the existing FileManager
SourceMgr = new SourceManager(getDiagnostics(), *FileMgr,
UserFilesAreVolatile);
TheSema.reset();
@@ -1598,9 +1598,14 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
TopLevelDecls.clear();
TopLevelDeclsInPreamble.clear();
PreambleDiagnostics.clear();
-
+
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+ createVFSFromCompilerInvocation(Clang->getInvocation(), getDiagnostics());
+ if (!VFS)
+ return nullptr;
+
// Create a file manager object to provide access to and cache the filesystem.
- Clang->setFileManager(new FileManager(Clang->getFileSystemOpts()));
+ Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS));
// Create the source manager.
Clang->setSourceManager(new SourceManager(getDiagnostics(),
@@ -1709,14 +1714,20 @@ void ASTUnit::RealizeTopLevelDeclsFromPreamble() {
}
void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) {
- // Steal the created target, context, and preprocessor.
+ // Steal the created target, context, and preprocessor if they have been
+ // created.
+ assert(CI.hasInvocation() && "missing invocation");
+ LangOpts = CI.getInvocation().getLangOpts();
TheSema.reset(CI.takeSema());
Consumer.reset(CI.takeASTConsumer());
- Ctx = &CI.getASTContext();
- PP = &CI.getPreprocessor();
+ if (CI.hasASTContext())
+ Ctx = &CI.getASTContext();
+ if (CI.hasPreprocessor())
+ PP = &CI.getPreprocessor();
CI.setSourceManager(0);
CI.setFileManager(0);
- Target = &CI.getTarget();
+ if (CI.hasTarget())
+ Target = &CI.getTarget();
Reader = CI.getModuleManager();
HadModuleLoaderFatalFailure = CI.hadModuleLoaderFatalFailure();
}
@@ -1758,7 +1769,11 @@ ASTUnit *ASTUnit::create(CompilerInvocation *CI,
AST->Diagnostics = Diags;
AST->Invocation = CI;
AST->FileSystemOpts = CI->getFileSystemOpts();
- AST->FileMgr = new FileManager(AST->FileSystemOpts);
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+ createVFSFromCompilerInvocation(*CI, *Diags);
+ if (!VFS)
+ return nullptr;
+ AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
AST->UserFilesAreVolatile = UserFilesAreVolatile;
AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr,
UserFilesAreVolatile);
@@ -1781,6 +1796,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
// Create the AST unit.
OwnAST.reset(create(CI, Diags, CaptureDiagnostics, UserFilesAreVolatile));
AST = OwnAST.get();
+ if (!AST)
+ return nullptr;
}
if (!ResourceFilesPath.empty()) {
@@ -1928,18 +1945,13 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
return Parse(OverrideMainBuffer);
}
-ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
- bool OnlyLocalDecls,
- bool CaptureDiagnostics,
- bool PrecompilePreamble,
- TranslationUnitKind TUKind,
- bool CacheCodeCompletionResults,
- bool IncludeBriefCommentsInCodeCompletion,
- bool UserFilesAreVolatile) {
+std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
+ CompilerInvocation *CI, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
+ bool OnlyLocalDecls, bool CaptureDiagnostics, bool PrecompilePreamble,
+ TranslationUnitKind TUKind, bool CacheCodeCompletionResults,
+ bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile) {
// Create the AST unit.
- std::unique_ptr<ASTUnit> AST;
- AST.reset(new ASTUnit(false));
+ std::unique_ptr<ASTUnit> AST(new ASTUnit(false));
ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics);
AST->Diagnostics = Diags;
AST->OnlyLocalDecls = OnlyLocalDecls;
@@ -1950,7 +1962,11 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
= IncludeBriefCommentsInCodeCompletion;
AST->Invocation = CI;
AST->FileSystemOpts = CI->getFileSystemOpts();
- AST->FileMgr = new FileManager(AST->FileSystemOpts);
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+ createVFSFromCompilerInvocation(*CI, *Diags);
+ if (!VFS)
+ return nullptr;
+ AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
AST->UserFilesAreVolatile = UserFilesAreVolatile;
// Recover resources if we crash before exiting this method.
@@ -1960,8 +1976,9 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
DiagCleanup(Diags.getPtr());
- return AST->LoadFromCompilerInvocation(PrecompilePreamble) ? 0
- : AST.release();
+ if (AST->LoadFromCompilerInvocation(PrecompilePreamble))
+ return nullptr;
+ return AST;
}
ASTUnit *ASTUnit::LoadFromCommandLine(
@@ -2017,7 +2034,11 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
AST->Diagnostics = Diags;
Diags = 0; // Zero out now to ease cleanup during crash recovery.
AST->FileSystemOpts = CI->getFileSystemOpts();
- AST->FileMgr = new FileManager(AST->FileSystemOpts);
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+ createVFSFromCompilerInvocation(*CI, *Diags);
+ if (!VFS)
+ return nullptr;
+ AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS);
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->CaptureDiagnostics = CaptureDiagnostics;
AST->TUKind = TUKind;
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index 2cb65826ad..bf1c968da1 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -17,7 +17,6 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
#include "clang/Basic/IdentifierTable.h"
-#include "clang/Basic/OnDiskHashTable.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/Preprocessor.h"
@@ -26,6 +25,7 @@
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
@@ -35,12 +35,13 @@
#endif
using namespace clang;
-using namespace clang::io;
//===----------------------------------------------------------------------===//
// PTH-specific stuff.
//===----------------------------------------------------------------------===//
+typedef uint32_t Offset;
+
namespace {
class PTHEntry {
Offset TokenData, PPCondData;
@@ -116,7 +117,10 @@ public:
typedef PTHEntry data_type;
typedef const PTHEntry& data_type_ref;
- static unsigned ComputeHash(PTHEntryKeyVariant V) {
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
+ static hash_value_type ComputeHash(PTHEntryKeyVariant V) {
return llvm::HashString(V.getString());
}
@@ -171,7 +175,7 @@ public:
};
} // end anonymous namespace
-typedef OnDiskChainedHashTableGenerator<FileEntryPTHEntryInfo> PTHMap;
+typedef llvm::OnDiskChainedHashTableGenerator<FileEntryPTHEntryInfo> PTHMap;
namespace {
class PTHWriter {
@@ -287,8 +291,11 @@ void PTHWriter::EmitToken(const Token& T) {
PTHEntry PTHWriter::LexTokens(Lexer& L) {
// Pad 0's so that we emit tokens to a 4-byte alignment.
// This speed up reading them back in.
- Pad(Out, 4);
- Offset TokenOff = (Offset) Out.tell();
+ using namespace llvm::support;
+ endian::Writer<little> LE(Out);
+ uint32_t TokenOff = Out.tell();
+ for (uint64_t N = llvm::OffsetToAlignment(TokenOff, 4); N; --N, ++TokenOff)
+ LE.write<uint8_t>(0);
// Keep track of matching '#if' ... '#endif'.
typedef std::vector<std::pair<Offset, unsigned> > PPCondTable;
@@ -595,7 +602,10 @@ public:
typedef uint32_t data_type;
typedef data_type data_type_ref;
- static unsigned ComputeHash(PTHIdKey* key) {
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
+ static hash_value_type ComputeHash(PTHIdKey* key) {
return llvm::HashString(key->II->getName());
}
@@ -636,7 +646,7 @@ std::pair<Offset,Offset> PTHWriter::EmitIdentifierTable() {
PTHIdKey *IIDMap = (PTHIdKey*)calloc(idcount, sizeof(PTHIdKey));
// Create the hashtable.
- OnDiskChainedHashTableGenerator<PTHIdentifierTableTrait> IIOffMap;
+ llvm::OnDiskChainedHashTableGenerator<PTHIdentifierTableTrait> IIOffMap;
// Generate mapping from persistent IDs -> IdentifierInfo*.
for (IDMap::iterator I = IM.begin(), E = IM.end(); I != E; ++I) {
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index ce47674edb..b74c288cda 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -31,6 +31,7 @@
#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/Sema/Sema.h"
#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Config/config.h"
#include "llvm/Support/CrashRecoveryContext.h"
@@ -49,9 +50,11 @@
using namespace clang;
-CompilerInstance::CompilerInstance()
- : Invocation(new CompilerInvocation()), ModuleManager(0),
- BuildGlobalModuleIndex(false), ModuleBuildFailed(false) {
+CompilerInstance::CompilerInstance(bool BuildingModule)
+ : ModuleLoader(BuildingModule),
+ Invocation(new CompilerInvocation()), ModuleManager(0),
+ BuildGlobalModuleIndex(false), HaveFullGlobalModuleIndex(false),
+ ModuleBuildFailed(false) {
}
CompilerInstance::~CompilerInstance() {
@@ -770,31 +773,10 @@ static InputKind getSourceInputKindFromOptions(const LangOptions &LangOpts) {
/// \brief Compile a module file for the given module, using the options
/// provided by the importing compiler instance.
-static void compileModule(CompilerInstance &ImportingInstance,
+static void compileModuleImpl(CompilerInstance &ImportingInstance,
SourceLocation ImportLoc,
Module *Module,
StringRef ModuleFileName) {
- // FIXME: have LockFileManager return an error_code so that we can
- // avoid the mkdir when the directory already exists.
- StringRef Dir = llvm::sys::path::parent_path(ModuleFileName);
- llvm::sys::fs::create_directories(Dir);
-
- llvm::LockFileManager Locked(ModuleFileName);
- switch (Locked) {
- case llvm::LockFileManager::LFS_Error:
- return;
-
- case llvm::LockFileManager::LFS_Owned:
- // We're responsible for building the module ourselves. Do so below.
- break;
-
- case llvm::LockFileManager::LFS_Shared:
- // Someone else is responsible for building the module. Wait for them to
- // finish.
- Locked.waitForUnlock();
- return;
- }
-
ModuleMap &ModMap
= ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
@@ -851,7 +833,7 @@ static void compileModule(CompilerInstance &ImportingInstance,
// Construct a compiler instance that will be used to actually create the
// module.
- CompilerInstance Instance;
+ CompilerInstance Instance(/*BuildingModule=*/true);
Instance.setInvocation(&*Invocation);
Instance.createDiagnostics(new ForwardingDiagnosticConsumer(
@@ -891,8 +873,9 @@ static void compileModule(CompilerInstance &ImportingInstance,
SourceMgr.overrideFileContents(ModuleMapFile, ModuleMapBuffer);
}
- // Construct a module-generating action.
- GenerateModuleAction CreateModuleAction(Module->IsSystem);
+ // Construct a module-generating action. Passing through Module->ModuleMap is
+ // safe because the FileManager is shared between the compiler instances.
+ GenerateModuleAction CreateModuleAction(Module->ModuleMap, Module->IsSystem);
// Execute the action to actually build the module in-place. Use a separate
// thread so that we get a stack large enough.
@@ -914,6 +897,38 @@ static void compileModule(CompilerInstance &ImportingInstance,
}
}
+static void compileModule(CompilerInstance &ImportingInstance,
+ SourceLocation ImportLoc,
+ Module *Module,
+ StringRef ModuleFileName) {
+ // FIXME: have LockFileManager return an error_code so that we can
+ // avoid the mkdir when the directory already exists.
+ StringRef Dir = llvm::sys::path::parent_path(ModuleFileName);
+ llvm::sys::fs::create_directories(Dir);
+
+ while (1) {
+ llvm::LockFileManager Locked(ModuleFileName);
+ switch (Locked) {
+ case llvm::LockFileManager::LFS_Error:
+ return;
+
+ case llvm::LockFileManager::LFS_Owned:
+ // We're responsible for building the module ourselves. Do so below.
+ break;
+
+ case llvm::LockFileManager::LFS_Shared:
+ // Someone else is responsible for building the module. Wait for them to
+ // finish.
+ if (Locked.waitForUnlock() == llvm::LockFileManager::Res_OwnerDied)
+ continue; // try again to get the lock.
+ return;
+ }
+
+ return compileModuleImpl(ImportingInstance, ImportLoc, Module,
+ ModuleFileName);
+ }
+}
+
/// \brief Diagnose differences between the current definition of the given
/// configuration macro and the definition provided on the command line.
static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro,
@@ -1085,6 +1100,43 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) {
}
}
+void CompilerInstance::createModuleManager() {
+ if (!ModuleManager) {
+ if (!hasASTContext())
+ createASTContext();
+
+ // If we're not recursively building a module, check whether we
+ // need to prune the module cache.
+ if (getSourceManager().getModuleBuildStack().empty() &&
+ getHeaderSearchOpts().ModuleCachePruneInterval > 0 &&
+ getHeaderSearchOpts().ModuleCachePruneAfter > 0) {
+ pruneModuleCache(getHeaderSearchOpts());
+ }
+
+ HeaderSearchOptions &HSOpts = getHeaderSearchOpts();
+ std::string Sysroot = HSOpts.Sysroot;
+ const PreprocessorOptions &PPOpts = getPreprocessorOpts();
+ ModuleManager = new ASTReader(getPreprocessor(), *Context,
+ Sysroot.empty() ? "" : Sysroot.c_str(),
+ PPOpts.DisablePCHValidation,
+ /*AllowASTWithCompilerErrors=*/false,
+ /*AllowConfigurationMismatch=*/false,
+ HSOpts.ModulesValidateSystemHeaders,
+ getFrontendOpts().UseGlobalModuleIndex);
+ if (hasASTConsumer()) {
+ ModuleManager->setDeserializationListener(
+ getASTConsumer().GetASTDeserializationListener());
+ getASTContext().setASTMutationListener(
+ getASTConsumer().GetASTMutationListener());
+ }
+ getASTContext().setExternalSource(ModuleManager);
+ if (hasSema())
+ ModuleManager->InitializeSema(getSema());
+ if (hasASTConsumer())
+ ModuleManager->StartTranslationUnit(&getASTConsumer());
+ }
+}
+
ModuleLoadResult
CompilerInstance::loadModule(SourceLocation ImportLoc,
ModuleIdPath Path,
@@ -1131,40 +1183,8 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
std::string ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(Module);
// If we don't already have an ASTReader, create one now.
- if (!ModuleManager) {
- if (!hasASTContext())
- createASTContext();
-
- // If we're not recursively building a module, check whether we
- // need to prune the module cache.
- if (getSourceManager().getModuleBuildStack().empty() &&
- getHeaderSearchOpts().ModuleCachePruneInterval > 0 &&
- getHeaderSearchOpts().ModuleCachePruneAfter > 0) {
- pruneModuleCache(getHeaderSearchOpts());
- }
-
- HeaderSearchOptions &HSOpts = getHeaderSearchOpts();
- std::string Sysroot = HSOpts.Sysroot;
- const PreprocessorOptions &PPOpts = getPreprocessorOpts();
- ModuleManager = new ASTReader(getPreprocessor(), *Context,
- Sysroot.empty() ? "" : Sysroot.c_str(),
- PPOpts.DisablePCHValidation,
- /*AllowASTWithCompilerErrors=*/false,
- /*AllowConfigurationMismatch=*/false,
- HSOpts.ModulesValidateSystemHeaders,
- getFrontendOpts().UseGlobalModuleIndex);
- if (hasASTConsumer()) {
- ModuleManager->setDeserializationListener(
- getASTConsumer().GetASTDeserializationListener());
- getASTContext().setASTMutationListener(
- getASTConsumer().GetASTMutationListener());
- }
- getASTContext().setExternalSource(ModuleManager);
- if (hasSema())
- ModuleManager->InitializeSema(getSema());
- if (hasASTConsumer())
- ModuleManager->StartTranslationUnit(&getASTConsumer());
- }
+ if (!ModuleManager)
+ createModuleManager();
if (TheDependencyFileGenerator)
TheDependencyFileGenerator->AttachToASTReader(*ModuleManager);
@@ -1391,3 +1411,84 @@ void CompilerInstance::makeModuleVisible(Module *Mod,
ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc, Complain);
}
+GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex(
+ SourceLocation TriggerLoc) {
+ if (!ModuleManager)
+ createModuleManager();
+ // Can't do anything if we don't have the module manager.
+ if (!ModuleManager)
+ return 0;
+ // Get an existing global index. This loads it if not already
+ // loaded.
+ ModuleManager->loadGlobalIndex();
+ GlobalModuleIndex *GlobalIndex = ModuleManager->getGlobalIndex();
+ // If the global index doesn't exist, create it.
+ if (!GlobalIndex && shouldBuildGlobalModuleIndex() && hasFileManager() &&
+ hasPreprocessor()) {
+ llvm::sys::fs::create_directories(
+ getPreprocessor().getHeaderSearchInfo().getModuleCachePath());
+ GlobalModuleIndex::writeIndex(
+ getFileManager(),
+ getPreprocessor().getHeaderSearchInfo().getModuleCachePath());
+ ModuleManager->resetForReload();
+ ModuleManager->loadGlobalIndex();
+ GlobalIndex = ModuleManager->getGlobalIndex();
+ }
+ // For finding modules needing to be imported for fixit messages,
+ // we need to make the global index cover all modules, so we do that here.
+ if (!HaveFullGlobalModuleIndex && GlobalIndex && !buildingModule()) {
+ ModuleMap &MMap = getPreprocessor().getHeaderSearchInfo().getModuleMap();
+ bool RecreateIndex = false;
+ for (ModuleMap::module_iterator I = MMap.module_begin(),
+ E = MMap.module_end(); I != E; ++I) {
+ Module *TheModule = I->second;
+ const FileEntry *Entry = TheModule->getASTFile();
+ if (!Entry) {
+ SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
+ Path.push_back(std::make_pair(
+ getPreprocessor().getIdentifierInfo(TheModule->Name), TriggerLoc));
+ std::reverse(Path.begin(), Path.end());
+ // Load a module as hidden. This also adds it to the global index.
+ loadModule(TheModule->DefinitionLoc, Path,
+ Module::Hidden, false);
+ RecreateIndex = true;
+ }
+ }
+ if (RecreateIndex) {
+ GlobalModuleIndex::writeIndex(
+ getFileManager(),
+ getPreprocessor().getHeaderSearchInfo().getModuleCachePath());
+ ModuleManager->resetForReload();
+ ModuleManager->loadGlobalIndex();
+ GlobalIndex = ModuleManager->getGlobalIndex();
+ }
+ HaveFullGlobalModuleIndex = true;
+ }
+ return GlobalIndex;
+}
+
+// Check global module index for missing imports.
+bool
+CompilerInstance::lookupMissingImports(StringRef Name,
+ SourceLocation TriggerLoc) {
+ // Look for the symbol in non-imported modules, but only if an error
+ // actually occurred.
+ if (!buildingModule()) {
+ // Load global module index, or retrieve a previously loaded one.
+ GlobalModuleIndex *GlobalIndex = loadGlobalModuleIndex(
+ TriggerLoc);
+
+ // Only if we have a global index.
+ if (GlobalIndex) {
+ GlobalModuleIndex::HitSet FoundModules;
+
+ // Find the modules that reference the identifier.
+ // Note that this only finds top-level modules.
+ // We'll let diagnoseTypo find the actual declaration module.
+ if (GlobalIndex->lookupIdentifier(Name, FoundModules))
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index b9706e8263..d10edd81ea 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -8,12 +8,12 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/CompilerInvocation.h"
-#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Util.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/LangStandard.h"
#include "clang/Frontend/Utils.h"
#include "clang/Lex/HeaderSearchOptions.h"
@@ -520,6 +520,17 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.DependentLibraries = Args.getAllArgValues(OPT_dependent_lib);
+ if (Arg *A = Args.getLastArg(OPT_Rpass_EQ)) {
+ StringRef Val = A->getValue();
+ std::string RegexError;
+ Opts.OptimizationRemarkPattern = std::make_shared<llvm::Regex>(Val);
+ if (!Opts.OptimizationRemarkPattern->isValid(RegexError)) {
+ Diags.Report(diag::err_drv_optimization_remark_pattern)
+ << RegexError << A->getAsString(Args);
+ Opts.OptimizationRemarkPattern.reset();
+ }
+ }
+
return Success;
}
@@ -1343,7 +1354,12 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.Blocks = Args.hasArg(OPT_fblocks);
Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional);
Opts.Modules = Args.hasArg(OPT_fmodules);
- Opts.ModulesDeclUse = Args.hasArg(OPT_fmodules_decluse);
+ Opts.ModulesStrictDeclUse = Args.hasArg(OPT_fmodules_strict_decluse);
+ Opts.ModulesDeclUse =
+ Args.hasArg(OPT_fmodules_decluse) || Opts.ModulesStrictDeclUse;
+ Opts.ModulesSearchAll = Opts.Modules &&
+ !Args.hasArg(OPT_fno_modules_search_all) &&
+ Args.hasArg(OPT_fmodules_search_all);
Opts.CharIsSigned = Opts.OpenCL || !Args.hasArg(OPT_fno_signed_char);
Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar);
Opts.ShortWChar = Args.hasFlag(OPT_fshort_wchar, OPT_fno_short_wchar, false);
@@ -1905,4 +1921,31 @@ void BuryPointer(const void *Ptr) {
return;
GraveYard[Idx] = Ptr;
}
+
+IntrusiveRefCntPtr<vfs::FileSystem>
+createVFSFromCompilerInvocation(const CompilerInvocation &CI,
+ DiagnosticsEngine &Diags) {
+ if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty())
+ return vfs::getRealFileSystem();
+
+ IntrusiveRefCntPtr<vfs::OverlayFileSystem>
+ Overlay(new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
+ // earlier vfs files are on the bottom
+ for (const std::string &File : CI.getHeaderSearchOpts().VFSOverlayFiles) {
+ std::unique_ptr<llvm::MemoryBuffer> Buffer;
+ if (llvm::errc::success != llvm::MemoryBuffer::getFile(File, Buffer)) {
+ Diags.Report(diag::err_missing_vfs_overlay_file) << File;
+ return IntrusiveRefCntPtr<vfs::FileSystem>();
+ }
+
+ IntrusiveRefCntPtr<vfs::FileSystem> FS =
+ vfs::getVFSFromYAML(Buffer.release(), /*DiagHandler*/0);
+ if (!FS.getPtr()) {
+ Diags.Report(diag::err_invalid_vfs_overlay) << File;
+ return IntrusiveRefCntPtr<vfs::FileSystem>();
+ }
+ Overlay->pushOverlay(FS);
+ }
+ return Overlay;
}
+} // end namespace clang
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index d2ece7e732..8b05849f90 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -211,30 +211,13 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
return true;
}
- if (!CI.getHeaderSearchOpts().VFSOverlayFiles.empty()) {
- IntrusiveRefCntPtr<vfs::OverlayFileSystem>
- Overlay(new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
- // earlier vfs files are on the bottom
- const std::vector<std::string> &Files =
- CI.getHeaderSearchOpts().VFSOverlayFiles;
- for (std::vector<std::string>::const_iterator I = Files.begin(),
- E = Files.end();
- I != E; ++I) {
- std::unique_ptr<llvm::MemoryBuffer> Buffer;
- if (llvm::errc::success != llvm::MemoryBuffer::getFile(*I, Buffer)) {
- CI.getDiagnostics().Report(diag::err_missing_vfs_overlay_file) << *I;
- goto failure;
- }
-
- IntrusiveRefCntPtr<vfs::FileSystem> FS =
- vfs::getVFSFromYAML(Buffer.release(), /*DiagHandler*/ 0);
- if (!FS.getPtr()) {
- CI.getDiagnostics().Report(diag::err_invalid_vfs_overlay) << *I;
- goto failure;
- }
- Overlay->pushOverlay(FS);
- }
- CI.setVirtualFileSystem(Overlay);
+ if (!CI.hasVirtualFileSystem()) {
+ if (IntrusiveRefCntPtr<vfs::FileSystem> VFS =
+ createVFSFromCompilerInvocation(CI.getInvocation(),
+ CI.getDiagnostics()))
+ CI.setVirtualFileSystem(VFS);
+ else
+ goto failure;
}
// Set up the file and source managers, if needed.
@@ -256,6 +239,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!BeginSourceFileAction(CI, InputFile))
goto failure;
+ // Initialize the main file entry.
+ if (!CI.InitializeSourceManager(CurrentInput))
+ goto failure;
+
return true;
}
@@ -302,6 +289,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!BeginSourceFileAction(CI, InputFile))
goto failure;
+ // Initialize the main file entry. It is important that this occurs after
+ // BeginSourceFileAction, which may change CurrentInput during module builds.
+ if (!CI.InitializeSourceManager(CurrentInput))
+ goto failure;
+
// Create the AST context and consumer unless this is a preprocessor only
// action.
if (!usesPreprocessorOnly()) {
@@ -389,13 +381,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
bool FrontendAction::Execute() {
CompilerInstance &CI = getCompilerInstance();
- // Initialize the main file entry. This needs to be delayed until after PCH
- // has loaded.
- if (!isCurrentFileAST()) {
- if (!CI.InitializeSourceManager(getCurrentInput()))
- return false;
- }
-
if (CI.hasFrontendTimer()) {
llvm::TimeRegion Timer(CI.getFrontendTimer());
ExecuteAction();
@@ -423,16 +408,16 @@ void FrontendAction::EndSourceFile() {
// Finalize the action.
EndSourceFileAction();
- // Release the consumer and the AST, in that order since the consumer may
- // perform actions in its destructor which require the context.
+ // Sema references the ast consumer, so reset sema first.
//
// FIXME: There is more per-file stuff we could just drop here?
- if (CI.getFrontendOpts().DisableFree) {
- BuryPointer(CI.takeASTConsumer());
+ bool DisableFree = CI.getFrontendOpts().DisableFree;
+ if (DisableFree) {
if (!isCurrentFileAST()) {
- BuryPointer(CI.takeSema());
+ CI.resetAndLeakSema();
CI.resetAndLeakASTContext();
}
+ BuryPointer(CI.takeASTConsumer());
} else {
if (!isCurrentFileAST()) {
CI.setSema(0);
@@ -458,8 +443,9 @@ void FrontendAction::EndSourceFile() {
// FrontendAction.
CI.clearOutputFiles(/*EraseFiles=*/shouldEraseOutputFiles());
+ // FIXME: Only do this if DisableFree is set.
if (isCurrentFileAST()) {
- CI.takeSema();
+ CI.resetAndLeakSema();
CI.resetAndLeakASTContext();
CI.resetAndLeakPreprocessor();
CI.resetAndLeakSourceManager();
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 2657c9878b..3d65ae32c0 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -213,7 +213,7 @@ collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr,
// If this header is marked 'unavailable' in this module, don't include
// it.
if (const FileEntry *Header = FileMgr.getFile(Dir->path())) {
- if (ModMap.isHeaderInUnavailableModule(Header))
+ if (ModMap.isHeaderUnavailableInModule(Header, Module))
continue;
Module->addTopHeader(Header);
}
@@ -288,7 +288,8 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
if (!Module->isAvailable(CI.getLangOpts(), CI.getTarget(), Requirement,
MissingHeader)) {
if (MissingHeader.FileNameLoc.isValid()) {
- CI.getDiagnostics().Report(diag::err_module_header_missing)
+ CI.getDiagnostics().Report(MissingHeader.FileNameLoc,
+ diag::err_module_header_missing)
<< MissingHeader.IsUmbrella << MissingHeader.FileName;
} else {
CI.getDiagnostics().Report(diag::err_module_unavailable)
@@ -299,6 +300,11 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
return false;
}
+ if (!ModuleMapForUniquing)
+ ModuleMapForUniquing = ModuleMap;
+ Module->ModuleMap = ModuleMapForUniquing;
+ assert(Module->ModuleMap && "missing module map file");
+
FileManager &FileMgr = CI.getFileManager();
// Collect the set of #includes we need to build the module.
@@ -337,10 +343,9 @@ bool GenerateModuleAction::ComputeASTConsumerArguments(CompilerInstance &CI,
// in the module cache.
if (CI.getFrontendOpts().OutputFile.empty()) {
HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
- SmallString<256> ModuleFileName(HS.getModuleCachePath());
- llvm::sys::path::append(ModuleFileName,
- CI.getLangOpts().CurrentModule + ".pcm");
- CI.getFrontendOpts().OutputFile = ModuleFileName.str();
+ CI.getFrontendOpts().OutputFile =
+ HS.getModuleFileName(CI.getLangOpts().CurrentModule,
+ ModuleMapForUniquing->getName());
}
// We use createOutputFile here because this is exposed via libclang, and we
@@ -412,6 +417,13 @@ namespace {
return ASTReaderListener::ReadFullVersionInformation(FullVersion);
}
+ void ReadModuleName(StringRef ModuleName) override {
+ Out.indent(2) << "Module name: " << ModuleName << "\n";
+ }
+ void ReadModuleMapFile(StringRef ModuleMapPath) override {
+ Out.indent(2) << "Module map file: " << ModuleMapPath << "\n";
+ }
+
bool ReadLanguageOptions(const LangOptions &LangOpts,
bool Complain) override {
Out.indent(2) << "Language options:\n";
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 761dba427e..a86fe51426 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -508,10 +508,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
}
if (LangOpts.MicrosoftExt) {
- // Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however
- // VC++ appears to only like __FUNCTION__.
- Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__");
- // Work around some issues with Visual C++ headers.
if (LangOpts.WChar) {
// wchar_t supported as a keyword.
Builder.defineMacro("_WCHAR_T_DEFINED");
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index 994a8f74ed..e0516146b1 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -81,7 +81,11 @@ static void printDiagnosticOptions(raw_ostream &OS,
StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
if (!Opt.empty()) {
- OS << (Started ? "," : " [") << "-W" << Opt;
+ OS << (Started ? "," : " [")
+ << (DiagnosticIDs::isRemark(Info.getID()) ? "-R" : "-W") << Opt;
+ StringRef OptValue = Info.getDiags()->getFlagNameValue();
+ if (!OptValue.empty())
+ OS << "=" << OptValue;
Started = true;
}
}
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 0221a5550c..d6d0115655 100644
--- a/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -491,11 +491,12 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
}
// Construct new directive.
- Directive *D = Directive::create(RegexKind, Pos, ExpectedLoc, Text,
- Min, Max);
+ std::unique_ptr<Directive> D(
+ Directive::create(RegexKind, Pos, ExpectedLoc, Text, Min, Max));
+
std::string Error;
if (D->isValid(Error)) {
- DL->push_back(D);
+ DL->push_back(D.release());
FoundDirective = true;
} else {
Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
@@ -846,9 +847,7 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() {
// Reset the buffer, we have processed all the diagnostics in it.
Buffer.reset(new TextDiagnosticBuffer());
- ED.Errors.clear();
- ED.Warnings.clear();
- ED.Notes.clear();
+ ED.Reset();
}
Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc,
@@ -880,5 +879,6 @@ Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc,
}
}
- return new RegexDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max, RegexStr);
+ return new RegexDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max,
+ RegexStr);
}
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index d0c26848a3..23b2446cff 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -45,7 +45,7 @@ set(files
xopintrin.h
cpuid.h
unwind.h
- module.map
+ module.modulemap
)
set(output_dir ${LLVM_LIBRARY_OUTPUT_INTDIR}/clang/${CLANG_VERSION}/include)
diff --git a/lib/Headers/Intrin.h b/lib/Headers/Intrin.h
index e365abe9a7..aa66ee6c61 100644
--- a/lib/Headers/Intrin.h
+++ b/lib/Headers/Intrin.h
@@ -100,11 +100,9 @@ static __inline__
unsigned int __popcnt(unsigned int);
static __inline__
unsigned short __popcnt16(unsigned short);
-static __inline__
-unsigned __int64 __rdtsc(void);
-unsigned __int64 __rdtscp(unsigned int *);
unsigned long __readcr0(void);
unsigned long __readcr2(void);
+static __inline__
unsigned long __readcr3(void);
unsigned long __readcr4(void);
unsigned long __readcr8(void);
@@ -119,6 +117,7 @@ unsigned __int64 __readfsqword(unsigned long);
static __inline__
unsigned short __readfsword(unsigned long);
#endif
+static __inline__
unsigned __int64 __readmsr(unsigned long);
unsigned __int64 __readpmc(unsigned long);
unsigned long __segmentlimit(unsigned long);
@@ -143,6 +142,7 @@ void __vmx_off(void);
void __vmx_vmptrst(unsigned __int64 *);
void __wbinvd(void);
void __writecr0(unsigned int);
+static __inline__
void __writecr3(unsigned int);
void __writecr4(unsigned int);
void __writecr8(unsigned int);
@@ -981,6 +981,35 @@ __halt(void) {
__asm__ volatile ("hlt");
}
+/*----------------------------------------------------------------------------*\
+|* Privileged intrinsics
+\*----------------------------------------------------------------------------*/
+static __inline__ unsigned __int64 __attribute__((__always_inline__, __nodebug__))
+__readmsr(unsigned long __register) {
+ // Loads the contents of a 64-bit model specific register (MSR) specified in
+ // the ECX register into registers EDX:EAX. The EDX register is loaded with
+ // the high-order 32 bits of the MSR and the EAX register is loaded with the
+ // low-order 32 bits. If less than 64 bits are implemented in the MSR being
+ // read, the values returned to EDX:EAX in unimplemented bit locations are
+ // undefined.
+ unsigned long __edx;
+ unsigned long __eax;
+ __asm__ ("rdmsr" : "=d"(__edx), "=a"(__eax) : "c"(__register));
+ return (((unsigned __int64)__edx) << 32) | (unsigned __int64)__eax;
+}
+
+static __inline__ unsigned long __attribute__((always_inline, __nodebug__))
+__readcr3(void) {
+ unsigned long __cr3_val;
+ __asm__ __volatile__ ("mov %%cr3, %0" : "=q"(__cr3_val) : : "memory");
+ return __cr3_val;
+}
+
+static __inline__ void __attribute__((always_inline, __nodebug__))
+__writecr3(unsigned int __cr3_val) {
+ __asm__ ("mov %0, %%cr3" : : "q"(__cr3_val) : "memory");
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/Headers/Makefile b/lib/Headers/Makefile
index 42219c4082..903acacc8a 100644
--- a/lib/Headers/Makefile
+++ b/lib/Headers/Makefile
@@ -32,13 +32,13 @@ $(HeaderDir)/arm_neon.h: $(BUILT_SOURCES) $(HeaderDir)/.dir
$(Verb) cp $< $@
$(Echo) Copying $(notdir $<) to build dir
-$(HeaderDir)/module.map: $(PROJ_SRC_DIR)/module.map $(HeaderDir)/.dir
+$(HeaderDir)/module.modulemap: $(PROJ_SRC_DIR)/module.modulemap $(HeaderDir)/.dir
$(Verb) cp $< $@
$(Echo) Copying $(notdir $<) to build dir
# Hook into the standard Makefile rules.
-all-local:: $(OBJHEADERS) $(HeaderDir)/module.map
+all-local:: $(OBJHEADERS) $(HeaderDir)/module.modulemap
PROJ_headers := $(DESTDIR)$(PROJ_prefix)/lib/clang/$(CLANG_VERSION)/include
@@ -52,12 +52,12 @@ $(INSTHEADERS): $(PROJ_headers)/%.h: $(HeaderDir)/%.h | $(PROJ_headers)
$(Verb) $(DataInstall) $< $(PROJ_headers)
$(Echo) Installing compiler include file: $(notdir $<)
-$(PROJ_headers)/module.map: $(HeaderDir)/module.map | $(PROJ_headers)
+$(PROJ_headers)/module.modulemap: $(HeaderDir)/module.modulemap | $(PROJ_headers)
$(Verb) $(DataInstall) $< $(PROJ_headers)
$(Echo) Installing compiler module map file: $(notdir $<)
-install-local:: $(INSTHEADERS) $(PROJ_headers)/module.map
+install-local:: $(INSTHEADERS) $(PROJ_headers)/module.modulemap
$(ObjDir)/arm_neon.h.inc.tmp : $(CLANG_LEVEL)/include/clang/Basic/arm_neon.td $(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang arm_neon.h.inc with tblgen"
diff --git a/lib/Headers/ia32intrin.h b/lib/Headers/ia32intrin.h
index a5985f660b..55c22473ba 100644
--- a/lib/Headers/ia32intrin.h
+++ b/lib/Headers/ia32intrin.h
@@ -82,9 +82,13 @@ __writeeflags(unsigned int __f)
/* __rdtsc */
static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
__rdtsc(void) {
- unsigned int __eax, __edx;
- __asm__ ("rdtsc" : "=a" (__eax), "=d" (__edx));
- return ((unsigned long long)__edx << 32) | __eax;
+ return __builtin_ia32_rdtsc();
+}
+
+/* __rdtscp */
+static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__))
+__rdtscp(unsigned int *__A) {
+ return __builtin_ia32_rdtscp(__A);
}
#define _rdtsc() __rdtsc()
diff --git a/lib/Headers/module.map b/lib/Headers/module.modulemap
index 9f7944dedb..9f7944dedb 100644
--- a/lib/Headers/module.map
+++ b/lib/Headers/module.modulemap
diff --git a/lib/Index/CommentToXML.cpp b/lib/Index/CommentToXML.cpp
index 43c423274d..eb5a0c8363 100644
--- a/lib/Index/CommentToXML.cpp
+++ b/lib/Index/CommentToXML.cpp
@@ -563,6 +563,7 @@ public:
// Helpers.
void appendToResultWithXMLEscaping(StringRef S);
+ void appendToResultWithCDATAEscaping(StringRef S);
void formatTextOfDeclaration(const DeclInfo *DI,
SmallString<128> &Declaration);
@@ -667,14 +668,27 @@ void CommentASTToXMLConverter::visitInlineCommandComment(
void CommentASTToXMLConverter::visitHTMLStartTagComment(
const HTMLStartTagComment *C) {
- Result << "<rawHTML><![CDATA[";
- printHTMLStartTagComment(C, Result);
- Result << "]]></rawHTML>";
+ Result << "<rawHTML";
+ if (C->isSafeToPassThrough())
+ Result << " isSafeToPassThrough=\"1\"";
+ Result << ">";
+ {
+ SmallString<32> Tag;
+ {
+ llvm::raw_svector_ostream TagOS(Tag);
+ printHTMLStartTagComment(C, TagOS);
+ }
+ appendToResultWithCDATAEscaping(Tag);
+ }
+ Result << "</rawHTML>";
}
void
CommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
- Result << "<rawHTML>&lt;/" << C->getTagName() << "&gt;</rawHTML>";
+ Result << "<rawHTML";
+ if (C->isSafeToPassThrough())
+ Result << " isSafeToPassThrough=\"1\"";
+ Result << ">&lt;/" << C->getTagName() << "&gt;</rawHTML>";
}
void
@@ -1100,6 +1114,31 @@ void CommentASTToXMLConverter::appendToResultWithXMLEscaping(StringRef S) {
}
}
+void CommentASTToXMLConverter::appendToResultWithCDATAEscaping(StringRef S) {
+ if (S.empty())
+ return;
+
+ Result << "<![CDATA[";
+ while (!S.empty()) {
+ size_t Pos = S.find("]]>");
+ if (Pos == 0) {
+ Result << "]]]]><![CDATA[>";
+ S = S.drop_front(3);
+ continue;
+ }
+ if (Pos == StringRef::npos)
+ Pos = S.size();
+
+ Result << S.substr(0, Pos);
+
+ S = S.drop_front(Pos);
+ }
+ Result << "]]>";
+}
+
+CommentToXMLConverter::CommentToXMLConverter() : FormatInMemoryUniqueId(0) {}
+CommentToXMLConverter::~CommentToXMLConverter() {}
+
void CommentToXMLConverter::convertCommentToHTML(const FullComment *FC,
SmallVectorImpl<char> &HTML,
const ASTContext &Context) {
@@ -1119,13 +1158,10 @@ void CommentToXMLConverter::convertHTMLTagNodeToText(
void CommentToXMLConverter::convertCommentToXML(const FullComment *FC,
SmallVectorImpl<char> &XML,
const ASTContext &Context) {
- if (!FormatContext) {
- FormatContext = new SimpleFormatContext(Context.getLangOpts());
- } else if ((FormatInMemoryUniqueId % 1000) == 0) {
- // Delete after some number of iterations, so the buffers don't grow
- // too large.
- delete FormatContext;
- FormatContext = new SimpleFormatContext(Context.getLangOpts());
+ if (!FormatContext || (FormatInMemoryUniqueId % 1000) == 0) {
+ // Create a new format context, or re-create it after some number of
+ // iterations, so the buffers don't grow too large.
+ FormatContext.reset(new SimpleFormatContext(Context.getLangOpts()));
}
CommentASTToXMLConverter Converter(FC, XML, Context.getCommentCommandTraits(),
diff --git a/lib/Index/SimpleFormatContext.h b/lib/Index/SimpleFormatContext.h
index fde43aed21..99d0d9a1ce 100644
--- a/lib/Index/SimpleFormatContext.h
+++ b/lib/Index/SimpleFormatContext.h
@@ -51,7 +51,7 @@ public:
llvm::MemoryBuffer::getMemBuffer(Content);
const FileEntry *Entry =
Files.getVirtualFile(Name, Source->getBufferSize(), 0);
- Sources.overrideFileContents(Entry, Source, true);
+ Sources.overrideFileContents(Entry, Source);
assert(Entry != NULL);
return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
}
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index f081024706..87a5053628 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -18,6 +18,8 @@
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Capacity.h"
#include "llvm/Support/FileSystem.h"
@@ -112,24 +114,33 @@ const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) {
}
std::string HeaderSearch::getModuleFileName(Module *Module) {
- // If we don't have a module cache path, we can't do anything.
- if (ModuleCachePath.empty())
- return std::string();
-
-
- SmallString<256> Result(ModuleCachePath);
- llvm::sys::path::append(Result, Module->getTopLevelModule()->Name + ".pcm");
- return Result.str().str();
+ return getModuleFileName(Module->Name, Module->ModuleMap->getName());
}
-std::string HeaderSearch::getModuleFileName(StringRef ModuleName) {
+std::string HeaderSearch::getModuleFileName(StringRef ModuleName,
+ StringRef ModuleMapPath) {
// If we don't have a module cache path, we can't do anything.
if (ModuleCachePath.empty())
return std::string();
-
-
+
SmallString<256> Result(ModuleCachePath);
- llvm::sys::path::append(Result, ModuleName + ".pcm");
+ llvm::sys::fs::make_absolute(Result);
+
+ if (HSOpts->DisableModuleHash) {
+ llvm::sys::path::append(Result, ModuleName + ".pcm");
+ } else {
+ // Construct the name <ModuleName>-<hash of ModuleMapPath>.pcm which should
+ // be globally unique to this particular module. To avoid false-negatives
+ // on case-insensitive filesystems, we use lower-case, which is safe because
+ // to cause a collision the modules must have the same name, which is an
+ // error if they are imported in the same translation.
+ SmallString<256> AbsModuleMapPath(ModuleMapPath);
+ llvm::sys::fs::make_absolute(AbsModuleMapPath);
+ llvm::APInt Code(64, llvm::hash_value(AbsModuleMapPath.str().lower()));
+ SmallString<128> HashStr;
+ Code.toStringUnsigned(HashStr, /*Radix*/36);
+ llvm::sys::path::append(Result, ModuleName + "-" + HashStr.str() + ".pcm");
+ }
return Result.str().str();
}
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 86d01d6cc8..0955cc5b33 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -2251,8 +2251,6 @@ static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr,
#ifdef __SSE2__
#include <emmintrin.h>
-#elif __AVX2__
-#include <avx2intrin.h>
#elif __ALTIVEC__
#include <altivec.h>
#undef bool
@@ -2308,33 +2306,17 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr,
// If there is a code-completion point avoid the fast scan because it
// doesn't check for '\0'.
!(PP && PP->getCodeCompletionFileLoc() == FileLoc)) {
-#ifndef __AVX2__
// While not aligned to a 16-byte boundary.
while (C != '/' && ((intptr_t)CurPtr & 0x0F) != 0)
C = *CurPtr++;
-#endif
if (C == '/') goto FoundSlash;
#ifdef __SSE2__
-#define VECTOR_TYPE __m128i
-#define SET1_EPI8(v) _mm_set1_epi8(v)
-#define CMPEQ_EPI8(v1,v2) _mm_cmpeq_epi8(v1,v2)
-#define MOVEMASK_EPI8(v) _mm_movemask_epi8(v)
-#define STEP 16
-#elif __AVX2__
-#define VECTOR_TYPE __m256i
-#define SET1_EPI8(v) _mm256_set1_epi8(v)
-#define CMPEQ_EPI8(v1,v2) _mm256_cmpeq_epi8(v1,v2)
-#define MOVEMASK_EPI8(v) _mm256_movemask_epi8(v)
-#define STEP 32
-#endif
-
-#if defined(__SSE2__) || defined(__AVX2__)
- VECTOR_TYPE Slashes = SET1_EPI8('/');
- while (CurPtr+STEP <= BufferEnd) {
- int cmp = MOVEMASK_EPI8(CMPEQ_EPI8(*(const VECTOR_TYPE*)CurPtr,
- Slashes));
+ __m128i Slashes = _mm_set1_epi8('/');
+ while (CurPtr+16 <= BufferEnd) {
+ int cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(*(const __m128i*)CurPtr,
+ Slashes));
if (cmp != 0) {
// Adjust the pointer to point directly after the first slash. It's
// not necessary to set C here, it will be overwritten at the end of
@@ -2342,13 +2324,8 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr,
CurPtr += llvm::countTrailingZeros<unsigned>(cmp) + 1;
goto FoundSlash;
}
- CurPtr += STEP;
+ CurPtr += 16;
}
-#undef VECTOR_TYPE
-#undef SET1_EPI8
-#undef CMPEQ_EPI8
-#undef MOVEMASK_EPI8
-#undef STEP
#elif __ALTIVEC__
__vector unsigned char Slashes = {
'/', '/', '/', '/', '/', '/', '/', '/',
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index ddfa10c698..80e025def7 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -765,6 +765,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
s++;
saw_period = true;
const char *floatDigitsBegin = s;
+ checkSeparator(TokLoc, s, CSK_BeforeDigits);
s = SkipHexDigits(s);
noSignificand &= (floatDigitsBegin == s);
}
@@ -779,6 +780,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
// A binary exponent can appear with or with a '.'. If dotted, the
// binary exponent is required.
if (*s == 'p' || *s == 'P') {
+ checkSeparator(TokLoc, s, CSK_AfterDigits);
const char *Exponent = s;
s++;
saw_exponent = true;
@@ -790,6 +792,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
hadError = true;
return;
}
+ checkSeparator(TokLoc, s, CSK_BeforeDigits);
s = first_non_digit;
if (!PP.getLangOpts().HexFloats)
@@ -858,9 +861,11 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
s++;
radix = 10;
saw_period = true;
+ checkSeparator(TokLoc, s, CSK_BeforeDigits);
s = SkipDigits(s); // Skip suffix.
}
if (*s == 'e' || *s == 'E') { // exponent
+ checkSeparator(TokLoc, s, CSK_AfterDigits);
const char *Exponent = s;
s++;
radix = 10;
@@ -868,6 +873,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
if (*s == '+' || *s == '-') s++; // sign
const char *first_non_digit = SkipDigits(s);
if (first_non_digit != s) {
+ checkSeparator(TokLoc, s, CSK_BeforeDigits);
s = first_non_digit;
} else {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Exponent-ThisTokBegin),
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
index 0325a80c3b..8547ad3f72 100644
--- a/lib/Lex/MacroInfo.cpp
+++ b/lib/Lex/MacroInfo.cpp
@@ -29,7 +29,8 @@ MacroInfo::MacroInfo(SourceLocation DefLoc)
IsUsed(false),
IsAllowRedefinitionsWithoutWarning(false),
IsWarnIfUnused(false),
- FromASTFile(false) {
+ FromASTFile(false),
+ UsedForHeaderGuard(false) {
}
unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const {
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index e78806dc50..39c1121011 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -170,6 +170,38 @@ ModuleMap::findKnownHeader(const FileEntry *File) {
return Known;
}
+ModuleMap::KnownHeader
+ModuleMap::findHeaderInUmbrellaDirs(const FileEntry *File,
+ SmallVectorImpl<const DirectoryEntry *> &IntermediateDirs) {
+ const DirectoryEntry *Dir = File->getDir();
+ assert(Dir && "file in no directory");
+
+ // Note: as an egregious but useful hack we use the real path here, because
+ // frameworks moving from top-level frameworks to embedded frameworks tend
+ // to be symlinked from the top-level location to the embedded location,
+ // and we need to resolve lookups as if we had found the embedded location.
+ StringRef DirName = SourceMgr.getFileManager().getCanonicalName(Dir);
+
+ // Keep walking up the directory hierarchy, looking for a directory with
+ // an umbrella header.
+ do {
+ auto KnownDir = UmbrellaDirs.find(Dir);
+ if (KnownDir != UmbrellaDirs.end())
+ return KnownHeader(KnownDir->second, NormalHeader);
+
+ IntermediateDirs.push_back(Dir);
+
+ // Retrieve our parent path.
+ DirName = llvm::sys::path::parent_path(DirName);
+ if (DirName.empty())
+ break;
+
+ // Resolve the parent path to a directory entry.
+ Dir = SourceMgr.getFileManager().getDirectory(DirName);
+ } while (Dir);
+ return KnownHeader();
+}
+
// Returns 'true' if 'RequestingModule directly uses 'RequestedModule'.
static bool directlyUses(const Module *RequestingModule,
const Module *RequestedModule) {
@@ -211,8 +243,12 @@ void ModuleMap::diagnoseHeaderInclusion(Module *RequestingModule,
resolveUses(RequestingModule, /*Complain=*/false);
HeadersMap::iterator Known = findKnownHeader(File);
- if (Known == Headers.end())
+ if (Known == Headers.end()) {
+ if (LangOpts.ModulesStrictDeclUse)
+ Diags.Report(FilenameLoc, diag::error_undeclared_use_of_module)
+ << RequestingModule->getFullModuleName() << Filename;
return;
+ }
Module *Private = NULL;
Module *NotUsed = NULL;
@@ -305,121 +341,111 @@ ModuleMap::findModuleForHeader(const FileEntry *File,
return Result;
}
- const DirectoryEntry *Dir = File->getDir();
SmallVector<const DirectoryEntry *, 2> SkippedDirs;
-
- // Note: as an egregious but useful hack we use the real path here, because
- // frameworks moving from top-level frameworks to embedded frameworks tend
- // to be symlinked from the top-level location to the embedded location,
- // and we need to resolve lookups as if we had found the embedded location.
- StringRef DirName = SourceMgr.getFileManager().getCanonicalName(Dir);
-
- // Keep walking up the directory hierarchy, looking for a directory with
- // an umbrella header.
- do {
- llvm::DenseMap<const DirectoryEntry *, Module *>::iterator KnownDir
- = UmbrellaDirs.find(Dir);
- if (KnownDir != UmbrellaDirs.end()) {
- Module *Result = KnownDir->second;
-
- // Search up the module stack until we find a module with an umbrella
- // directory.
- Module *UmbrellaModule = Result;
- while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent)
- UmbrellaModule = UmbrellaModule->Parent;
-
- if (UmbrellaModule->InferSubmodules) {
- // Infer submodules for each of the directories we found between
- // the directory of the umbrella header and the directory where
- // the actual header is located.
- bool Explicit = UmbrellaModule->InferExplicitSubmodules;
-
- for (unsigned I = SkippedDirs.size(); I != 0; --I) {
- // Find or create the module that corresponds to this directory name.
- SmallString<32> NameBuf;
- StringRef Name = sanitizeFilenameAsIdentifier(
- llvm::sys::path::stem(SkippedDirs[I-1]->getName()),
- NameBuf);
- Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
- Explicit).first;
-
- // Associate the module and the directory.
- UmbrellaDirs[SkippedDirs[I-1]] = Result;
-
- // If inferred submodules export everything they import, add a
- // wildcard to the set of exports.
- if (UmbrellaModule->InferExportWildcard && Result->Exports.empty())
- Result->Exports.push_back(Module::ExportDecl(0, true));
- }
-
- // Infer a submodule with the same name as this header file.
+ KnownHeader H = findHeaderInUmbrellaDirs(File, SkippedDirs);
+ if (H) {
+ Module *Result = H.getModule();
+
+ // Search up the module stack until we find a module with an umbrella
+ // directory.
+ Module *UmbrellaModule = Result;
+ while (!UmbrellaModule->getUmbrellaDir() && UmbrellaModule->Parent)
+ UmbrellaModule = UmbrellaModule->Parent;
+
+ if (UmbrellaModule->InferSubmodules) {
+ // Infer submodules for each of the directories we found between
+ // the directory of the umbrella header and the directory where
+ // the actual header is located.
+ bool Explicit = UmbrellaModule->InferExplicitSubmodules;
+
+ for (unsigned I = SkippedDirs.size(); I != 0; --I) {
+ // Find or create the module that corresponds to this directory name.
SmallString<32> NameBuf;
StringRef Name = sanitizeFilenameAsIdentifier(
- llvm::sys::path::stem(File->getName()), NameBuf);
- Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
- Explicit).first;
- Result->addTopHeader(File);
-
- // If inferred submodules export everything they import, add a
+ llvm::sys::path::stem(SkippedDirs[I-1]->getName()), NameBuf);
+ Result = findOrCreateModule(Name, Result, UmbrellaModule->ModuleMap,
+ /*IsFramework=*/false, Explicit).first;
+ Result->IsInferred = true;
+
+ // Associate the module and the directory.
+ UmbrellaDirs[SkippedDirs[I-1]] = Result;
+
+ // If inferred submodules export everything they import, add a
// wildcard to the set of exports.
if (UmbrellaModule->InferExportWildcard && Result->Exports.empty())
Result->Exports.push_back(Module::ExportDecl(0, true));
- } else {
- // Record each of the directories we stepped through as being part of
- // the module we found, since the umbrella header covers them all.
- for (unsigned I = 0, N = SkippedDirs.size(); I != N; ++I)
- UmbrellaDirs[SkippedDirs[I]] = Result;
}
-
- Headers[File].push_back(KnownHeader(Result, NormalHeader));
- // If a header corresponds to an unavailable module, don't report
- // that it maps to anything.
- if (!Result->isAvailable())
- return KnownHeader();
-
- return Headers[File].back();
+ // Infer a submodule with the same name as this header file.
+ SmallString<32> NameBuf;
+ StringRef Name = sanitizeFilenameAsIdentifier(
+ llvm::sys::path::stem(File->getName()), NameBuf);
+ Result = findOrCreateModule(Name, Result, UmbrellaModule->ModuleMap,
+ /*IsFramework=*/false, Explicit).first;
+ Result->IsInferred = true;
+ Result->addTopHeader(File);
+
+ // If inferred submodules export everything they import, add a
+ // wildcard to the set of exports.
+ if (UmbrellaModule->InferExportWildcard && Result->Exports.empty())
+ Result->Exports.push_back(Module::ExportDecl(0, true));
+ } else {
+ // Record each of the directories we stepped through as being part of
+ // the module we found, since the umbrella header covers them all.
+ for (unsigned I = 0, N = SkippedDirs.size(); I != N; ++I)
+ UmbrellaDirs[SkippedDirs[I]] = Result;
}
-
- SkippedDirs.push_back(Dir);
-
- // Retrieve our parent path.
- DirName = llvm::sys::path::parent_path(DirName);
- if (DirName.empty())
- break;
-
- // Resolve the parent path to a directory entry.
- Dir = SourceMgr.getFileManager().getDirectory(DirName);
- } while (Dir);
+
+ Headers[File].push_back(KnownHeader(Result, NormalHeader));
+
+ // If a header corresponds to an unavailable module, don't report
+ // that it maps to anything.
+ if (!Result->isAvailable())
+ return KnownHeader();
+
+ return Headers[File].back();
+ }
return KnownHeader();
}
bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
+ return isHeaderUnavailableInModule(Header, 0);
+}
+
+bool
+ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header,
+ const Module *RequestingModule) const {
HeadersMap::const_iterator Known = Headers.find(Header);
if (Known != Headers.end()) {
for (SmallVectorImpl<KnownHeader>::const_iterator
I = Known->second.begin(),
E = Known->second.end();
I != E; ++I) {
- if (I->isAvailable())
+ if (I->isAvailable() && (!RequestingModule ||
+ I->getModule()->isSubModuleOf(RequestingModule)))
return false;
}
return true;
}
-
+
const DirectoryEntry *Dir = Header->getDir();
SmallVector<const DirectoryEntry *, 2> SkippedDirs;
StringRef DirName = Dir->getName();
+ auto IsUnavailable = [&](const Module *M) {
+ return !M->isAvailable() && (!RequestingModule ||
+ M->isSubModuleOf(RequestingModule));
+ };
+
// Keep walking up the directory hierarchy, looking for a directory with
// an umbrella header.
- do {
+ do {
llvm::DenseMap<const DirectoryEntry *, Module *>::const_iterator KnownDir
= UmbrellaDirs.find(Dir);
if (KnownDir != UmbrellaDirs.end()) {
Module *Found = KnownDir->second;
- if (!Found->isAvailable())
+ if (IsUnavailable(Found))
return true;
// Search up the module stack until we find a module with an umbrella
@@ -438,7 +464,7 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
Found = lookupModuleQualified(Name, Found);
if (!Found)
return false;
- if (!Found->isAvailable())
+ if (IsUnavailable(Found))
return true;
}
@@ -452,7 +478,7 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
return false;
}
- return !Found->isAvailable();
+ return IsUnavailable(Found);
}
SkippedDirs.push_back(Dir);
@@ -495,15 +521,16 @@ Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) const{
}
std::pair<Module *, bool>
-ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
+ModuleMap::findOrCreateModule(StringRef Name, Module *Parent,
+ const FileEntry *ModuleMap, bool IsFramework,
bool IsExplicit) {
// Try to find an existing module with this name.
if (Module *Sub = lookupModuleQualified(Name, Parent))
return std::make_pair(Sub, false);
// Create a new module with this name.
- Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,
- IsExplicit);
+ Module *Result = new Module(Name, SourceLocation(), Parent, ModuleMap,
+ IsFramework, IsExplicit);
if (LangOpts.CurrentModule == Name) {
SourceModule = Result;
SourceModuleName = Name;
@@ -572,6 +599,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// If the framework has a parent path from which we're allowed to infer
// a framework module, do so.
+ const FileEntry *ModuleMapFile = nullptr;
if (!Parent) {
// Determine whether we're allowed to infer a module map.
@@ -616,6 +644,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
if (inferred->second.InferSystemModules)
IsSystem = true;
+ ModuleMapFile = inferred->second.ModuleMapFile;
}
}
}
@@ -623,7 +652,8 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// If we're not allowed to infer a framework module, don't.
if (!canInfer)
return 0;
- }
+ } else
+ ModuleMapFile = Parent->ModuleMap;
// Look for an umbrella header.
@@ -637,7 +667,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
if (!UmbrellaHeader)
return 0;
- Module *Result = new Module(ModuleName, SourceLocation(), Parent,
+ Module *Result = new Module(ModuleName, SourceLocation(), Parent, ModuleMapFile,
/*IsFramework=*/true, /*IsExplicit=*/false);
if (LangOpts.CurrentModule == ModuleName) {
SourceModule = Result;
@@ -931,6 +961,9 @@ namespace clang {
DiagnosticsEngine &Diags;
ModuleMap &Map;
+
+ /// \brief The current module map file.
+ const FileEntry *ModuleMapFile;
/// \brief The directory that this module map resides in.
const DirectoryEntry *Directory;
@@ -976,20 +1009,20 @@ namespace clang {
void parseConflict();
void parseInferredModuleDecl(bool Framework, bool Explicit);
bool parseOptionalAttributes(Attributes &Attrs);
-
- const DirectoryEntry *getOverriddenHeaderSearchDir();
public:
explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
const TargetInfo *Target,
DiagnosticsEngine &Diags,
ModuleMap &Map,
+ const FileEntry *ModuleMapFile,
const DirectoryEntry *Directory,
const DirectoryEntry *BuiltinIncludeDir,
bool IsSystem)
: L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),
- Directory(Directory), BuiltinIncludeDir(BuiltinIncludeDir),
- IsSystem(IsSystem), HadError(false), ActiveModule(0)
+ ModuleMapFile(ModuleMapFile), Directory(Directory),
+ BuiltinIncludeDir(BuiltinIncludeDir), IsSystem(IsSystem),
+ HadError(false), ActiveModule(0)
{
Tok.clear();
consumeToken();
@@ -1336,9 +1369,14 @@ void ModuleMapParser::parseModuleDecl() {
return;
}
+ // If this is a submodule, use the parent's module map, since we don't want
+ // the private module map file.
+ const FileEntry *ModuleMap = ActiveModule ? ActiveModule->ModuleMap
+ : ModuleMapFile;
+
// Start defining this module.
- ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework,
- Explicit).first;
+ ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, ModuleMap,
+ Framework, Explicit).first;
ActiveModule->DefinitionLoc = ModuleNameLoc;
if (Attrs.IsSystem || IsSystem)
ActiveModule->IsSystem = true;
@@ -1441,6 +1479,15 @@ void ModuleMapParser::parseModuleDecl() {
inferFrameworkLink(ActiveModule, Directory, SourceMgr.getFileManager());
}
+ // If the module meets all requirements but is still unavailable, mark the
+ // whole tree as unavailable to prevent it from building.
+ if (!ActiveModule->IsAvailable && !ActiveModule->IsMissingRequirement &&
+ ActiveModule->Parent) {
+ ActiveModule->getTopLevelModule()->markUnavailable();
+ ActiveModule->getTopLevelModule()->MissingHeaders.append(
+ ActiveModule->MissingHeaders.begin(), ActiveModule->MissingHeaders.end());
+ }
+
// We're done parsing this module. Pop back to the previous module.
ActiveModule = PreviousActiveModule;
}
@@ -1591,10 +1638,6 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
if (llvm::sys::path::is_absolute(Header.FileName)) {
PathName = Header.FileName;
File = SourceMgr.getFileManager().getFile(PathName);
- } else if (const DirectoryEntry *Dir = getOverriddenHeaderSearchDir()) {
- PathName = Dir->getName();
- llvm::sys::path::append(PathName, Header.FileName);
- File = SourceMgr.getFileManager().getFile(PathName);
} else {
// Search for the header file within the search directory.
PathName = Directory->getName();
@@ -1673,9 +1716,8 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
// If we find a module that has a missing header, we mark this module as
// unavailable and store the header directive for displaying diagnostics.
- // Other submodules in the same module can still be used.
Header.IsUmbrella = LeadingToken == MMToken::UmbrellaKeyword;
- ActiveModule->IsAvailable = false;
+ ActiveModule->markUnavailable();
ActiveModule->MissingHeaders.push_back(Header);
}
}
@@ -1948,7 +1990,8 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
if (ActiveModule) {
// Inferred modules must have umbrella directories.
- if (!Failed && !ActiveModule->getUmbrellaDir()) {
+ if (!Failed && ActiveModule->IsAvailable &&
+ !ActiveModule->getUmbrellaDir()) {
Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella);
Failed = true;
}
@@ -1997,6 +2040,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
// We'll be inferring framework modules for this directory.
Map.InferredDirectories[Directory].InferModules = true;
Map.InferredDirectories[Directory].InferSystemModules = Attrs.IsSystem;
+ Map.InferredDirectories[Directory].ModuleMapFile = ModuleMapFile;
// FIXME: Handle the 'framework' keyword.
}
@@ -2146,22 +2190,6 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) {
return HadError;
}
-/// \brief If there is a specific header search directory due the presence
-/// of an umbrella directory, retrieve that directory. Otherwise, returns null.
-const DirectoryEntry *ModuleMapParser::getOverriddenHeaderSearchDir() {
- for (Module *Mod = ActiveModule; Mod; Mod = Mod->Parent) {
- // If we have an umbrella directory, use that.
- if (Mod->hasUmbrellaDir())
- return Mod->getUmbrellaDir();
-
- // If we have a framework directory, stop looking.
- if (Mod->IsFramework)
- return 0;
- }
-
- return 0;
-}
-
/// \brief Parse a module map file.
///
/// module-map-file:
@@ -2233,7 +2261,7 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem) {
// Parse this module map file.
Lexer L(ID, SourceMgr.getBuffer(ID), SourceMgr, MMapLangOpts);
- ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, Dir,
+ ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir,
BuiltinIncludeDir, IsSystem);
bool Result = Parser.parseModuleMapFile();
ParsedModuleMap[File] = Result;
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index 949cd63262..0b1be09d87 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -284,6 +284,10 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
if (const FileEntry *FE =
SourceMgr.getFileEntryForID(CurPPLexer->getFileID())) {
HeaderInfo.SetFileControllingMacro(FE, ControllingMacro);
+ if (MacroInfo *MI =
+ getMacroInfo(const_cast<IdentifierInfo*>(ControllingMacro))) {
+ MI->UsedForHeaderGuard = true;
+ }
if (const IdentifierInfo *DefinedMacro =
CurPPLexer->MIOpt.GetDefinedMacro()) {
if (!ControllingMacro->hasMacroDefinition() &&
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 35f9192d38..cd96f8cf34 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -115,6 +115,7 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__has_include = RegisterBuiltinMacro(*this, "__has_include");
Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next");
Ident__has_warning = RegisterBuiltinMacro(*this, "__has_warning");
+ Ident__is_identifier = RegisterBuiltinMacro(*this, "__is_identifier");
// Modules.
if (LangOpts.Modules) {
@@ -885,7 +886,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("attribute_unused_on_fields", true)
.Case("blocks", LangOpts.Blocks)
.Case("c_thread_safety_attributes", true)
- .Case("cxx_exceptions", LangOpts.Exceptions)
+ .Case("cxx_exceptions", LangOpts.CXXExceptions)
.Case("cxx_rtti", LangOpts.RTTI)
.Case("enumerator_attributes", true)
.Case("memory_sanitizer", LangOpts.Sanitize.Memory)
@@ -1359,6 +1360,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
} else if (II == Ident__has_feature ||
II == Ident__has_extension ||
II == Ident__has_builtin ||
+ II == Ident__is_identifier ||
II == Ident__has_attribute) {
// The argument to these builtins should be a parenthesized identifier.
SourceLocation StartLoc = Tok.getLocation();
@@ -1382,6 +1384,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
bool Value = false;
if (!IsValid)
Diag(StartLoc, diag::err_feature_check_malformed);
+ else if (II == Ident__is_identifier)
+ Value = FeatureII->getTokenID() == tok::identifier;
else if (II == Ident__has_builtin) {
// Check for a builtin is trivial.
Value = FeatureII->getBuiltinID() != 0;
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index 1ca16d39b4..b888f2ed9b 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -15,7 +15,6 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
#include "clang/Basic/IdentifierTable.h"
-#include "clang/Basic/OnDiskHashTable.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/PTHManager.h"
@@ -25,10 +24,10 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/system_error.h"
#include <memory>
using namespace clang;
-using namespace clang::io;
#define DISK_TOKEN_SIZE (1+1+2+4+4)
@@ -319,8 +318,10 @@ public:
class PTHFileLookupCommonTrait {
public:
typedef std::pair<unsigned char, const char*> internal_key_type;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
- static unsigned ComputeHash(internal_key_type x) {
+ static hash_value_type ComputeHash(internal_key_type x) {
return llvm::HashString(x.second);
}
@@ -364,13 +365,11 @@ public:
class PTHStringLookupTrait {
public:
- typedef uint32_t
- data_type;
-
- typedef const std::pair<const char*, unsigned>
- external_key_type;
-
+ typedef uint32_t data_type;
+ typedef const std::pair<const char*, unsigned> external_key_type;
typedef external_key_type internal_key_type;
+ typedef uint32_t hash_value_type;
+ typedef unsigned offset_type;
static bool EqualKey(const internal_key_type& a,
const internal_key_type& b) {
@@ -378,7 +377,7 @@ public:
: false;
}
- static unsigned ComputeHash(const internal_key_type& a) {
+ static hash_value_type ComputeHash(const internal_key_type& a) {
return llvm::HashString(StringRef(a.first, a.second));
}
@@ -409,8 +408,8 @@ public:
} // end anonymous namespace
-typedef OnDiskChainedHashTable<PTHFileLookupTrait> PTHFileLookup;
-typedef OnDiskChainedHashTable<PTHStringLookupTrait> PTHStringIdLookup;
+typedef llvm::OnDiskChainedHashTable<PTHFileLookupTrait> PTHFileLookup;
+typedef llvm::OnDiskChainedHashTable<PTHStringLookupTrait> PTHStringIdLookup;
//===----------------------------------------------------------------------===//
// PTHManager methods.
@@ -693,7 +692,7 @@ public:
};
class PTHStatCache : public FileSystemStatCache {
- typedef OnDiskChainedHashTable<PTHStatLookupTrait> CacheTy;
+ typedef llvm::OnDiskChainedHashTable<PTHStatLookupTrait> CacheTy;
CacheTy Cache;
public:
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 331c5e42fd..07e606c986 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -261,7 +261,7 @@ void Parser::ParseAttributeWithTypeArg(IdentifierInfo &AttrName,
0, AttrNameLoc, 0, 0, AttributeList::AS_GNU);
}
-void Parser::ParseAttributeArgsCommon(
+unsigned Parser::ParseAttributeArgsCommon(
IdentifierInfo *AttrName, SourceLocation AttrNameLoc,
ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName,
SourceLocation ScopeLoc, AttributeList::Syntax Syntax) {
@@ -302,7 +302,7 @@ void Parser::ParseAttributeArgsCommon(
ExprResult ArgExpr(ParseAssignmentExpression());
if (ArgExpr.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
- return;
+ return 0;
}
ArgExprs.push_back(ArgExpr.release());
// Eat the comma, move to the next argument
@@ -318,6 +318,8 @@ void Parser::ParseAttributeArgsCommon(
if (EndLoc)
*EndLoc = RParen;
+
+ return static_cast<unsigned>(ArgExprs.size());
}
/// Parse the arguments to a parameterized GNU attribute or
@@ -392,6 +394,8 @@ bool Parser::ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName,
return false;
}
+ SourceLocation OpenParenLoc = Tok.getLocation();
+
if (AttrName->getName() == "property") {
// The property declspec is more complex in that it can take one or two
// assignment expressions as a parameter, but the lhs of the assignment
@@ -505,8 +509,17 @@ bool Parser::ParseMicrosoftDeclSpecArgs(IdentifierInfo *AttrName,
return !HasInvalidAccessor;
}
- ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, nullptr, nullptr,
- SourceLocation(), AttributeList::AS_Declspec);
+ unsigned NumArgs =
+ ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, nullptr, nullptr,
+ SourceLocation(), AttributeList::AS_Declspec);
+
+ // If this attribute's args were parsed, and it was expected to have
+ // arguments but none were provided, emit a diagnostic.
+ const AttributeList *Attr = Attrs.getList();
+ if (Attr && Attr->getMaxArgs() && !NumArgs) {
+ Diag(OpenParenLoc, diag::err_attribute_requires_arguments) << AttrName;
+ return false;
+ }
return true;
}
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index cef748f2aa..7ef04730ac 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1541,18 +1541,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
}
// Build the class template specialization.
- TagOrTempResult
- = Actions.ActOnClassTemplateSpecialization(getCurScope(), TagType, TUK,
- StartLoc, DS.getModulePrivateSpecLoc(), SS,
- TemplateId->Template,
- TemplateId->TemplateNameLoc,
- TemplateId->LAngleLoc,
- TemplateArgsPtr,
- TemplateId->RAngleLoc,
- attrs.getList(),
- MultiTemplateParamsArg(
- TemplateParams? &(*TemplateParams)[0] : 0,
- TemplateParams? TemplateParams->size() : 0));
+ TagOrTempResult = Actions.ActOnClassTemplateSpecialization(
+ getCurScope(), TagType, TUK, StartLoc, DS.getModulePrivateSpecLoc(),
+ *TemplateId, attrs.getList(),
+ MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0] : 0,
+ TemplateParams ? TemplateParams->size() : 0));
}
} else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
TUK == Sema::TUK_Declaration) {
@@ -2648,6 +2641,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
continue;
}
+ if (Tok.is(tok::annot_pragma_ms_pragma)) {
+ HandlePragmaMSPragma();
+ continue;
+ }
+
// If we see a namespace here, a close brace was missing somewhere.
if (Tok.is(tok::kw_namespace)) {
DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl));
@@ -3189,6 +3187,7 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
switch (AttributeList::getKind(AttrName, ScopeName,
AttributeList::AS_CXX11)) {
case AttributeList::AT_CarriesDependency:
+ case AttributeList::AT_Deprecated:
case AttributeList::AT_FallThrough:
case AttributeList::AT_CXX11NoReturn: {
return true;
@@ -3220,6 +3219,7 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
IdentifierInfo *ScopeName,
SourceLocation ScopeLoc) {
assert(Tok.is(tok::l_paren) && "Not a C++11 attribute argument list");
+ SourceLocation LParenLoc = Tok.getLocation();
// If the attribute isn't known, we will not attempt to parse any
// arguments.
@@ -3236,9 +3236,33 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,
// behaviors.
ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
ScopeLoc, AttributeList::AS_CXX11, 0);
- else
- ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
- ScopeLoc, AttributeList::AS_CXX11);
+ else {
+ unsigned NumArgs =
+ ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc,
+ ScopeName, ScopeLoc, AttributeList::AS_CXX11);
+
+ const AttributeList *Attr = Attrs.getList();
+ if (Attr && IsBuiltInOrStandardCXX11Attribute(AttrName, ScopeName)) {
+ // If the attribute is a standard or built-in attribute and we are
+ // parsing an argument list, we need to determine whether this attribute
+ // was allowed to have an argument list (such as [[deprecated]]), and how
+ // many arguments were parsed (so we can diagnose on [[deprecated()]]).
+ if (Attr->getMaxArgs() && !NumArgs) {
+ // The attribute was allowed to have arguments, but none were provided
+ // even though the attribute parsed successfully. This is an error.
+ // FIXME: This is a good place for a fixit which removes the parens.
+ Diag(LParenLoc, diag::err_attribute_requires_arguments) << AttrName;
+ return false;
+ } else if (!Attr->getMaxArgs()) {
+ // The attribute parsed successfully, but was not allowed to have any
+ // arguments. It doesn't matter whether any were provided -- the
+ // presence of the argument list (even if empty) is diagnosed.
+ Diag(LParenLoc, diag::err_cxx11_attribute_forbids_arguments)
+ << AttrName;
+ return false;
+ }
+ }
+ }
return true;
}
@@ -3319,14 +3343,9 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
<< AttrName << SourceRange(SeenAttrs[AttrName]);
// Parse attribute arguments
- if (Tok.is(tok::l_paren)) {
- if (StandardAttr)
- Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments)
- << AttrName->getName();
-
+ if (Tok.is(tok::l_paren))
AttrParsed = ParseCXX11AttributeArgs(AttrName, AttrLoc, attrs, endLoc,
ScopeName, ScopeLoc);
- }
if (!AttrParsed)
attrs.addNew(AttrName,
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index ed9d72d338..15b327d1ef 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -835,6 +835,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2]
case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU]
case tok::kw___FUNCDNAME__: // primary-expression: __FUNCDNAME__ [MS]
+ case tok::kw___FUNCSIG__: // primary-expression: __FUNCSIG__ [MS]
case tok::kw_L__FUNCTION__: // primary-expression: L__FUNCTION__ [MS]
case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU]
Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind);
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index f10ca6ab78..614949c935 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -365,15 +365,15 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// Consume the template-id token.
ConsumeToken();
-
+
assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
SourceLocation CCLoc = ConsumeToken();
HasScopeSpecifier = true;
-
+
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
-
+
if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(),
SS,
TemplateId->TemplateKWLoc,
@@ -393,7 +393,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
continue;
}
-
// The rest of the nested-name-specifier possibilities start with
// tok::identifier.
if (Tok.isNot(tok::identifier))
@@ -418,9 +417,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
// error, but they probably meant something else strange so don't
// recover like this.
PP.LookAhead(1).is(tok::identifier)) {
- Diag(Next, diag::err_unexected_colon_in_nested_name_spec)
+ Diag(Next, diag::err_unexpected_colon_in_nested_name_spec)
<< FixItHint::CreateReplacement(Next.getLocation(), "::");
-
// Recover as if the user wrote '::'.
Next.setKind(tok::coloncolon);
}
@@ -434,23 +432,52 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
return false;
}
+ if (ColonIsSacred) {
+ const Token &Next2 = GetLookAheadToken(2);
+ if (Next2.is(tok::kw_private) || Next2.is(tok::kw_protected) ||
+ Next2.is(tok::kw_public) || Next2.is(tok::kw_virtual)) {
+ Diag(Next2, diag::err_unexpected_token_in_nested_name_spec)
+ << Next2.getName()
+ << FixItHint::CreateReplacement(Next.getLocation(), ":");
+ Token ColonColon;
+ PP.Lex(ColonColon);
+ ColonColon.setKind(tok::colon);
+ PP.EnterToken(ColonColon);
+ break;
+ }
+ }
+
if (LastII)
*LastII = &II;
// We have an identifier followed by a '::'. Lookup this name
// as the name in a nested-name-specifier.
+ Token Identifier = Tok;
SourceLocation IdLoc = ConsumeToken();
assert((Tok.is(tok::coloncolon) || Tok.is(tok::colon)) &&
"NextToken() not working properly!");
+ Token ColonColon = Tok;
SourceLocation CCLoc = ConsumeToken();
CheckForLParenAfterColonColon();
- HasScopeSpecifier = true;
+ bool IsCorrectedToColon = false;
+ bool *CorrectionFlagPtr = ColonIsSacred ? &IsCorrectedToColon : 0;
if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), II, IdLoc, CCLoc,
- ObjectType, EnteringContext, SS))
+ ObjectType, EnteringContext, SS,
+ false, CorrectionFlagPtr)) {
+ // Identifier is not recognized as a nested name, but we can have
+ // mistyped '::' instead of ':'.
+ if (CorrectionFlagPtr && IsCorrectedToColon) {
+ ColonColon.setKind(tok::colon);
+ PP.EnterToken(Tok);
+ PP.EnterToken(ColonColon);
+ Tok = Identifier;
+ break;
+ }
SS.SetInvalid(SourceRange(IdLoc, CCLoc));
-
+ }
+ HasScopeSpecifier = true;
continue;
}
@@ -837,8 +864,8 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
// [..., x = expr
//
// We need to find the end of the following expression in order to
- // determine whether this is an Obj-C message send's receiver, or a
- // lambda init-capture.
+ // determine whether this is an Obj-C message send's receiver, a
+ // C99 designator, or a lambda init-capture.
//
// Parse the expression to find where it ends, and annotate it back
// onto the tokens. We would have parsed this expression the same way
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 44053f193b..bdd4513167 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -66,45 +66,29 @@ bool Parser::MayBeDesignationStart() {
}
// Parse up to (at most) the token after the closing ']' to determine
- // whether this is a C99 designator or a lambda.
+ // whether this is a C99 designator or a lambda.
TentativeParsingAction Tentative(*this);
- ConsumeBracket();
- while (true) {
- switch (Tok.getKind()) {
- case tok::equal:
- case tok::amp:
- case tok::identifier:
- case tok::kw_this:
- // These tokens can occur in a capture list or a constant-expression.
- // Keep looking.
- ConsumeToken();
- continue;
-
- case tok::comma:
- // Since a comma cannot occur in a constant-expression, this must
- // be a lambda.
- Tentative.Revert();
- return false;
-
- case tok::r_square: {
- // Once we hit the closing square bracket, we look at the next
- // token. If it's an '=', this is a designator. Otherwise, it's a
- // lambda expression. This decision favors lambdas over the older
- // GNU designator syntax, which allows one to omit the '=', but is
- // consistent with GCC.
- ConsumeBracket();
- tok::TokenKind Kind = Tok.getKind();
- Tentative.Revert();
- return Kind == tok::equal;
- }
-
- default:
- // Anything else cannot occur in a lambda capture list, so it
- // must be a designator.
- Tentative.Revert();
- return true;
- }
+
+ LambdaIntroducer Intro;
+ bool SkippedInits = false;
+ Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro, &SkippedInits));
+
+ if (DiagID) {
+ // If this can't be a lambda capture list, it's a designator.
+ Tentative.Revert();
+ return true;
}
+
+ // Once we hit the closing square bracket, we look at the next
+ // token. If it's an '=', this is a designator. Otherwise, it's a
+ // lambda expression. This decision favors lambdas over the older
+ // GNU designator syntax, which allows one to omit the '=', but is
+ // consistent with GCC.
+ tok::TokenKind Kind = Tok.getKind();
+ // FIXME: If we didn't skip any inits, parse the lambda from here
+ // rather than throwing away then reparsing the LambdaIntroducer.
+ Tentative.Revert();
+ return Kind == tok::equal;
}
static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index f1b61077b3..bf3753fd81 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -258,7 +258,7 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
///
/// clause:
/// if-clause | num_threads-clause | safelen-clause | default-clause |
-/// private-clause | firstprivate-clause | shared-clause
+/// private-clause | firstprivate-clause | shared-clause | linear-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
@@ -301,6 +301,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
+ case OMPC_linear:
case OMPC_copyin:
Clause = ParseOpenMPVarListClause(CKind);
break;
@@ -392,10 +393,13 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
/// 'firstprivate' '(' list ')'
/// shared-clause:
/// 'shared' '(' list ')'
+/// linear-clause:
+/// 'linear' '(' list [ ':' linear-step ] ')'
///
OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
SourceLocation Loc = Tok.getLocation();
SourceLocation LOpen = ConsumeToken();
+ SourceLocation ColonLoc = SourceLocation();
// Parse '('.
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
if (T.expectAndConsume(diag::err_expected_lparen_after,
@@ -404,8 +408,10 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
SmallVector<Expr *, 5> Vars;
bool IsComma = true;
- while (IsComma || (Tok.isNot(tok::r_paren) &&
+ const bool MayHaveTail = (Kind == OMPC_linear);
+ while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
Tok.isNot(tok::annot_pragma_openmp_end))) {
+ ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
// Parse variable
ExprResult VarExpr = ParseAssignmentExpression();
if (VarExpr.isUsable()) {
@@ -416,21 +422,34 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
}
// Skip ',' if any
IsComma = Tok.is(tok::comma);
- if (IsComma) {
+ if (IsComma)
ConsumeToken();
- } else if (Tok.isNot(tok::r_paren) &&
- Tok.isNot(tok::annot_pragma_openmp_end)) {
- Diag(Tok, diag::err_omp_expected_punc)
- << getOpenMPClauseName(Kind);
- }
+ else if (Tok.isNot(tok::r_paren) &&
+ Tok.isNot(tok::annot_pragma_openmp_end) &&
+ (!MayHaveTail || Tok.isNot(tok::colon)))
+ Diag(Tok, diag::err_omp_expected_punc) << getOpenMPClauseName(Kind);
+ }
+
+ // Parse ':' linear-step
+ Expr *TailExpr = 0;
+ const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon);
+ if (MustHaveTail) {
+ ColonLoc = Tok.getLocation();
+ ConsumeToken();
+ ExprResult Tail = ParseAssignmentExpression();
+ if (Tail.isUsable())
+ TailExpr = Tail.take();
+ else
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
}
// Parse ')'.
T.consumeClose();
- if (Vars.empty())
+ if (Vars.empty() || (MustHaveTail && !TailExpr))
return 0;
- return Actions.ActOnOpenMPVarListClause(Kind, Vars, Loc, LOpen,
- Tok.getLocation());
+ return Actions.ActOnOpenMPVarListClause(Kind, Vars, TailExpr, Loc, LOpen,
+ ColonLoc, Tok.getLocation());
}
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 29e17715b3..4b687a8b2e 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "RAIIObjectsForParser.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
@@ -124,6 +125,12 @@ struct PragmaMSVtorDisp : public PragmaHandler {
Token &FirstToken) override;
};
+struct PragmaMSPragma : public PragmaHandler {
+ explicit PragmaMSPragma(const char *name) : PragmaHandler(name) {}
+ void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken) override;
+};
+
} // end namespace
void Parser::initializePragmaHandlers() {
@@ -175,6 +182,18 @@ void Parser::initializePragmaHandlers() {
PP.AddPragmaHandler(MSPointersToMembers.get());
MSVtorDisp.reset(new PragmaMSVtorDisp());
PP.AddPragmaHandler(MSVtorDisp.get());
+ MSInitSeg.reset(new PragmaMSPragma("init_seg"));
+ PP.AddPragmaHandler(MSInitSeg.get());
+ MSDataSeg.reset(new PragmaMSPragma("data_seg"));
+ PP.AddPragmaHandler(MSDataSeg.get());
+ MSBSSSeg.reset(new PragmaMSPragma("bss_seg"));
+ PP.AddPragmaHandler(MSBSSSeg.get());
+ MSConstSeg.reset(new PragmaMSPragma("const_seg"));
+ PP.AddPragmaHandler(MSConstSeg.get());
+ MSCodeSeg.reset(new PragmaMSPragma("code_seg"));
+ PP.AddPragmaHandler(MSCodeSeg.get());
+ MSSection.reset(new PragmaMSPragma("section"));
+ PP.AddPragmaHandler(MSSection.get());
}
}
@@ -214,6 +233,18 @@ void Parser::resetPragmaHandlers() {
MSPointersToMembers.reset();
PP.RemovePragmaHandler(MSVtorDisp.get());
MSVtorDisp.reset();
+ PP.RemovePragmaHandler(MSInitSeg.get());
+ MSInitSeg.reset();
+ PP.RemovePragmaHandler(MSDataSeg.get());
+ MSDataSeg.reset();
+ PP.RemovePragmaHandler(MSBSSSeg.get());
+ MSBSSSeg.reset();
+ PP.RemovePragmaHandler(MSConstSeg.get());
+ MSConstSeg.reset();
+ PP.RemovePragmaHandler(MSCodeSeg.get());
+ MSCodeSeg.reset();
+ PP.RemovePragmaHandler(MSSection.get());
+ MSSection.reset();
}
PP.RemovePragmaHandler("STDC", FPContractHandler.get());
@@ -400,6 +431,145 @@ void Parser::HandlePragmaMSVtorDisp() {
Actions.ActOnPragmaMSVtorDisp(Kind, PragmaLoc, Mode);
}
+void Parser::HandlePragmaMSPragma() {
+ assert(Tok.is(tok::annot_pragma_ms_pragma));
+ // Grab the tokens out of the annotation and enter them into the stream.
+ auto TheTokens = (std::pair<Token*, size_t> *)Tok.getAnnotationValue();
+ PP.EnterTokenStream(TheTokens->first, TheTokens->second, true, true);
+ SourceLocation PragmaLocation = ConsumeToken(); // The annotation token.
+ assert(Tok.isAnyIdentifier());
+ llvm::StringRef PragmaName = Tok.getIdentifierInfo()->getName();
+ PP.Lex(Tok); // pragma kind
+ // Figure out which #pragma we're dealing with. The switch has no default
+ // because lex shouldn't emit the annotation token for unrecognized pragmas.
+ typedef unsigned (Parser::*PragmaHandler)(llvm::StringRef, SourceLocation);
+ PragmaHandler Handler = llvm::StringSwitch<PragmaHandler>(PragmaName)
+ .Case("data_seg", &Parser::HandlePragmaMSSegment)
+ .Case("bss_seg", &Parser::HandlePragmaMSSegment)
+ .Case("const_seg", &Parser::HandlePragmaMSSegment)
+ .Case("code_seg", &Parser::HandlePragmaMSSegment)
+ .Case("section", &Parser::HandlePragmaMSSection)
+ .Case("init_seg", &Parser::HandlePragmaMSInitSeg);
+ if (auto DiagID = (this->*Handler)(PragmaName, PragmaLocation)) {
+ PP.Diag(PragmaLocation, DiagID) << PragmaName;
+ while (Tok.isNot(tok::eof))
+ PP.Lex(Tok);
+ PP.Lex(Tok);
+ }
+}
+
+unsigned Parser::HandlePragmaMSSection(llvm::StringRef PragmaName,
+ SourceLocation PragmaLocation) {
+ if (Tok.isNot(tok::l_paren))
+ return diag::warn_pragma_expected_lparen;
+ PP.Lex(Tok); // (
+ // Parsing code for pragma section
+ if (Tok.isNot(tok::string_literal))
+ return diag::warn_pragma_expected_section_name;
+ StringLiteral *SegmentName =
+ cast<StringLiteral>(ParseStringLiteralExpression().get());
+ int SectionFlags = 0;
+ while (Tok.is(tok::comma)) {
+ PP.Lex(Tok); // ,
+ if (!Tok.isAnyIdentifier())
+ return diag::warn_pragma_expected_action_or_r_paren;
+ Sema::PragmaSectionFlag Flag =
+ llvm::StringSwitch<Sema::PragmaSectionFlag>(
+ Tok.getIdentifierInfo()->getName())
+ .Case("read", Sema::PSF_Read)
+ .Case("write", Sema::PSF_Write)
+ .Case("execute", Sema::PSF_Execute)
+ .Case("shared", Sema::PSF_Invalid)
+ .Case("nopage", Sema::PSF_Invalid)
+ .Case("nocache", Sema::PSF_Invalid)
+ .Case("discard", Sema::PSF_Invalid)
+ .Case("remove", Sema::PSF_Invalid)
+ .Default(Sema::PSF_None);
+ if (Flag == Sema::PSF_None || Flag == Sema::PSF_Invalid) {
+ PP.Diag(PragmaLocation, Flag == Sema::PSF_None ?
+ diag::warn_pragma_invalid_specific_action :
+ diag::warn_pragma_unsupported_action)
+ << PragmaName << Tok.getIdentifierInfo()->getName();
+ while (Tok.isNot(tok::eof))
+ PP.Lex(Tok);
+ PP.Lex(Tok);
+ return 0;
+ }
+ SectionFlags |= Flag;
+ PP.Lex(Tok); // Identifier
+ }
+ if (Tok.isNot(tok::r_paren))
+ return diag::warn_pragma_expected_rparen;
+ PP.Lex(Tok); // )
+ if (Tok.isNot(tok::eof))
+ return diag::warn_pragma_extra_tokens_at_eol;
+ PP.Lex(Tok); // eof
+ Actions.ActOnPragmaMSSection(PragmaLocation, SectionFlags, SegmentName);
+ return 0;
+}
+
+unsigned Parser::HandlePragmaMSSegment(llvm::StringRef PragmaName,
+ SourceLocation PragmaLocation) {
+ if (Tok.isNot(tok::l_paren))
+ return diag::warn_pragma_expected_lparen;
+ PP.Lex(Tok); // (
+ Sema::PragmaMsStackAction Action = Sema::PSK_Reset;
+ llvm::StringRef SlotLabel;
+ if (Tok.isAnyIdentifier()) {
+ llvm::StringRef PushPop = Tok.getIdentifierInfo()->getName();
+ if (PushPop == "push")
+ Action = Sema::PSK_Push;
+ else if (PushPop == "pop")
+ Action = Sema::PSK_Pop;
+ else
+ return diag::warn_pragma_expected_section_push_pop_or_name;
+ if (Action != Sema::PSK_Reset) {
+ PP.Lex(Tok); // push | pop
+ if (Tok.is(tok::comma)) {
+ PP.Lex(Tok); // ,
+ // If we've got a comma, we either need a label or a string.
+ if (Tok.isAnyIdentifier()) {
+ SlotLabel = Tok.getIdentifierInfo()->getName();
+ PP.Lex(Tok); // identifier
+ if (Tok.is(tok::comma))
+ PP.Lex(Tok);
+ else if (Tok.isNot(tok::r_paren))
+ return diag::warn_pragma_expected_punc;
+ }
+ } else if (Tok.isNot(tok::r_paren))
+ return diag::warn_pragma_expected_punc;
+ }
+ }
+ // Grab the string literal for our section name.
+ StringLiteral *SegmentName = nullptr;
+ if (Tok.isNot(tok::r_paren)) {
+ if (Tok.isNot(tok::string_literal))
+ return Action != Sema::PSK_Reset ? !SlotLabel.empty() ?
+ diag::warn_pragma_expected_section_name :
+ diag::warn_pragma_expected_section_label_or_name :
+ diag::warn_pragma_expected_section_push_pop_or_name;
+ SegmentName = cast<StringLiteral>(ParseStringLiteralExpression().get());
+ // Setting section "" has no effect
+ if (SegmentName->getLength())
+ Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set);
+ }
+ if (Tok.isNot(tok::r_paren))
+ return diag::warn_pragma_expected_rparen;
+ PP.Lex(Tok); // )
+ if (Tok.isNot(tok::eof))
+ return diag::warn_pragma_extra_tokens_at_eol;
+ PP.Lex(Tok); // eof
+ Actions.ActOnPragmaMSSeg(PragmaLocation, Action, SlotLabel,
+ SegmentName, PragmaName);
+ return 0;
+}
+
+unsigned Parser::HandlePragmaMSInitSeg(llvm::StringRef PragmaName,
+ SourceLocation PragmaLocation) {
+ return PP.getDiagnostics().getCustomDiagID(
+ DiagnosticsEngine::Error, "'#pragma %0' not implemented.");
+}
+
// #pragma GCC visibility comes in two variants:
// 'push' '(' [visibility] ')'
// 'pop'
@@ -1204,6 +1374,33 @@ void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP,
PP.EnterToken(AnnotTok);
}
+/// \brief Handle all MS pragmas. Simply forwards the tokens after inserting
+/// an annotation token.
+void PragmaMSPragma::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &Tok) {
+ Token EoF, AnnotTok;
+ EoF.startToken();
+ EoF.setKind(tok::eof);
+ AnnotTok.startToken();
+ AnnotTok.setKind(tok::annot_pragma_ms_pragma);
+ AnnotTok.setLocation(Tok.getLocation());
+ SmallVector<Token, 8> TokenVector;
+ // Suck up all of the tokens before the eod.
+ for (; Tok.isNot(tok::eod); PP.Lex(Tok))
+ TokenVector.push_back(Tok);
+ // Add a sentinal EoF token to the end of the list.
+ TokenVector.push_back(EoF);
+ // We must allocate this array with new because EnterTokenStream is going to
+ // delete it later.
+ Token *TokenArray = new Token[TokenVector.size()];
+ std::copy(TokenVector.begin(), TokenVector.end(), TokenArray);
+ auto Value = new (PP.getPreprocessorAllocator())
+ std::pair<Token*, size_t>(std::make_pair(TokenArray, TokenVector.size()));
+ AnnotTok.setAnnotationValue(Value);
+ PP.EnterToken(AnnotTok);
+}
+
/// \brief Handle the Microsoft \#pragma detect_mismatch extension.
///
/// The syntax is:
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 7254eb3c11..88c6126311 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -26,12 +26,15 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetAsmParser.h"
+#include "llvm/MC/MCTargetOptions.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
@@ -350,6 +353,10 @@ Retry:
HandlePragmaMSPointersToMembers();
return StmtEmpty();
+ case tok::annot_pragma_ms_pragma:
+ ProhibitAttributes(Attrs);
+ HandlePragmaMSPragma();
+ return StmtEmpty();
}
// If we reached this code, the statement must end in a semicolon.
@@ -639,8 +646,9 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
ColonProtection.restore();
if (TryConsumeToken(tok::colon, ColonLoc)) {
- } else if (TryConsumeToken(tok::semi, ColonLoc)) {
- // Treat "case blah;" as a typo for "case blah:".
+ } else if (TryConsumeToken(tok::semi, ColonLoc) ||
+ TryConsumeToken(tok::coloncolon, ColonLoc)) {
+ // Treat "case blah;" or "case blah::" as a typo for "case blah:".
Diag(ColonLoc, diag::err_expected_after)
<< "'case'" << tok::colon
<< FixItHint::CreateReplacement(ColonLoc, ":");
@@ -828,6 +836,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
break;
+ case tok::annot_pragma_ms_pragma:
+ HandlePragmaMSPragma();
+ break;
default:
checkForPragmas = false;
break;
@@ -2166,7 +2177,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT));
// Get the instruction descriptor.
- const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo();
+ std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo());
std::unique_ptr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo());
std::unique_ptr<llvm::MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(TT, "", ""));
@@ -2182,11 +2193,14 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
std::unique_ptr<llvm::MCStreamer> Str(createNullStreamer(Ctx));
std::unique_ptr<llvm::MCAsmParser> Parser(
createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI));
+
+ // FIXME: init MCOptions from sanitizer flags here.
+ llvm::MCTargetOptions MCOptions;
std::unique_ptr<llvm::MCTargetAsmParser> TargetParser(
- TheTarget->createMCAsmParser(*STI, *Parser, *MII));
+ TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions));
- llvm::MCInstPrinter *IP =
- TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI);
+ std::unique_ptr<llvm::MCInstPrinter> IP(
+ TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI));
// Change to the Intel dialect.
Parser->setAssemblerDialect(1);
@@ -2208,7 +2222,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
SmallVector<std::string, 4> Clobbers;
if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR,
NumOutputs, NumInputs, OpExprs, Constraints,
- Clobbers, MII, IP, Callback))
+ Clobbers, MII.get(), IP.get(), Callback))
return StmtError();
// Filter out "fpsw". Clang doesn't accept it, and it always lists flags and
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 777fd01aa2..e81c41da67 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -1161,6 +1161,7 @@ bool
Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
// Template argument lists are constant-evaluation contexts.
EnterExpressionEvaluationContext EvalContext(Actions,Sema::ConstantEvaluated);
+ ColonProtectionRAIIObject ColonProtection(*this, false);
do {
ParsedTemplateArgument Arg = ParseTemplateArgument();
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 330e541659..71d19613a7 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -936,6 +936,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___real:
case tok::kw___FUNCTION__:
case tok::kw___FUNCDNAME__:
+ case tok::kw___FUNCSIG__:
case tok::kw_L__FUNCTION__:
case tok::kw___PRETTY_FUNCTION__:
case tok::kw___uuidof:
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 9936a5a3ab..9d3f251a55 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -631,6 +631,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::annot_pragma_ms_vtordisp:
HandlePragmaMSVtorDisp();
return DeclGroupPtrTy();
+ case tok::annot_pragma_ms_pragma:
+ HandlePragmaMSPragma();
+ return DeclGroupPtrTy();
case tok::semi:
// Either a C++11 empty-declaration or attribute-declaration.
SingleDecl = Actions.ActOnEmptyDeclaration(getCurScope(),
diff --git a/lib/Rewrite/Core/RewriteRope.cpp b/lib/Rewrite/Core/RewriteRope.cpp
index fe7aa2d647..135f42a207 100644
--- a/lib/Rewrite/Core/RewriteRope.cpp
+++ b/lib/Rewrite/Core/RewriteRope.cpp
@@ -788,9 +788,8 @@ RopePiece RewriteRope::MakeRopeString(const char *Start, const char *End) {
// Otherwise, this was a small request but we just don't have space for it
// Make a new chunk and share it with later allocations.
- // If we had an old allocation, drop our reference to it.
- if (AllocBuffer && --AllocBuffer->RefCount == 0)
- delete [] (char*)AllocBuffer;
+ if (AllocBuffer)
+ AllocBuffer->dropRef();
unsigned AllocSize = offsetof(RopeRefCountString, Data) + AllocChunkSize;
AllocBuffer = reinterpret_cast<RopeRefCountString *>(new char[AllocSize]);
diff --git a/lib/Rewrite/Frontend/RewriteModernObjC.cpp b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
index 9066a5fdcb..65a5dc5162 100644
--- a/lib/Rewrite/Frontend/RewriteModernObjC.cpp
+++ b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
@@ -6108,7 +6108,7 @@ void RewriteModernObjC::Initialize(ASTContext &context) {
Preamble += " int *isa;\n";
Preamble += " int flags;\n";
Preamble += " char *str;\n";
- Preamble += "#if __LLP64__\n";
+ Preamble += "#if _WIN64\n";
Preamble += " long long length;\n";
Preamble += "#else\n";
Preamble += " long length;\n";
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 3e40485a8b..fc591bd77c 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -117,6 +117,38 @@ static void CheckUnreachable(Sema &S, AnalysisDeclContext &AC) {
reachable_code::FindUnreachableCode(AC, S.getPreprocessor(), UC);
}
+/// \brief Warn on logical operator errors in CFGBuilder
+class LogicalErrorHandler : public CFGCallback {
+ Sema &S;
+
+public:
+ LogicalErrorHandler(Sema &S) : CFGCallback(), S(S) {}
+
+ static bool HasMacroID(const Expr *E) {
+ if (E->getExprLoc().isMacroID())
+ return true;
+
+ // Recurse to children.
+ for (ConstStmtRange SubStmts = E->children(); SubStmts; ++SubStmts)
+ if (*SubStmts)
+ if (const Expr *SubExpr = dyn_cast<Expr>(*SubStmts))
+ if (HasMacroID(SubExpr))
+ return true;
+
+ return false;
+ }
+
+ void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) {
+ if (HasMacroID(B))
+ return;
+
+ SourceRange DiagRange = B->getSourceRange();
+ S.Diag(B->getExprLoc(), diag::warn_tautological_overlap_comparison)
+ << DiagRange << isAlwaysTrue;
+ }
+};
+
+
//===----------------------------------------------------------------------===//
// Check for infinite self-recursion in functions
//===----------------------------------------------------------------------===//
@@ -413,8 +445,7 @@ struct CheckFallThroughDiagnostics {
diag::err_noreturn_block_has_return_expr;
D.diag_AlwaysFallThrough_ReturnsNonVoid =
diag::err_falloff_nonvoid_block;
- D.diag_NeverFallThroughOrReturn =
- diag::warn_suggest_noreturn_block;
+ D.diag_NeverFallThroughOrReturn = 0;
D.funMode = Block;
return D;
}
@@ -449,10 +480,7 @@ struct CheckFallThroughDiagnostics {
}
// For blocks / lambdas.
- return ReturnsVoid && !HasNoReturn
- && ((funMode == Lambda) ||
- D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc)
- == DiagnosticsEngine::Ignored);
+ return ReturnsVoid && !HasNoReturn;
}
};
@@ -1810,6 +1838,13 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
.setAlwaysAdd(Stmt::AttributedStmtClass);
}
+ // Install the logical handler for -Wtautological-overlap-compare
+ std::unique_ptr<LogicalErrorHandler> LEH;
+ if (Diags.getDiagnosticLevel(diag::warn_tautological_overlap_comparison,
+ D->getLocStart())) {
+ LEH.reset(new LogicalErrorHandler(S));
+ AC.getCFGBuildOptions().Observer = LEH.get();
+ }
// Emit delayed diagnostics.
if (!fscope->PossiblyUnreachableDiags.empty()) {
@@ -1956,6 +1991,13 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
}
}
+ // If none of the previous checks caused a CFG build, trigger one here
+ // for -Wtautological-overlap-compare
+ if (Diags.getDiagnosticLevel(diag::warn_tautological_overlap_comparison,
+ D->getLocStart())) {
+ AC.getCFG();
+ }
+
// Collect statistics about the CFG if it was built.
if (S.CollectStats && AC.isCFGBuilt()) {
++NumFunctionsAnalyzed;
diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp
index 533b7ef3e8..ddecfdb376 100644
--- a/lib/Sema/DelayedDiagnostic.cpp
+++ b/lib/Sema/DelayedDiagnostic.cpp
@@ -52,12 +52,13 @@ DelayedDiagnostic::makeAvailability(Sema::AvailabilityDiagnostic AD,
}
void DelayedDiagnostic::Destroy() {
- switch (Kind) {
+ switch (static_cast<DDKind>(Kind)) {
case Access:
getAccessData().~AccessedEntity();
break;
- case Deprecation:
+ case Deprecation:
+ case Unavailable:
delete [] DeprecationData.Message;
break;
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 3612bb962c..8faf29556e 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -79,7 +79,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
MSPointerToMemberRepresentationMethod(
LangOpts.getMSPointerToMemberRepresentationMethod()),
VtorDispModeStack(1, MSVtorDispAttr::Mode(LangOpts.VtorDispMode)),
- VisContext(0),
+ DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
+ CodeSegStack(nullptr), VisContext(0),
IsBuildingRecoveryCallExpr(false),
ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0),
IdResolver(pp), StdInitializerList(0), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
@@ -1113,14 +1114,30 @@ BlockScopeInfo *Sema::getCurBlock() {
if (FunctionScopes.empty())
return 0;
- return dyn_cast<BlockScopeInfo>(FunctionScopes.back());
+ auto CurBSI = dyn_cast<BlockScopeInfo>(FunctionScopes.back());
+ if (CurBSI && CurBSI->TheDecl &&
+ !CurBSI->TheDecl->Encloses(CurContext)) {
+ // We have switched contexts due to template instantiation.
+ assert(!ActiveTemplateInstantiations.empty());
+ return nullptr;
+ }
+
+ return CurBSI;
}
LambdaScopeInfo *Sema::getCurLambda() {
if (FunctionScopes.empty())
return 0;
- return dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
+ auto CurLSI = dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
+ if (CurLSI && CurLSI->Lambda &&
+ !CurLSI->Lambda->Encloses(CurContext)) {
+ // We have switched contexts due to template instantiation.
+ assert(!ActiveTemplateInstantiations.empty());
+ return nullptr;
+ }
+
+ return CurLSI;
}
// We have a generic lambda if we parsed auto parameters, or we have
// an associated template parameter list.
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index 2e344ff930..f5905842fd 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -325,6 +325,112 @@ void Sema::ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind,
}
}
+template<typename ValueType>
+void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
+ PragmaMsStackAction Action,
+ llvm::StringRef StackSlotLabel,
+ ValueType Value) {
+ if (Action == PSK_Reset) {
+ CurrentValue = nullptr;
+ return;
+ }
+ if (Action & PSK_Push)
+ Stack.push_back(Slot(StackSlotLabel, CurrentValue, CurrentPragmaLocation));
+ else if (Action & PSK_Pop) {
+ if (!StackSlotLabel.empty()) {
+ // If we've got a label, try to find it and jump there.
+ auto I = std::find_if(Stack.rbegin(), Stack.rend(),
+ [&](const Slot &x) { return x.StackSlotLabel == StackSlotLabel; });
+ // If we found the label so pop from there.
+ if (I != Stack.rend()) {
+ CurrentValue = I->Value;
+ CurrentPragmaLocation = I->PragmaLocation;
+ Stack.erase(std::prev(I.base()), Stack.end());
+ }
+ } else if (!Stack.empty()) {
+ // We don't have a label, just pop the last entry.
+ CurrentValue = Stack.back().Value;
+ CurrentPragmaLocation = Stack.back().PragmaLocation;
+ Stack.pop_back();
+ }
+ }
+ if (Action & PSK_Set) {
+ CurrentValue = Value;
+ CurrentPragmaLocation = PragmaLocation;
+ }
+}
+
+bool Sema::UnifySection(const StringRef &SectionName,
+ int SectionFlags,
+ DeclaratorDecl *Decl) {
+ auto Section = SectionInfos.find(SectionName);
+ if (Section == SectionInfos.end()) {
+ SectionInfos[SectionName] =
+ SectionInfo(Decl, SourceLocation(), SectionFlags);
+ return false;
+ }
+ // A pre-declared section takes precedence w/o diagnostic.
+ if (Section->second.SectionFlags == SectionFlags ||
+ !(Section->second.SectionFlags & PSF_Implicit))
+ return false;
+ auto OtherDecl = Section->second.Decl;
+ Diag(Decl->getLocation(), diag::err_section_conflict)
+ << Decl << OtherDecl;
+ Diag(OtherDecl->getLocation(), diag::note_declared_at)
+ << OtherDecl->getName();
+ if (auto A = Decl->getAttr<SectionAttr>())
+ if (A->isImplicit())
+ Diag(A->getLocation(), diag::note_pragma_entered_here);
+ if (auto A = OtherDecl->getAttr<SectionAttr>())
+ if (A->isImplicit())
+ Diag(A->getLocation(), diag::note_pragma_entered_here);
+ return false;
+}
+
+bool Sema::UnifySection(const StringRef &SectionName,
+ int SectionFlags,
+ SourceLocation PragmaSectionLocation) {
+ auto Section = SectionInfos.find(SectionName);
+ if (Section != SectionInfos.end()) {
+ if (Section->second.SectionFlags == SectionFlags)
+ return false;
+ if (!(Section->second.SectionFlags & PSF_Implicit)) {
+ Diag(PragmaSectionLocation, diag::err_section_conflict)
+ << "this" << "a prior #pragma section";
+ Diag(Section->second.PragmaSectionLocation,
+ diag::note_pragma_entered_here);
+ return true;
+ }
+ }
+ SectionInfos[SectionName] =
+ SectionInfo(nullptr, PragmaSectionLocation, SectionFlags);
+ return false;
+}
+
+/// \brief Called on well formed \#pragma bss_seg().
+void Sema::ActOnPragmaMSSeg(SourceLocation PragmaLocation,
+ PragmaMsStackAction Action,
+ llvm::StringRef StackSlotLabel,
+ StringLiteral *SegmentName,
+ llvm::StringRef PragmaName) {
+ PragmaStack<StringLiteral *> *Stack =
+ llvm::StringSwitch<PragmaStack<StringLiteral *> *>(PragmaName)
+ .Case("data_seg", &DataSegStack)
+ .Case("bss_seg", &BSSSegStack)
+ .Case("const_seg", &ConstSegStack)
+ .Case("code_seg", &CodeSegStack);
+ if (Action & PSK_Pop && Stack->Stack.empty())
+ Diag(PragmaLocation, diag::warn_pragma_pop_failed) << PragmaName
+ << "stack empty";
+ Stack->Act(PragmaLocation, Action, StackSlotLabel, SegmentName);
+}
+
+/// \brief Called on well formed \#pragma bss_seg().
+void Sema::ActOnPragmaMSSection(SourceLocation PragmaLocation,
+ int SectionFlags, StringLiteral *SegmentName) {
+ UnifySection(SegmentName->getString(), SectionFlags, PragmaLocation);
+}
+
void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
SourceLocation PragmaLoc) {
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index ce47cfffa8..707d1b2e81 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -377,6 +377,28 @@ class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback {
/// by ActOnCXXNestedNameSpecifier.
///
/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
+/// that it contains an extra parameter \p ScopeLookupResult.
+///
+/// \param S Scope in which the nested-name-specifier occurs.
+/// \param Identifier Identifier in the sequence "identifier" "::".
+/// \param IdentifierLoc Location of the \p Identifier.
+/// \param CCLoc Location of "::" following Identifier.
+/// \param ObjectType Type of postfix expression if the nested-name-specifier
+/// occurs in construct like: <tt>ptr->nns::f</tt>.
+/// \param EnteringContext If true, enter the context specified by the
+/// nested-name-specifier.
+/// \param SS Optional nested name specifier preceding the identifier.
+/// \param ScopeLookupResult Provides the result of name lookup within the
+/// scope of the nested-name-specifier that was computed at template
+/// definition time.
+/// \param ErrorRecoveryLookup Specifies if the method is called to improve
+/// error recovery and what kind of recovery is performed.
+/// \param IsCorrectedToColon If not null, suggestion of replace '::' -> ':'
+/// are allowed. The bool value pointed by this parameter is set to
+/// 'true' if the identifier is treated as if it was followed by ':',
+/// not '::'.
+///
+/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
/// that it contains an extra parameter \p ScopeLookupResult, which provides
/// the result of name lookup within the scope of the nested-name-specifier
/// that was computed at template definition time.
@@ -395,13 +417,16 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
bool EnteringContext,
CXXScopeSpec &SS,
NamedDecl *ScopeLookupResult,
- bool ErrorRecoveryLookup) {
+ bool ErrorRecoveryLookup,
+ bool *IsCorrectedToColon) {
LookupResult Found(*this, &Identifier, IdentifierLoc,
LookupNestedNameSpecifierName);
// Determine where to perform name lookup
DeclContext *LookupCtx = 0;
bool isDependent = false;
+ if (IsCorrectedToColon)
+ *IsCorrectedToColon = false;
if (!ObjectType.isNull()) {
// This nested-name-specifier occurs in a member access expression, e.g.,
// x->B::f, and we are looking into the type of the object.
@@ -416,7 +441,6 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
Found.setContextRange(SS.getRange());
}
-
bool ObjectTypeSearchedInScope = false;
if (LookupCtx) {
// Perform "qualified" name lookup into the declaration context we
@@ -473,17 +497,48 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
// Don't speculate if we're just trying to improve error recovery.
if (ErrorRecoveryLookup)
return true;
-
+
// We were not able to compute the declaration context for a dependent
// base object type or prior nested-name-specifier, so this
// nested-name-specifier refers to an unknown specialization. Just build
// a dependent nested-name-specifier.
SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc);
return false;
- }
-
+ }
+
// FIXME: Deal with ambiguities cleanly.
+ if (Found.empty() && !ErrorRecoveryLookup) {
+ // If identifier is not found as class-name-or-namespace-name, but is found
+ // as other entity, don't look for typos.
+ LookupResult R(*this, Found.getLookupNameInfo(), LookupOrdinaryName);
+ if (LookupCtx)
+ LookupQualifiedName(R, LookupCtx);
+ else if (S && !isDependent)
+ LookupName(R, S);
+ if (!R.empty()) {
+ // The identifier is found in ordinary lookup. If correction to colon is
+ // allowed, suggest replacement to ':'.
+ if (IsCorrectedToColon) {
+ *IsCorrectedToColon = true;
+ Diag(CCLoc, diag::err_nested_name_spec_is_not_class)
+ << &Identifier << getLangOpts().CPlusPlus
+ << FixItHint::CreateReplacement(CCLoc, ":");
+ if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
+ Diag(ND->getLocation(), diag::note_declared_at);
+ return true;
+ }
+ // Replacement '::' -> ':' is not allowed, just issue respective error.
+ Diag(R.getNameLoc(), diag::err_expected_class_or_namespace)
+ << &Identifier << getLangOpts().CPlusPlus;
+ if (NamedDecl *ND = R.getAsSingle<NamedDecl>())
+ Diag(ND->getLocation(),
+ diag::note_expected_class_or_namespace_declared_here)
+ << &Identifier;
+ return true;
+ }
+ }
+
if (Found.empty() && !ErrorRecoveryLookup && !getLangOpts().MSVCCompat) {
// We haven't found anything, and we're not recovering from a
// different kind of error, so look for typos.
@@ -492,7 +547,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
Found.clear();
if (TypoCorrection Corrected =
CorrectTypo(Found.getLookupNameInfo(), Found.getLookupKind(), S,
- &SS, Validator, LookupCtx, EnteringContext)) {
+ &SS, Validator, CTK_ErrorRecovery, LookupCtx,
+ EnteringContext)) {
if (LookupCtx) {
bool DroppedSpecifier =
Corrected.WillReplaceSpecifier() &&
@@ -543,8 +599,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
!Context.hasSameType(
Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)),
Context.getTypeDeclType(cast<TypeDecl>(SD))))) {
- if (ErrorRecoveryLookup)
- return true;
+ if (ErrorRecoveryLookup)
+ return true;
Diag(IdentifierLoc,
diag::err_nested_name_member_ref_lookup_ambiguous)
@@ -558,7 +614,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
}
}
- // If we're just performing this lookup for error-recovery purposes,
+ // If we're just performing this lookup for error-recovery purposes,
// don't extend the nested-name-specifier. Just return now.
if (ErrorRecoveryLookup)
return false;
@@ -681,14 +737,17 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
SourceLocation CCLoc,
ParsedType ObjectType,
bool EnteringContext,
- CXXScopeSpec &SS) {
+ CXXScopeSpec &SS,
+ bool ErrorRecoveryLookup,
+ bool *IsCorrectedToColon) {
if (SS.isInvalid())
return true;
-
+
return BuildCXXNestedNameSpecifier(S, Identifier, IdentifierLoc, CCLoc,
GetTypeFromParser(ObjectType),
EnteringContext, SS,
- /*ScopeLookupResult=*/0, false);
+ /*ScopeLookupResult=*/0, false,
+ IsCorrectedToColon);
}
bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index 5d49225ac4..41570962a2 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -2097,10 +2097,16 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
DestType,
/*Complain*/ true,
Found);
-
- assert(!Fn && "cast failed but able to resolve overload expression!!");
- (void)Fn;
-
+ if (Fn) {
+ // If DestType is a function type (not to be confused with the function
+ // pointer type), it will be possible to resolve the function address,
+ // but the type cast should be considered as failure.
+ OverloadExpr *OE = OverloadExpr::find(SrcExpr.get()).Expression;
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cstyle_cast_overload)
+ << OE->getName() << DestType << OpRange
+ << OE->getQualifierLoc().getSourceRange();
+ Self.NoteAllOverloadCandidates(SrcExpr.get());
+ }
} else {
diagnoseBadCast(Self, msg, (FunctionalStyle ? CT_Functional : CT_CStyle),
OpRange, SrcExpr.get(), DestType, ListInitialization);
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 27cc8a37a5..6c84b974c4 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -176,7 +176,7 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return ExprError();
break;
case Builtin::BI__builtin_object_size:
- if (SemaBuiltinObjectSize(TheCall))
+ if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3))
return ExprError();
break;
case Builtin::BI__builtin_longjmp:
@@ -467,24 +467,8 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
#include "clang/Basic/arm_neon.inc"
#undef GET_NEON_IMMEDIATE_CHECK
}
- ;
- // We can't check the value of a dependent argument.
- if (TheCall->getArg(i)->isTypeDependent() ||
- TheCall->getArg(i)->isValueDependent())
- return false;
-
- // Check that the immediate argument is actually a constant.
- if (SemaBuiltinConstantArg(TheCall, i, Result))
- return true;
-
- // Range check against the upper/lower values for this isntruction.
- unsigned Val = Result.getZExtValue();
- if (Val < l || Val > (u + l))
- return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << l << u + l << TheCall->getArg(i)->getSourceRange();
-
- return false;
+ return SemaBuiltinConstantArgRange(TheCall, i, l, u + l);
}
bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
@@ -628,25 +612,10 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case ARM::BI__builtin_arm_vcvtr_d: i = 1; u = 1; break;
case ARM::BI__builtin_arm_dmb:
case ARM::BI__builtin_arm_dsb: l = 0; u = 15; break;
- };
-
- // We can't check the value of a dependent argument.
- if (TheCall->getArg(i)->isTypeDependent() ||
- TheCall->getArg(i)->isValueDependent())
- return false;
-
- // Check that the immediate argument is actually a constant.
- if (SemaBuiltinConstantArg(TheCall, i, Result))
- return true;
-
- // Range check against the upper/lower values for this isntruction.
- unsigned Val = Result.getZExtValue();
- if (Val < l || Val > (u + l))
- return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << l << u+l << TheCall->getArg(i)->getSourceRange();
+ }
// FIXME: VFP Intrinsics should error if VFP not present.
- return false;
+ return SemaBuiltinConstantArgRange(TheCall, i, l, u + l);
}
bool Sema::CheckARM64BuiltinFunctionCall(unsigned BuiltinID,
@@ -675,31 +644,16 @@ bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case Mips::BI__builtin_mips_precr_sra_ph_w: i = 2; l = 0; u = 31; break;
case Mips::BI__builtin_mips_precr_sra_r_ph_w: i = 2; l = 0; u = 31; break;
case Mips::BI__builtin_mips_prepend: i = 2; l = 0; u = 31; break;
- };
-
- // We can't check the value of a dependent argument.
- if (TheCall->getArg(i)->isTypeDependent() ||
- TheCall->getArg(i)->isValueDependent())
- return false;
-
- // Check that the immediate argument is actually a constant.
- llvm::APSInt Result;
- if (SemaBuiltinConstantArg(TheCall, i, Result))
- return true;
-
- // Range check against the upper/lower values for this instruction.
- unsigned Val = Result.getZExtValue();
- if (Val < l || Val > u)
- return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << l << u << TheCall->getArg(i)->getSourceRange();
+ }
- return false;
+ return SemaBuiltinConstantArgRange(TheCall, i, l, u);
}
bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
switch (BuiltinID) {
case X86::BI_mm_prefetch:
- return SemaBuiltinMMPrefetch(TheCall);
+ // This is declared to take (const char*, int)
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3);
}
return false;
}
@@ -1969,51 +1923,10 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) {
// Argument 0 is checked for us and the remaining arguments must be
// constant integers.
- for (unsigned i = 1; i != NumArgs; ++i) {
- Expr *Arg = TheCall->getArg(i);
-
- // We can't check the value of a dependent argument.
- if (Arg->isTypeDependent() || Arg->isValueDependent())
- continue;
-
- llvm::APSInt Result;
- if (SemaBuiltinConstantArg(TheCall, i, Result))
+ for (unsigned i = 1; i != NumArgs; ++i)
+ if (SemaBuiltinConstantArgRange(TheCall, i, 0, i == 1 ? 1 : 3))
return true;
- // FIXME: gcc issues a warning and rewrites these to 0. These
- // seems especially odd for the third argument since the default
- // is 3.
- if (i == 1) {
- if (Result.getLimitedValue() > 1)
- return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << "0" << "1" << Arg->getSourceRange();
- } else {
- if (Result.getLimitedValue() > 3)
- return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << "0" << "3" << Arg->getSourceRange();
- }
- }
-
- return false;
-}
-
-/// SemaBuiltinMMPrefetch - Handle _mm_prefetch.
-// This is declared to take (const char*, int)
-bool Sema::SemaBuiltinMMPrefetch(CallExpr *TheCall) {
- Expr *Arg = TheCall->getArg(1);
-
- // We can't check the value of a dependent argument.
- if (Arg->isTypeDependent() || Arg->isValueDependent())
- return false;
-
- llvm::APSInt Result;
- if (SemaBuiltinConstantArg(TheCall, 1, Result))
- return true;
-
- if (Result.getLimitedValue() > 3)
- return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << "0" << "3" << Arg->getSourceRange();
-
return false;
}
@@ -2034,27 +1947,24 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum,
return false;
}
-/// SemaBuiltinObjectSize - Handle __builtin_object_size(void *ptr,
-/// int type). This simply type checks that type is one of the defined
-/// constants (0-3).
-// For compatibility check 0-3, llvm only handles 0 and 2.
-bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) {
+/// SemaBuiltinConstantArgRange - Handle a check if argument ArgNum of CallExpr
+/// TheCall is a constant expression in the range [Low, High].
+bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum,
+ int Low, int High) {
llvm::APSInt Result;
// We can't check the value of a dependent argument.
- if (TheCall->getArg(1)->isTypeDependent() ||
- TheCall->getArg(1)->isValueDependent())
+ Expr *Arg = TheCall->getArg(ArgNum);
+ if (Arg->isTypeDependent() || Arg->isValueDependent())
return false;
// Check constant-ness first.
- if (SemaBuiltinConstantArg(TheCall, 1, Result))
+ if (SemaBuiltinConstantArg(TheCall, ArgNum, Result))
return true;
- Expr *Arg = TheCall->getArg(1);
- if (Result.getSExtValue() < 0 || Result.getSExtValue() > 3) {
+ if (Result.getSExtValue() < Low || Result.getSExtValue() > High)
return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range)
- << "0" << "3" << SourceRange(Arg->getLocStart(), Arg->getLocEnd());
- }
+ << Low << High << Arg->getSourceRange();
return false;
}
@@ -3862,54 +3772,107 @@ static unsigned getAbsoluteValueFunctionKind(const FunctionDecl *FDecl) {
// If the replacement is valid, emit a note with replacement function.
// Additionally, suggest including the proper header if not already included.
static void emitReplacement(Sema &S, SourceLocation Loc, SourceRange Range,
- unsigned AbsKind) {
- std::string AbsName = S.Context.BuiltinInfo.GetName(AbsKind);
-
- // Look up absolute value function in TU scope.
- DeclarationName DN(&S.Context.Idents.get(AbsName));
- LookupResult R(S, DN, Loc, Sema::LookupAnyName);
- R.suppressDiagnostics();
- S.LookupName(R, S.TUScope);
-
- // Skip notes if multiple results found in lookup.
- if (!R.empty() && !R.isSingleResult())
- return;
-
- FunctionDecl *FD = 0;
- bool FoundFunction = R.isSingleResult();
- // When one result is found, see if it is the correct function.
- if (R.isSingleResult()) {
- FD = dyn_cast<FunctionDecl>(R.getFoundDecl());
- if (!FD || FD->getBuiltinID() != AbsKind)
- return;
- }
-
- // Look for local name conflict, prepend "::" as necessary.
- R.clear();
- S.LookupName(R, S.getCurScope());
+ unsigned AbsKind, QualType ArgType) {
+ bool EmitHeaderHint = true;
+ const char *HeaderName = 0;
+ const char *FunctionName = 0;
+ if (S.getLangOpts().CPlusPlus && !ArgType->isAnyComplexType()) {
+ FunctionName = "std::abs";
+ if (ArgType->isIntegralOrEnumerationType()) {
+ HeaderName = "cstdlib";
+ } else if (ArgType->isRealFloatingType()) {
+ HeaderName = "cmath";
+ } else {
+ llvm_unreachable("Invalid Type");
+ }
- if (!FoundFunction) {
- if (!R.empty()) {
- AbsName = "::" + AbsName;
+ // Lookup all std::abs
+ if (NamespaceDecl *Std = S.getStdNamespace()) {
+ LookupResult R(S, &S.PP.getIdentifierTable().get("abs"), Loc,
+ Sema::LookupAnyName);
+ R.suppressDiagnostics();
+ S.LookupQualifiedName(R, Std);
+
+ for (const auto *I : R) {
+ const FunctionDecl *FDecl = 0;
+ if (const UsingShadowDecl *UsingD = dyn_cast<UsingShadowDecl>(I)) {
+ FDecl = dyn_cast<FunctionDecl>(UsingD->getTargetDecl());
+ } else {
+ FDecl = dyn_cast<FunctionDecl>(I);
+ }
+ if (!FDecl)
+ continue;
+
+ // Found std::abs(), check that they are the right ones.
+ if (FDecl->getNumParams() != 1)
+ continue;
+
+ // Check that the parameter type can handle the argument.
+ QualType ParamType = FDecl->getParamDecl(0)->getType();
+ if (getAbsoluteValueKind(ArgType) == getAbsoluteValueKind(ParamType) &&
+ S.Context.getTypeSize(ArgType) <=
+ S.Context.getTypeSize(ParamType)) {
+ // Found a function, don't need the header hint.
+ EmitHeaderHint = false;
+ break;
+ }
+ }
}
- } else { // FoundFunction
- if (R.isSingleResult()) {
- if (R.getFoundDecl() != FD) {
- AbsName = "::" + AbsName;
+ } else {
+ FunctionName = S.Context.BuiltinInfo.GetName(AbsKind);
+ HeaderName = S.Context.BuiltinInfo.getHeaderName(AbsKind);
+
+ if (HeaderName) {
+ DeclarationName DN(&S.Context.Idents.get(FunctionName));
+ LookupResult R(S, DN, Loc, Sema::LookupAnyName);
+ R.suppressDiagnostics();
+ S.LookupName(R, S.getCurScope());
+
+ if (R.isSingleResult()) {
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(R.getFoundDecl());
+ if (FD && FD->getBuiltinID() == AbsKind) {
+ EmitHeaderHint = false;
+ } else {
+ return;
+ }
+ } else if (!R.empty()) {
+ return;
}
- } else if (!R.empty()) {
- AbsName = "::" + AbsName;
}
}
S.Diag(Loc, diag::note_replace_abs_function)
- << AbsName << FixItHint::CreateReplacement(Range, AbsName);
+ << FunctionName << FixItHint::CreateReplacement(Range, FunctionName);
+
+ if (!HeaderName)
+ return;
+
+ if (!EmitHeaderHint)
+ return;
+
+ S.Diag(Loc, diag::note_please_include_header) << HeaderName << FunctionName;
+}
- if (!FoundFunction) {
- S.Diag(Loc, diag::note_please_include_header)
- << S.Context.BuiltinInfo.getHeaderName(AbsKind)
- << S.Context.BuiltinInfo.GetName(AbsKind);
+static bool IsFunctionStdAbs(const FunctionDecl *FDecl) {
+ if (!FDecl)
+ return false;
+
+ if (!FDecl->getIdentifier() || !FDecl->getIdentifier()->isStr("abs"))
+ return false;
+
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(FDecl->getDeclContext());
+
+ while (ND && ND->isInlineNamespace()) {
+ ND = dyn_cast<NamespaceDecl>(ND->getDeclContext());
}
+
+ if (!ND || !ND->getIdentifier() || !ND->getIdentifier()->isStr("std"))
+ return false;
+
+ if (!isa<TranslationUnitDecl>(ND->getDeclContext()))
+ return false;
+
+ return true;
}
// Warn when using the wrong abs() function.
@@ -3920,7 +3883,8 @@ void Sema::CheckAbsoluteValueFunction(const CallExpr *Call,
return;
unsigned AbsKind = getAbsoluteValueFunctionKind(FDecl);
- if (AbsKind == 0)
+ bool IsStdAbs = IsFunctionStdAbs(FDecl);
+ if (AbsKind == 0 && !IsStdAbs)
return;
QualType ArgType = Call->getArg(0)->IgnoreParenImpCasts()->getType();
@@ -3929,13 +3893,20 @@ void Sema::CheckAbsoluteValueFunction(const CallExpr *Call,
// Unsigned types can not be negative. Suggest to drop the absolute value
// function.
if (ArgType->isUnsignedIntegerType()) {
+ const char *FunctionName =
+ IsStdAbs ? "std::abs" : Context.BuiltinInfo.GetName(AbsKind);
Diag(Call->getExprLoc(), diag::warn_unsigned_abs) << ArgType << ParamType;
Diag(Call->getExprLoc(), diag::note_remove_abs)
- << FDecl
+ << FunctionName
<< FixItHint::CreateRemoval(Call->getCallee()->getSourceRange());
return;
}
+ // std::abs has overloads which prevent most of the absolute value problems
+ // from occurring.
+ if (IsStdAbs)
+ return;
+
AbsoluteValueKind ArgValueKind = getAbsoluteValueKind(ArgType);
AbsoluteValueKind ParamValueKind = getAbsoluteValueKind(ParamType);
@@ -3953,7 +3924,7 @@ void Sema::CheckAbsoluteValueFunction(const CallExpr *Call,
return;
emitReplacement(*this, Call->getExprLoc(),
- Call->getCallee()->getSourceRange(), NewAbsKind);
+ Call->getCallee()->getSourceRange(), NewAbsKind, ArgType);
return;
}
@@ -3969,7 +3940,7 @@ void Sema::CheckAbsoluteValueFunction(const CallExpr *Call,
<< FDecl << ParamValueKind << ArgValueKind;
emitReplacement(*this, Call->getExprLoc(),
- Call->getCallee()->getSourceRange(), NewAbsKind);
+ Call->getCallee()->getSourceRange(), NewAbsKind, ArgType);
return;
}
@@ -5334,90 +5305,182 @@ static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E,
if (!S.ActiveTemplateInstantiations.empty())
return;
+ // TODO: Investigate using GetExprRange() to get tighter bounds
+ // on the bit ranges.
+ QualType OtherT = Other->getType();
+ IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
+ unsigned OtherWidth = OtherRange.Width;
+
+ bool OtherIsBooleanType = Other->isKnownToHaveBooleanValue();
+
// 0 values are handled later by CheckTrivialUnsignedComparison().
- if (Value == 0)
+ if ((Value == 0) && (!OtherIsBooleanType))
return;
BinaryOperatorKind op = E->getOpcode();
- QualType OtherT = Other->getType();
- QualType ConstantT = Constant->getType();
- QualType CommonT = E->getLHS()->getType();
- if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT))
- return;
- assert((OtherT->isIntegerType() && ConstantT->isIntegerType())
- && "comparison with non-integer type");
+ bool IsTrue = true;
- bool ConstantSigned = ConstantT->isSignedIntegerType();
- bool CommonSigned = CommonT->isSignedIntegerType();
+ // Used for diagnostic printout.
+ enum {
+ LiteralConstant = 0,
+ CXXBoolLiteralTrue,
+ CXXBoolLiteralFalse
+ } LiteralOrBoolConstant = LiteralConstant;
- bool EqualityOnly = false;
+ if (!OtherIsBooleanType) {
+ QualType ConstantT = Constant->getType();
+ QualType CommonT = E->getLHS()->getType();
- // TODO: Investigate using GetExprRange() to get tighter bounds on
- // on the bit ranges.
- IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
- unsigned OtherWidth = OtherRange.Width;
-
- if (CommonSigned) {
- // The common type is signed, therefore no signed to unsigned conversion.
- if (!OtherRange.NonNegative) {
- // Check that the constant is representable in type OtherT.
- if (ConstantSigned) {
- if (OtherWidth >= Value.getMinSignedBits())
- return;
- } else { // !ConstantSigned
- if (OtherWidth >= Value.getActiveBits() + 1)
- return;
+ if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT))
+ return;
+ assert((OtherT->isIntegerType() && ConstantT->isIntegerType()) &&
+ "comparison with non-integer type");
+
+ bool ConstantSigned = ConstantT->isSignedIntegerType();
+ bool CommonSigned = CommonT->isSignedIntegerType();
+
+ bool EqualityOnly = false;
+
+ if (CommonSigned) {
+ // The common type is signed, therefore no signed to unsigned conversion.
+ if (!OtherRange.NonNegative) {
+ // Check that the constant is representable in type OtherT.
+ if (ConstantSigned) {
+ if (OtherWidth >= Value.getMinSignedBits())
+ return;
+ } else { // !ConstantSigned
+ if (OtherWidth >= Value.getActiveBits() + 1)
+ return;
+ }
+ } else { // !OtherSigned
+ // Check that the constant is representable in type OtherT.
+ // Negative values are out of range.
+ if (ConstantSigned) {
+ if (Value.isNonNegative() && OtherWidth >= Value.getActiveBits())
+ return;
+ } else { // !ConstantSigned
+ if (OtherWidth >= Value.getActiveBits())
+ return;
+ }
}
- } else { // !OtherSigned
- // Check that the constant is representable in type OtherT.
- // Negative values are out of range.
- if (ConstantSigned) {
- if (Value.isNonNegative() && OtherWidth >= Value.getActiveBits())
- return;
- } else { // !ConstantSigned
+ } else { // !CommonSigned
+ if (OtherRange.NonNegative) {
if (OtherWidth >= Value.getActiveBits())
return;
+ } else if (!OtherRange.NonNegative && !ConstantSigned) {
+ // Check to see if the constant is representable in OtherT.
+ if (OtherWidth > Value.getActiveBits())
+ return;
+ // Check to see if the constant is equivalent to a negative value
+ // cast to CommonT.
+ if (S.Context.getIntWidth(ConstantT) ==
+ S.Context.getIntWidth(CommonT) &&
+ Value.isNegative() && Value.getMinSignedBits() <= OtherWidth)
+ return;
+ // The constant value rests between values that OtherT can represent
+ // after conversion. Relational comparison still works, but equality
+ // comparisons will be tautological.
+ EqualityOnly = true;
+ } else { // OtherSigned && ConstantSigned
+ assert(0 && "Two signed types converted to unsigned types.");
}
}
- } else { // !CommonSigned
- if (OtherRange.NonNegative) {
- if (OtherWidth >= Value.getActiveBits())
- return;
- } else if (!OtherRange.NonNegative && !ConstantSigned) {
- // Check to see if the constant is representable in OtherT.
- if (OtherWidth > Value.getActiveBits())
- return;
- // Check to see if the constant is equivalent to a negative value
- // cast to CommonT.
- if (S.Context.getIntWidth(ConstantT) == S.Context.getIntWidth(CommonT) &&
- Value.isNegative() && Value.getMinSignedBits() <= OtherWidth)
- return;
- // The constant value rests between values that OtherT can represent after
- // conversion. Relational comparison still works, but equality
- // comparisons will be tautological.
- EqualityOnly = true;
- } else { // OtherSigned && ConstantSigned
- assert(0 && "Two signed types converted to unsigned types.");
- }
- }
- bool PositiveConstant = !ConstantSigned || Value.isNonNegative();
+ bool PositiveConstant = !ConstantSigned || Value.isNonNegative();
- bool IsTrue = true;
- if (op == BO_EQ || op == BO_NE) {
- IsTrue = op == BO_NE;
- } else if (EqualityOnly) {
- return;
- } else if (RhsConstant) {
- if (op == BO_GT || op == BO_GE)
- IsTrue = !PositiveConstant;
- else // op == BO_LT || op == BO_LE
- IsTrue = PositiveConstant;
+ if (op == BO_EQ || op == BO_NE) {
+ IsTrue = op == BO_NE;
+ } else if (EqualityOnly) {
+ return;
+ } else if (RhsConstant) {
+ if (op == BO_GT || op == BO_GE)
+ IsTrue = !PositiveConstant;
+ else // op == BO_LT || op == BO_LE
+ IsTrue = PositiveConstant;
+ } else {
+ if (op == BO_LT || op == BO_LE)
+ IsTrue = !PositiveConstant;
+ else // op == BO_GT || op == BO_GE
+ IsTrue = PositiveConstant;
+ }
} else {
- if (op == BO_LT || op == BO_LE)
- IsTrue = !PositiveConstant;
- else // op == BO_GT || op == BO_GE
- IsTrue = PositiveConstant;
+ // Other isKnownToHaveBooleanValue
+ enum CompareBoolWithConstantResult { AFals, ATrue, Unkwn };
+ enum ConstantValue { LT_Zero, Zero, One, GT_One, SizeOfConstVal };
+ enum ConstantSide { Lhs, Rhs, SizeOfConstSides };
+
+ static const struct LinkedConditions {
+ CompareBoolWithConstantResult BO_LT_OP[SizeOfConstSides][SizeOfConstVal];
+ CompareBoolWithConstantResult BO_GT_OP[SizeOfConstSides][SizeOfConstVal];
+ CompareBoolWithConstantResult BO_LE_OP[SizeOfConstSides][SizeOfConstVal];
+ CompareBoolWithConstantResult BO_GE_OP[SizeOfConstSides][SizeOfConstVal];
+ CompareBoolWithConstantResult BO_EQ_OP[SizeOfConstSides][SizeOfConstVal];
+ CompareBoolWithConstantResult BO_NE_OP[SizeOfConstSides][SizeOfConstVal];
+
+ } TruthTable = {
+ // Constant on LHS. | Constant on RHS. |
+ // LT_Zero| Zero | One |GT_One| LT_Zero| Zero | One |GT_One|
+ { { ATrue, Unkwn, AFals, AFals }, { AFals, AFals, Unkwn, ATrue } },
+ { { AFals, AFals, Unkwn, ATrue }, { ATrue, Unkwn, AFals, AFals } },
+ { { ATrue, ATrue, Unkwn, AFals }, { AFals, Unkwn, ATrue, ATrue } },
+ { { AFals, Unkwn, ATrue, ATrue }, { ATrue, ATrue, Unkwn, AFals } },
+ { { AFals, Unkwn, Unkwn, AFals }, { AFals, Unkwn, Unkwn, AFals } },
+ { { ATrue, Unkwn, Unkwn, ATrue }, { ATrue, Unkwn, Unkwn, ATrue } }
+ };
+
+ bool ConstantIsBoolLiteral = isa<CXXBoolLiteralExpr>(Constant);
+
+ enum ConstantValue ConstVal = Zero;
+ if (Value.isUnsigned() || Value.isNonNegative()) {
+ if (Value == 0) {
+ LiteralOrBoolConstant =
+ ConstantIsBoolLiteral ? CXXBoolLiteralFalse : LiteralConstant;
+ ConstVal = Zero;
+ } else if (Value == 1) {
+ LiteralOrBoolConstant =
+ ConstantIsBoolLiteral ? CXXBoolLiteralTrue : LiteralConstant;
+ ConstVal = One;
+ } else {
+ LiteralOrBoolConstant = LiteralConstant;
+ ConstVal = GT_One;
+ }
+ } else {
+ ConstVal = LT_Zero;
+ }
+
+ CompareBoolWithConstantResult CmpRes;
+
+ switch (op) {
+ case BO_LT:
+ CmpRes = TruthTable.BO_LT_OP[RhsConstant][ConstVal];
+ break;
+ case BO_GT:
+ CmpRes = TruthTable.BO_GT_OP[RhsConstant][ConstVal];
+ break;
+ case BO_LE:
+ CmpRes = TruthTable.BO_LE_OP[RhsConstant][ConstVal];
+ break;
+ case BO_GE:
+ CmpRes = TruthTable.BO_GE_OP[RhsConstant][ConstVal];
+ break;
+ case BO_EQ:
+ CmpRes = TruthTable.BO_EQ_OP[RhsConstant][ConstVal];
+ break;
+ case BO_NE:
+ CmpRes = TruthTable.BO_NE_OP[RhsConstant][ConstVal];
+ break;
+ default:
+ CmpRes = Unkwn;
+ break;
+ }
+
+ if (CmpRes == AFals) {
+ IsTrue = false;
+ } else if (CmpRes == ATrue) {
+ IsTrue = true;
+ } else {
+ return;
+ }
}
// If this is a comparison to an enum constant, include that
@@ -5433,11 +5496,12 @@ static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E,
else
OS << Value;
- S.DiagRuntimeBehavior(E->getOperatorLoc(), E,
- S.PDiag(diag::warn_out_of_range_compare)
- << OS.str() << OtherT << IsTrue
- << E->getLHS()->getSourceRange()
- << E->getRHS()->getSourceRange());
+ S.DiagRuntimeBehavior(
+ E->getOperatorLoc(), E,
+ S.PDiag(diag::warn_out_of_range_compare)
+ << OS.str() << LiteralOrBoolConstant
+ << OtherT << (OtherIsBooleanType && !OtherT->isBooleanType()) << IsTrue
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange());
}
/// Analyze the operands of the given comparison. Implements the
@@ -6025,7 +6089,7 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
if (E->isTypeDependent() || E->isValueDependent())
return;
-
+
// For conditional operators, we analyze the arguments as if they
// were being fed directly into the output.
if (isa<ConditionalOperator>(E)) {
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index d44c04b480..4b23c37a63 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -2987,11 +2987,16 @@ static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results,
for (Preprocessor::macro_iterator M = PP.macro_begin(),
MEnd = PP.macro_end();
M != MEnd; ++M) {
- if (IncludeUndefined || M->first->hasMacroDefinition())
+ if (IncludeUndefined || M->first->hasMacroDefinition()) {
+ if (MacroInfo *MI = M->second->getMacroInfo())
+ if (MI->isUsedForHeaderGuard())
+ continue;
+
Results.AddResult(Result(M->first,
getMacroUsagePriority(M->first->getName(),
PP.getLangOpts(),
TargetTypeIsPointer)));
+ }
}
Results.ExitScope();
@@ -3828,7 +3833,7 @@ void Sema::CodeCompleteCall(Scope *S, Expr *FnIn, ArrayRef<Expr *> Args) {
// Build an overload candidate set based on the functions we find.
SourceLocation Loc = Fn->getExprLoc();
- OverloadCandidateSet CandidateSet(Loc);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
// FIXME: What if we're calling something that isn't a function declaration?
// FIXME: What if we're calling a pseudo-destructor?
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 43d855c0cb..ed74c5d47a 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -218,7 +218,8 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
if (CorrectedII) {
TypeNameValidatorCCC Validator(true, isClassName);
TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(),
- Kind, S, SS, Validator);
+ Kind, S, SS, Validator,
+ CTK_ErrorRecovery);
IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo();
TemplateTy Template;
bool MemberOfUnknownSpecialization;
@@ -408,7 +409,7 @@ bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
TypeNameValidatorCCC Validator(false, false, AllowClassTemplates);
if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc),
LookupOrdinaryName, S, SS,
- Validator)) {
+ Validator, CTK_ErrorRecovery)) {
if (Corrected.isKeyword()) {
// We corrected to a keyword.
diagnoseTypo(Corrected, PDiag(diag::err_unknown_typename_suggest) << II);
@@ -584,16 +585,15 @@ Sema::NameClassification Sema::ClassifyName(Scope *S,
CorrectionCandidateCallback *CCC) {
DeclarationNameInfo NameInfo(Name, NameLoc);
ObjCMethodDecl *CurMethod = getCurMethodDecl();
-
+
if (NextToken.is(tok::coloncolon)) {
BuildCXXNestedNameSpecifier(S, *Name, NameLoc, NextToken.getLocation(),
QualType(), false, SS, 0, false);
-
}
-
+
LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName);
LookupParsedName(Result, S, &SS, !CurMethod);
-
+
// Perform lookup for Objective-C instance variables (including automatically
// synthesized instance variables), if we're in an Objective-C method.
// FIXME: This lookup really, really needs to be folded in to the normal
@@ -651,7 +651,8 @@ Corrected:
SecondTry = true;
if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
Result.getLookupKind(), S,
- &SS, *CCC)) {
+ &SS, *CCC,
+ CTK_ErrorRecovery)) {
unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
unsigned QualifiedDiag = diag::err_no_member_suggest;
@@ -1423,7 +1424,7 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
DeclFilterCCC<ObjCInterfaceDecl> Validator;
if (TypoCorrection C = CorrectTypo(DeclarationNameInfo(Id, IdLoc),
LookupOrdinaryName, TUScope, NULL,
- Validator)) {
+ Validator, CTK_ErrorRecovery)) {
diagnoseTypo(C, PDiag(diag::err_undef_interface_suggest) << Id);
IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>();
Id = IDecl->getIdentifier();
@@ -1924,43 +1925,43 @@ static bool mergeAlignedAttrs(Sema &S, NamedDecl *New, Decl *Old) {
return AnyAdded;
}
-static bool mergeDeclAttribute(Sema &S, NamedDecl *D, InheritableAttr *Attr,
- bool Override) {
- InheritableAttr *NewAttr = NULL;
+static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
+ const InheritableAttr *Attr, bool Override) {
+ InheritableAttr *NewAttr = nullptr;
unsigned AttrSpellingListIndex = Attr->getSpellingListIndex();
- if (AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attr))
+ if (const auto *AA = dyn_cast<AvailabilityAttr>(Attr))
NewAttr = S.mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
AA->getIntroduced(), AA->getDeprecated(),
AA->getObsoleted(), AA->getUnavailable(),
AA->getMessage(), Override,
AttrSpellingListIndex);
- else if (VisibilityAttr *VA = dyn_cast<VisibilityAttr>(Attr))
+ else if (const auto *VA = dyn_cast<VisibilityAttr>(Attr))
NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
AttrSpellingListIndex);
- else if (TypeVisibilityAttr *VA = dyn_cast<TypeVisibilityAttr>(Attr))
+ else if (const auto *VA = dyn_cast<TypeVisibilityAttr>(Attr))
NewAttr = S.mergeTypeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
AttrSpellingListIndex);
- else if (DLLImportAttr *ImportA = dyn_cast<DLLImportAttr>(Attr))
+ else if (const auto *ImportA = dyn_cast<DLLImportAttr>(Attr))
NewAttr = S.mergeDLLImportAttr(D, ImportA->getRange(),
AttrSpellingListIndex);
- else if (DLLExportAttr *ExportA = dyn_cast<DLLExportAttr>(Attr))
+ else if (const auto *ExportA = dyn_cast<DLLExportAttr>(Attr))
NewAttr = S.mergeDLLExportAttr(D, ExportA->getRange(),
AttrSpellingListIndex);
- else if (FormatAttr *FA = dyn_cast<FormatAttr>(Attr))
+ else if (const auto *FA = dyn_cast<FormatAttr>(Attr))
NewAttr = S.mergeFormatAttr(D, FA->getRange(), FA->getType(),
FA->getFormatIdx(), FA->getFirstArg(),
AttrSpellingListIndex);
- else if (SectionAttr *SA = dyn_cast<SectionAttr>(Attr))
+ else if (const auto *SA = dyn_cast<SectionAttr>(Attr))
NewAttr = S.mergeSectionAttr(D, SA->getRange(), SA->getName(),
AttrSpellingListIndex);
- else if (MSInheritanceAttr *IA = dyn_cast<MSInheritanceAttr>(Attr))
+ else if (const auto *IA = dyn_cast<MSInheritanceAttr>(Attr))
NewAttr = S.mergeMSInheritanceAttr(D, IA->getRange(), IA->getBestCase(),
AttrSpellingListIndex,
IA->getSemanticSpelling());
else if (isa<AlignedAttr>(Attr))
// AlignedAttrs are handled separately, because we need to handle all
// such attributes on a declaration at the same time.
- NewAttr = 0;
+ NewAttr = nullptr;
else if (Attr->duplicatesAllowed() || !DeclHasAttr(D, Attr))
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
@@ -5229,29 +5230,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// determine whether we have a template or a template specialization.
TemplateParams = MatchTemplateParametersToScopeSpecifier(
D.getDeclSpec().getLocStart(), D.getIdentifierLoc(),
- D.getCXXScopeSpec(), TemplateParamLists,
+ D.getCXXScopeSpec(),
+ D.getName().getKind() == UnqualifiedId::IK_TemplateId
+ ? D.getName().TemplateId
+ : 0,
+ TemplateParamLists,
/*never a friend*/ false, IsExplicitSpecialization, Invalid);
- if (D.getName().getKind() == UnqualifiedId::IK_TemplateId &&
- !TemplateParams) {
- TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
-
- // We have encountered something that the user meant to be a
- // specialization (because it has explicitly-specified template
- // arguments) but that was not introduced with a "template<>" (or had
- // too few of them).
- // FIXME: Differentiate between attempts for explicit instantiations
- // (starting with "template") and the rest.
- Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header)
- << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)
- << FixItHint::CreateInsertion(D.getDeclSpec().getLocStart(),
- "template<> ");
- IsExplicitSpecialization = true;
- TemplateParams = TemplateParameterList::Create(Context, SourceLocation(),
- SourceLocation(), 0, 0,
- SourceLocation());
- }
-
if (TemplateParams) {
if (!TemplateParams->size() &&
D.getName().getKind() != UnqualifiedId::IK_TemplateId) {
@@ -5264,12 +5249,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TemplateParams->getRAngleLoc());
TemplateParams = 0;
} else {
- // Only C++1y supports variable templates (N3651).
- Diag(D.getIdentifierLoc(),
- getLangOpts().CPlusPlus1y
- ? diag::warn_cxx11_compat_variable_template
- : diag::ext_variable_template);
-
if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
// This is an explicit specialization or a partial specialization.
// FIXME: Check that we can declare a specialization here.
@@ -5282,8 +5261,17 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Check that we can declare a template here.
if (CheckTemplateDeclScope(S, TemplateParams))
return 0;
+
+ // Only C++1y supports variable templates (N3651).
+ Diag(D.getIdentifierLoc(),
+ getLangOpts().CPlusPlus1y
+ ? diag::warn_cxx11_compat_variable_template
+ : diag::ext_variable_template);
}
}
+ } else {
+ assert(D.getName().getKind() != UnqualifiedId::IK_TemplateId &&
+ "should have a 'template<>' for this decl");
}
if (IsVariableTemplateSpecialization) {
@@ -6174,7 +6162,7 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
} else if ((Correction = SemaRef.CorrectTypo(
Prev.getLookupNameInfo(), Prev.getLookupKind(), S,
&ExtraArgs.D.getCXXScopeSpec(), Validator,
- IsLocalFriend ? 0 : NewDC))) {
+ Sema::CTK_ErrorRecovery, IsLocalFriend ? 0 : NewDC))) {
// Set up everything for the call to ActOnFunctionDeclarator
ExtraArgs.D.SetIdentifier(Correction.getCorrectionAsIdentifierInfo(),
ExtraArgs.D.getIdentifierLoc());
@@ -6710,8 +6698,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (TemplateParameterList *TemplateParams =
MatchTemplateParametersToScopeSpecifier(
D.getDeclSpec().getLocStart(), D.getIdentifierLoc(),
- D.getCXXScopeSpec(), TemplateParamLists, isFriend,
- isExplicitSpecialization, Invalid)) {
+ D.getCXXScopeSpec(),
+ D.getName().getKind() == UnqualifiedId::IK_TemplateId
+ ? D.getName().TemplateId
+ : 0,
+ TemplateParamLists, isFriend, isExplicitSpecialization,
+ Invalid)) {
if (TemplateParams->size() > 0) {
// This is a function template
@@ -6752,9 +6744,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// This is a function template specialization.
isFunctionTemplateSpecialization = true;
// For source fidelity, store all the template param lists.
- NewFD->setTemplateParameterListsInfo(Context,
- TemplateParamLists.size(),
- TemplateParamLists.data());
+ if (TemplateParamLists.size() > 0)
+ NewFD->setTemplateParameterListsInfo(Context,
+ TemplateParamLists.size(),
+ TemplateParamLists.data());
// C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);".
if (isFriend) {
@@ -7059,6 +7052,17 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setInvalidDecl();
}
+ if (D.isFunctionDefinition() && CodeSegStack.CurrentValue &&
+ !NewFD->hasAttr<SectionAttr>()) {
+ NewFD->addAttr(
+ SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate,
+ CodeSegStack.CurrentValue->getString(),
+ CodeSegStack.CurrentPragmaLocation));
+ if (UnifySection(CodeSegStack.CurrentValue->getString(),
+ PSF_Implicit | PSF_Execute | PSF_Read, NewFD))
+ NewFD->dropAttr<SectionAttr>();
+ }
+
// Handle attributes.
ProcessDeclAttributes(S, NewFD, D);
@@ -7142,21 +7146,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc);
HasExplicitTemplateArgs = false;
- } else if (!isFunctionTemplateSpecialization &&
- !D.getDeclSpec().isFriendSpecified()) {
- // We have encountered something that the user meant to be a
- // specialization (because it has explicitly-specified template
- // arguments) but that was not introduced with a "template<>" (or had
- // too few of them).
- // FIXME: Differentiate between attempts for explicit instantiations
- // (starting with "template") and the rest.
- Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header)
- << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc)
- << FixItHint::CreateInsertion(
- D.getDeclSpec().getLocStart(),
- "template<> ");
- isFunctionTemplateSpecialization = true;
} else {
+ assert((isFunctionTemplateSpecialization ||
+ D.getDeclSpec().isFriendSpecified()) &&
+ "should have a 'template<>' for this decl");
// "friend void foo<>(int);" is an implicit specialization decl.
isFunctionTemplateSpecialization = true;
}
@@ -7168,7 +7161,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// friend void foo<>(int);
// Go ahead and fake up a template id.
HasExplicitTemplateArgs = true;
- TemplateArgs.setLAngleLoc(D.getIdentifierLoc());
+ TemplateArgs.setLAngleLoc(D.getIdentifierLoc());
TemplateArgs.setRAngleLoc(D.getIdentifierLoc());
}
@@ -8613,7 +8606,7 @@ void Sema::ActOnInitializerError(Decl *D) {
return;
}
- // Require an abstract type.
+ // Require a non-abstract type.
if (RequireNonAbstractType(VD->getLocation(), Ty,
diag::err_abstract_type_in_decl,
AbstractVariableType)) {
@@ -8929,6 +8922,29 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
Diag(var->getLocation(), diag::note_use_thread_local);
}
+ if (var->isThisDeclarationADefinition() &&
+ ActiveTemplateInstantiations.empty()) {
+ PragmaStack<StringLiteral *> *Stack = nullptr;
+ int SectionFlags = PSF_Implicit | PSF_Read;
+ if (var->getType().isConstQualified())
+ Stack = &ConstSegStack;
+ else if (!var->getInit()) {
+ Stack = &BSSSegStack;
+ SectionFlags |= PSF_Write;
+ } else {
+ Stack = &DataSegStack;
+ SectionFlags |= PSF_Write;
+ }
+ if (!var->hasAttr<SectionAttr>() && Stack->CurrentValue)
+ var->addAttr(
+ SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate,
+ Stack->CurrentValue->getString(),
+ Stack->CurrentPragmaLocation));
+ if (const SectionAttr *SA = var->getAttr<SectionAttr>())
+ if (UnifySection(SA->getName(), SectionFlags, var))
+ var->dropAttr<SectionAttr>();
+ }
+
// All the following checks are C++ only.
if (!getLangOpts().CPlusPlus) return;
@@ -9046,7 +9062,8 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
AddPushedVisibilityAttribute(VD);
// FIXME: Warn on unused templates.
- if (VD->isFileVarDecl() && !VD->getDescribedVarTemplate())
+ if (VD->isFileVarDecl() && !VD->getDescribedVarTemplate() &&
+ !isa<VarTemplatePartialSpecializationDecl>(VD))
MarkUnusedFileScopedDecl(VD);
// Now we have parsed the initializer and can update the table of magic
@@ -9436,8 +9453,12 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
// Since all parameters have automatic store duration, they can not have
// an address space.
if (T.getAddressSpace() != 0) {
- Diag(NameLoc, diag::err_arg_with_address_space);
- New->setInvalidDecl();
+ // OpenCL allows function arguments declared to be an array of a type
+ // to be qualified with an address space.
+ if (!(getLangOpts().OpenCL && T->isArrayType())) {
+ Diag(NameLoc, diag::err_arg_with_address_space);
+ New->setInvalidDecl();
+ }
}
return New;
@@ -9939,8 +9960,20 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
MD->isDesignatedInitializerForTheInterface(&InitMethod);
assert(isDesignated && InitMethod);
(void)isDesignated;
- // Don't issue this warning for unavaialable inits.
- if (!MD->isUnavailable()) {
+
+ auto superIsNSObject = [&](const ObjCMethodDecl *MD) {
+ auto IFace = MD->getClassInterface();
+ if (!IFace)
+ return false;
+ auto SuperD = IFace->getSuperClass();
+ if (!SuperD)
+ return false;
+ return SuperD->getIdentifier() ==
+ NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject);
+ };
+ // Don't issue this warning for unavailable inits or direct subclasses
+ // of NSObject.
+ if (!MD->isUnavailable() && !superIsNSObject(MD)) {
Diag(MD->getLocation(),
diag::warn_objc_designated_init_missing_super_call);
Diag(InitMethod->getLocation(),
@@ -10070,7 +10103,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
TypoCorrection Corrected;
DeclFilterCCC<FunctionDecl> Validator;
if (S && (Corrected = CorrectTypo(DeclarationNameInfo(&II, Loc),
- LookupOrdinaryName, S, 0, Validator)))
+ LookupOrdinaryName, S, 0, Validator,
+ CTK_NonError)))
diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion),
/*ErrorRecovery*/false);
}
@@ -10088,9 +10122,9 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
Declarator D(DS, Declarator::BlockContext);
D.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/false,
/*IsAmbiguous=*/false,
- /*RParenLoc=*/NoLoc,
- /*ArgInfo=*/0,
- /*NumArgs=*/0,
+ /*LParenLoc=*/NoLoc,
+ /*Params=*/0,
+ /*NumParams=*/0,
/*EllipsisLoc=*/NoLoc,
/*RParenLoc=*/NoLoc,
/*TypeQuals=*/0,
@@ -10520,8 +10554,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
(SS.isNotEmpty() && TUK != TUK_Reference)) {
if (TemplateParameterList *TemplateParams =
MatchTemplateParametersToScopeSpecifier(
- KWLoc, NameLoc, SS, TemplateParameterLists, TUK == TUK_Friend,
- isExplicitSpecialization, Invalid)) {
+ KWLoc, NameLoc, SS, 0, TemplateParameterLists,
+ TUK == TUK_Friend, isExplicitSpecialization, Invalid)) {
if (Kind == TTK_Enum) {
Diag(KWLoc, diag::err_enum_template);
return 0;
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 38b3c45e2a..3e2daee778 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -363,8 +363,7 @@ static const RecordType *getRecordType(QualType QT) {
return 0;
}
-static bool checkRecordTypeForCapability(Sema &S, const AttributeList &Attr,
- QualType Ty) {
+static bool checkRecordTypeForCapability(Sema &S, QualType Ty) {
const RecordType *RT = getRecordType(Ty);
if (!RT)
@@ -397,8 +396,7 @@ static bool checkRecordTypeForCapability(Sema &S, const AttributeList &Attr,
return false;
}
-static bool checkTypedefTypeForCapability(Sema &S, const AttributeList &Attr,
- QualType Ty) {
+static bool checkTypedefTypeForCapability(QualType Ty) {
const auto *TD = Ty->getAs<TypedefType>();
if (!TD)
return false;
@@ -410,18 +408,40 @@ static bool checkTypedefTypeForCapability(Sema &S, const AttributeList &Attr,
return TN->hasAttr<CapabilityAttr>();
}
-/// \brief Checks that the passed in type is qualified as a capability. This
-/// type can either be a struct, or a typedef to a built-in type (such as int).
-static void checkForCapability(Sema &S, const AttributeList &Attr,
- QualType Ty) {
- if (checkTypedefTypeForCapability(S, Attr, Ty))
- return;
+static bool typeHasCapability(Sema &S, QualType Ty) {
+ if (checkTypedefTypeForCapability(Ty))
+ return true;
- if (checkRecordTypeForCapability(S, Attr, Ty))
- return;
+ if (checkRecordTypeForCapability(S, Ty))
+ return true;
+
+ return false;
+}
+
+static bool isCapabilityExpr(Sema &S, const Expr *Ex) {
+ // Capability expressions are simple expressions involving the boolean logic
+ // operators &&, || or !, a simple DeclRefExpr, CastExpr or a ParenExpr. Once
+ // a DeclRefExpr is found, its type should be checked to determine whether it
+ // is a capability or not.
+
+ if (const auto *E = dyn_cast<DeclRefExpr>(Ex))
+ return typeHasCapability(S, E->getType());
+ else if (const auto *E = dyn_cast<CastExpr>(Ex))
+ return isCapabilityExpr(S, E->getSubExpr());
+ else if (const auto *E = dyn_cast<ParenExpr>(Ex))
+ return isCapabilityExpr(S, E->getSubExpr());
+ else if (const auto *E = dyn_cast<UnaryOperator>(Ex)) {
+ if (E->getOpcode() == UO_LNot)
+ return isCapabilityExpr(S, E->getSubExpr());
+ return false;
+ } else if (const auto *E = dyn_cast<BinaryOperator>(Ex)) {
+ if (E->getOpcode() == BO_LAnd || E->getOpcode() == BO_LOr)
+ return isCapabilityExpr(S, E->getLHS()) &&
+ isCapabilityExpr(S, E->getRHS());
+ return false;
+ }
- S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable)
- << Attr.getName() << Ty;
+ return false;
}
/// \brief Checks that all attribute arguments, starting from Sidx, resolve to
@@ -491,7 +511,13 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D,
}
}
- checkForCapability(S, Attr, ArgTy);
+ // If the type does not have a capability, see if the components of the
+ // expression have capabilities. This allows for writing C code where the
+ // capability may be on the type, and the expression is a capability
+ // boolean logic expression. Eg) requires_capability(A || B && !C)
+ if (!typeHasCapability(S, ArgTy) && !isCapabilityExpr(S, ArgExp))
+ S.Diag(Attr.getLoc(), diag::warn_thread_attribute_argument_not_lockable)
+ << Attr.getName() << ArgTy;
Args.push_back(ArgExp);
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 850db26e9a..e3bedf78e6 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1175,10 +1175,12 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
} else {
if (ReturnStmts.empty()) {
// C++1y doesn't require constexpr functions to contain a 'return'
- // statement. We still do, unless the return type is void, because
+ // statement. We still do, unless the return type might be void, because
// otherwise if there's no return statement, the function cannot
// be used in a core constant expression.
- bool OK = getLangOpts().CPlusPlus1y && Dcl->getReturnType()->isVoidType();
+ bool OK = getLangOpts().CPlusPlus1y &&
+ (Dcl->getReturnType()->isVoidType() ||
+ Dcl->getReturnType()->isDependentType());
Diag(Dcl->getLocation(),
OK ? diag::warn_cxx11_compat_constexpr_body_no_return
: diag::err_constexpr_body_no_return);
@@ -1960,14 +1962,19 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr_member);
SourceLocation ConstexprLoc = DS.getConstexprSpecLoc();
if (InitStyle == ICIS_NoInit) {
- B << 0 << 0 << FixItHint::CreateReplacement(ConstexprLoc, "const");
- D.getMutableDeclSpec().ClearConstexprSpec();
- const char *PrevSpec;
- unsigned DiagID;
- bool Failed = D.getMutableDeclSpec().SetTypeQual(DeclSpec::TQ_const, ConstexprLoc,
- PrevSpec, DiagID, getLangOpts());
- (void)Failed;
- assert(!Failed && "Making a constexpr member const shouldn't fail");
+ B << 0 << 0;
+ if (D.getDeclSpec().getTypeQualifiers() & DeclSpec::TQ_const)
+ B << FixItHint::CreateRemoval(ConstexprLoc);
+ else {
+ B << FixItHint::CreateReplacement(ConstexprLoc, "const");
+ D.getMutableDeclSpec().ClearConstexprSpec();
+ const char *PrevSpec;
+ unsigned DiagID;
+ bool Failed = D.getMutableDeclSpec().SetTypeQual(
+ DeclSpec::TQ_const, ConstexprLoc, PrevSpec, DiagID, getLangOpts());
+ (void)Failed;
+ assert(!Failed && "Making a constexpr member const shouldn't fail");
+ }
} else {
B << 1;
const char *PrevSpec;
@@ -2598,7 +2605,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
MemInitializerValidatorCCC Validator(ClassDecl);
if (R.empty() && BaseType.isNull() &&
(Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
- Validator, ClassDecl))) {
+ Validator, CTK_ErrorRecovery, ClassDecl))) {
if (FieldDecl *Member = Corr.getCorrectionDeclAs<FieldDecl>()) {
// We have found a non-static data member with a similar
// name to what was typed; complain and initialize that
@@ -3435,7 +3442,8 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
return false;
// Overwhelmingly common case: we have a direct initializer for this field.
- if (CXXCtorInitializer *Init = Info.AllBaseFields.lookup(Field))
+ if (CXXCtorInitializer *Init =
+ Info.AllBaseFields.lookup(Field->getCanonicalDecl()))
return Info.addFieldInitializer(Init);
// C++11 [class.base.init]p8:
@@ -3548,7 +3556,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
if (Member->isBaseInitializer())
Info.AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member;
else {
- Info.AllBaseFields[Member->getAnyMember()] = Member;
+ Info.AllBaseFields[Member->getAnyMember()->getCanonicalDecl()] = Member;
if (IndirectFieldDecl *F = Member->getIndirectMember()) {
for (auto *C : F->chain()) {
@@ -3696,7 +3704,7 @@ static void PopulateKeysForFields(FieldDecl *Field, SmallVectorImpl<const void*>
return;
}
}
- IdealInits.push_back(Field);
+ IdealInits.push_back(Field->getCanonicalDecl());
}
static const void *GetKeyForBase(ASTContext &Context, QualType BaseType) {
@@ -3708,7 +3716,7 @@ static const void *GetKeyForMember(ASTContext &Context,
if (!Member->isAnyMemberInitializer())
return GetKeyForBase(Context, QualType(Member->getBaseClass(), 0));
- return Member->getAnyMember();
+ return Member->getAnyMember()->getCanonicalDecl();
}
static void DiagnoseBaseOrMemInitializerOrder(
@@ -3903,13 +3911,12 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
Init->setSourceOrder(i);
if (Init->isAnyMemberInitializer()) {
- FieldDecl *Field = Init->getAnyMember();
- if (CheckRedundantInit(*this, Init, Members[Field]) ||
+ const void *Key = GetKeyForMember(Context, Init);
+ if (CheckRedundantInit(*this, Init, Members[Key]) ||
CheckRedundantUnionInit(*this, Init, MemberUnions))
HadError = true;
} else if (Init->isBaseInitializer()) {
- const void *Key =
- GetKeyForBase(Context, QualType(Init->getBaseClass(), 0));
+ const void *Key = GetKeyForMember(Context, Init);
if (CheckRedundantInit(*this, Init, Members[Key]))
HadError = true;
} else {
@@ -6893,7 +6900,8 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
R.clear();
if (TypoCorrection Corrected = S.CorrectTypo(R.getLookupNameInfo(),
R.getLookupKind(), Sc, &SS,
- Validator)) {
+ Validator,
+ Sema::CTK_ErrorRecovery)) {
if (DeclContext *DC = S.computeDeclContext(SS, false)) {
std::string CorrectedStr(Corrected.getAsString(S.getLangOpts()));
bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&
@@ -7379,6 +7387,13 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
NamedDecl *D = F.next();
if (!isDeclInScope(D, CurContext, S))
F.erase();
+ // If we found a local extern declaration that's not ordinarily visible,
+ // and this declaration is being added to a non-block scope, ignore it.
+ // We're only checking for scope conflicts here, not also for violations
+ // of the linkage rules.
+ else if (!CurContext->isFunctionOrMethod() && D->isLocalExternDecl() &&
+ !(D->getIdentifierNamespace() & Decl::IDNS_Ordinary))
+ F.erase();
}
F.done();
} else {
@@ -7457,7 +7472,8 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
UsingValidatorCCC CCC(HasTypenameKeyword, IsInstantiation,
CurContext->isRecord());
if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
- R.getLookupKind(), S, &SS, CCC)){
+ R.getLookupKind(), S, &SS, CCC,
+ CTK_ErrorRecovery)){
// We reject any correction for which ND would be NULL.
NamedDecl *ND = Corrected.getCorrectionDecl();
R.setLookupName(Corrected.getCorrection());
@@ -11358,7 +11374,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
if (TemplateParameterList *TemplateParams =
MatchTemplateParametersToScopeSpecifier(
- TagLoc, NameLoc, SS, TempParamLists, /*friend*/ true,
+ TagLoc, NameLoc, SS, 0, TempParamLists, /*friend*/ true,
isExplicitSpecialization, Invalid)) {
if (TemplateParams->size() > 0) {
// This is a declaration of a class template.
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index d59dd8b995..7fbca6aadb 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -524,7 +524,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
ObjCInterfaceValidatorCCC Validator(IDecl);
if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope,
- NULL, Validator)) {
+ NULL, Validator, CTK_ErrorRecovery)) {
diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest)
<< SuperName << ClassName);
PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
@@ -794,7 +794,7 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
DeclFilterCCC<ObjCProtocolDecl> Validator;
TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second),
- LookupObjCProtocolName, TUScope, NULL, Validator);
+ LookupObjCProtocolName, TUScope, NULL, Validator, CTK_ErrorRecovery);
if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>()))
diagnoseTypo(Corrected, PDiag(diag::err_undeclared_protocol_suggest)
<< ProtocolId[i].first);
@@ -1034,7 +1034,8 @@ Decl *Sema::ActOnStartClassImplementation(
ObjCInterfaceValidatorCCC Validator;
TypoCorrection Corrected =
CorrectTypo(DeclarationNameInfo(ClassName, ClassLoc),
- LookupOrdinaryName, TUScope, NULL, Validator);
+ LookupOrdinaryName, TUScope, NULL, Validator,
+ CTK_NonError);
if (Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
// Suggest the (potentially) correct interface name. Don't provide a
// code-modification hint or use the typo name for recovery, because
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 7894682efc..595770dc36 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1843,7 +1843,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// We didn't find anything, so try to correct for a typo.
TypoCorrection Corrected;
if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
- S, &SS, CCC))) {
+ S, &SS, CCC, CTK_ErrorRecovery))) {
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
bool DroppedSpecifier =
Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr;
@@ -1854,7 +1854,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
NamedDecl *ND = Corrected.getCorrectionDecl();
if (ND) {
if (Corrected.isOverloaded()) {
- OverloadCandidateSet OCS(R.getNameLoc());
+ OverloadCandidateSet OCS(R.getNameLoc(),
+ OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
for (TypoCorrection::decl_iterator CD = Corrected.begin(),
CDEnd = Corrected.end();
@@ -2872,6 +2873,7 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
case tok::kw___func__: IT = PredefinedExpr::Func; break; // [C99 6.4.2.2]
case tok::kw___FUNCTION__: IT = PredefinedExpr::Function; break;
case tok::kw___FUNCDNAME__: IT = PredefinedExpr::FuncDName; break; // [MS]
+ case tok::kw___FUNCSIG__: IT = PredefinedExpr::FuncSig; break; // [MS]
case tok::kw_L__FUNCTION__: IT = PredefinedExpr::LFunction; break;
case tok::kw___PRETTY_FUNCTION__: IT = PredefinedExpr::PrettyFunction; break;
}
@@ -3974,8 +3976,8 @@ namespace {
class FunctionCallCCC : public FunctionCallFilterCCC {
public:
FunctionCallCCC(Sema &SemaRef, const IdentifierInfo *FuncName,
- unsigned NumArgs, bool HasExplicitTemplateArgs)
- : FunctionCallFilterCCC(SemaRef, NumArgs, HasExplicitTemplateArgs),
+ unsigned NumArgs, MemberExpr *ME)
+ : FunctionCallFilterCCC(SemaRef, NumArgs, false, ME),
FunctionName(FuncName) {}
bool ValidateCandidate(const TypoCorrection &candidate) override {
@@ -3992,17 +3994,21 @@ private:
};
}
-static TypoCorrection TryTypoCorrectionForCall(Sema &S,
- DeclarationNameInfo FuncName,
+static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn,
+ FunctionDecl *FDecl,
ArrayRef<Expr *> Args) {
- FunctionCallCCC CCC(S, FuncName.getName().getAsIdentifierInfo(),
- Args.size(), false);
- if (TypoCorrection Corrected =
- S.CorrectTypo(FuncName, Sema::LookupOrdinaryName,
- S.getScopeForContext(S.CurContext), NULL, CCC)) {
+ MemberExpr *ME = dyn_cast<MemberExpr>(Fn);
+ DeclarationName FuncName = FDecl->getDeclName();
+ SourceLocation NameLoc = ME ? ME->getMemberLoc() : Fn->getLocStart();
+ FunctionCallCCC CCC(S, FuncName.getAsIdentifierInfo(), Args.size(), ME);
+
+ if (TypoCorrection Corrected = S.CorrectTypo(
+ DeclarationNameInfo(FuncName, NameLoc), Sema::LookupOrdinaryName,
+ S.getScopeForContext(S.CurContext), NULL, CCC,
+ Sema::CTK_ErrorRecovery)) {
if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
if (Corrected.isOverloaded()) {
- OverloadCandidateSet OCS(FuncName.getLoc());
+ OverloadCandidateSet OCS(NameLoc, OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
for (TypoCorrection::decl_iterator CD = Corrected.begin(),
CDEnd = Corrected.end();
@@ -4011,7 +4017,7 @@ static TypoCorrection TryTypoCorrectionForCall(Sema &S,
S.AddOverloadCandidate(FD, DeclAccessPair::make(FD, AS_none), Args,
OCS);
}
- switch (OCS.BestViableFunction(S, FuncName.getLoc(), Best)) {
+ switch (OCS.BestViableFunction(S, NameLoc, Best)) {
case OR_Success:
ND = Best->Function;
Corrected.setCorrectionDecl(ND);
@@ -4062,13 +4068,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
// arguments for the remaining parameters), don't make the call.
if (Args.size() < NumParams) {
if (Args.size() < MinArgs) {
- MemberExpr *ME = dyn_cast<MemberExpr>(Fn);
TypoCorrection TC;
- if (FDecl && (TC = TryTypoCorrectionForCall(
- *this, DeclarationNameInfo(FDecl->getDeclName(),
- (ME ? ME->getMemberLoc()
- : Fn->getLocStart())),
- Args))) {
+ if (FDecl && (TC = TryTypoCorrectionForCall(*this, Fn, FDecl, Args))) {
unsigned diag_id =
MinArgs == NumParams && !Proto->isVariadic()
? diag::err_typecheck_call_too_few_args_suggest
@@ -4103,13 +4104,8 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
// them.
if (Args.size() > NumParams) {
if (!Proto->isVariadic()) {
- MemberExpr *ME = dyn_cast<MemberExpr>(Fn);
TypoCorrection TC;
- if (FDecl && (TC = TryTypoCorrectionForCall(
- *this, DeclarationNameInfo(FDecl->getDeclName(),
- (ME ? ME->getMemberLoc()
- : Fn->getLocStart())),
- Args))) {
+ if (FDecl && (TC = TryTypoCorrectionForCall(*this, Fn, FDecl, Args))) {
unsigned diag_id =
MinArgs == NumParams && !Proto->isVariadic()
? diag::err_typecheck_call_too_many_args_suggest
@@ -8272,7 +8268,8 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
// Parens on the RHS are ignored.
llvm::APSInt Result;
if (RHS.get()->EvaluateAsInt(Result, Context))
- if ((getLangOpts().Bool && !RHS.get()->getType()->isBooleanType()) ||
+ if ((getLangOpts().Bool && !RHS.get()->getType()->isBooleanType() &&
+ !RHS.get()->getExprLoc().isMacroID()) ||
(Result != 0 && Result != 1)) {
Diag(Loc, diag::warn_logical_instead_of_bitwise)
<< RHS.get()->getSourceRange()
@@ -10561,7 +10558,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
// to deduce an implicit return type.
if (getLangOpts().CPlusPlus && RetTy->isRecordType() &&
!BSI->TheDecl->isDependentContext())
- computeNRVO(Body, getCurBlock());
+ computeNRVO(Body, BSI);
BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy);
AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 8b9c0e2cc7..81fabd4b20 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1853,7 +1853,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
R.suppressDiagnostics();
- OverloadCandidateSet Candidates(StartLoc);
+ OverloadCandidateSet Candidates(StartLoc, OverloadCandidateSet::CSK_Normal);
for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end();
Alloc != AllocEnd; ++Alloc) {
// Even member operator new/delete are implicitly treated as
@@ -3656,6 +3656,11 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
if (Args[0]->getType()->isIncompleteType())
return false;
+ // Make sure the first argument is not an abstract type.
+ CXXRecordDecl *RD = Args[0]->getType()->getAsCXXRecordDecl();
+ if (RD && RD->isAbstract())
+ return false;
+
SmallVector<OpaqueValueExpr, 2> OpaqueArgExprs;
SmallVector<Expr *, 2> ArgExprs;
ArgExprs.reserve(Args.size() - 1);
@@ -4298,7 +4303,8 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS,
SourceLocation QuestionLoc) {
Expr *Args[2] = { LHS.get(), RHS.get() };
- OverloadCandidateSet CandidateSet(QuestionLoc);
+ OverloadCandidateSet CandidateSet(QuestionLoc,
+ OverloadCandidateSet::CSK_Operator);
Self.AddBuiltinOperatorCandidates(OO_Conditional, QuestionLoc, Args,
CandidateSet);
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index c4a1780174..f4ff237b81 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -306,7 +306,7 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK,
// This flag determines whether or not CompName has an 's' char prefix,
// indicating that it is a string of hex values to be used as vector indices.
- bool HexSwizzle = *compStr == 's' || *compStr == 'S';
+ bool HexSwizzle = (*compStr == 's' || *compStr == 'S') && compStr[1];
bool HasRepeated = false;
bool HasIndex[16] = {};
@@ -644,7 +644,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
RecordMemberExprValidatorCCC Validator(RTy);
TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(),
R.getLookupKind(), NULL,
- &SS, Validator, DC);
+ &SS, Validator,
+ Sema::CTK_ErrorRecovery, DC);
R.clear();
if (Corrected.isResolved() && !Corrected.isKeyword()) {
R.setLookupName(Corrected.getCorrection());
@@ -1287,7 +1288,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
Validator.IsObjCIvarLookup = IsArrow;
if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
LookupMemberName, NULL, NULL,
- Validator, IDecl)) {
+ Validator, CTK_ErrorRecovery,
+ IDecl)) {
IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>();
diagnoseTypo(Corrected,
PDiag(diag::err_typecheck_member_reference_ivar_suggest)
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 5bffdd1573..7b0db1cfc1 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -1669,7 +1669,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
DeclFilterCCC<ObjCPropertyDecl> Validator;
if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL,
- NULL, Validator, IFace, false, OPT)) {
+ NULL, Validator, CTK_ErrorRecovery, IFace, false, OPT)) {
diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest)
<< MemberName << QualType(OPT, 0));
DeclarationName TypoResult = Corrected.getCorrection();
@@ -1762,10 +1762,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
// If this reference is in an @implementation, check for 'private' methods.
if (!Getter)
- if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
- if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
- if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
- Getter = ImpDecl->getClassMethod(Sel);
+ Getter = IFace->lookupPrivateClassMethod(Sel);
if (Getter) {
// FIXME: refactor/share with ActOnMemberReference().
@@ -1784,10 +1781,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
if (!Setter) {
// If this reference is in an @implementation, also check for 'private'
// methods.
- if (ObjCMethodDecl *CurMeth = getCurMethodDecl())
- if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
- if (ObjCImplementationDecl *ImpDecl = ClassDecl->getImplementation())
- Setter = ImpDecl->getClassMethod(SetterSel);
+ Setter = IFace->lookupPrivateClassMethod(SetterSel);
}
// Look through local category implementations associated with the class.
if (!Setter)
@@ -1907,7 +1901,8 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
ObjCInterfaceOrSuperCCC Validator(getCurMethodDecl());
if (TypoCorrection Corrected =
CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S,
- NULL, Validator, NULL, false, NULL, false)) {
+ NULL, Validator, CTK_ErrorRecovery, NULL, false, NULL,
+ false)) {
if (Corrected.isKeyword()) {
// If we've found the keyword "super" (the only keyword that would be
// returned by CorrectTypo), this is a send to super.
@@ -3295,7 +3290,8 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
}
template <typename TB>
-static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr) {
+static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr,
+ bool TollFreeBridgeCast) {
QualType T = castExpr->getType();
while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) {
TypedefNameDecl *TDNDecl = TD->getDecl();
@@ -3314,8 +3310,15 @@ static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr) {
ObjCInterfaceDecl *CastClass
= InterfacePointerType->getObjectType()->getInterface();
if ((CastClass == ExprClass) ||
- (CastClass && ExprClass->isSuperClassOf(CastClass)))
+ (CastClass && ExprClass->isSuperClassOf(CastClass))) {
+ if (!TollFreeBridgeCast && S.getLangOpts().ObjCAutoRefCount) {
+ // bridge attribute is ok. However, under ARC, cast still requires
+ // an explicit cast and should not compile under ARC.
+ S.Diag(castExpr->getLocStart(), diag::err_objc_invalid_bridge)
+ << T << Target->getName();
+ }
return true;
+ }
S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge)
<< T << Target->getName() << castType->getPointeeType();
return true;
@@ -3408,8 +3411,8 @@ void Sema::CheckTollFreeBridgeCast(QualType castType, Expr *castExpr) {
ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExpr->getType());
ARCConversionTypeClass castACTC = classifyTypeForARCConversion(castType);
if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation) {
- (void)CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr);
- (void)CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr);
+ (void)CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr, true);
+ (void)CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr, true);
}
else if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable) {
(void)CheckObjCBridgeCFCast<ObjCBridgeAttr>(*this, castType, castExpr);
@@ -3630,8 +3633,8 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
if (castACTC == ACTC_retainable && exprACTC == ACTC_coreFoundation &&
(CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast))
- if (CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr) ||
- CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr))
+ if (CheckObjCBridgeNSCast<ObjCBridgeAttr>(*this, castType, castExpr, false) ||
+ CheckObjCBridgeNSCast<ObjCBridgeMutableAttr>(*this, castType, castExpr, false))
return ACR_okay;
if (castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable &&
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 382901667e..2cf5598581 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -1816,7 +1816,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
if (TypoCorrection Corrected = SemaRef.CorrectTypo(
DeclarationNameInfo(FieldName, D->getFieldLoc()),
Sema::LookupMemberName, /*Scope=*/ 0, /*SS=*/ 0, Validator,
- RT->getDecl())) {
+ Sema::CTK_ErrorRecovery, RT->getDecl())) {
SemaRef.diagnoseTypo(
Corrected,
SemaRef.PDiag(diag::err_field_designator_unknown_suggest)
@@ -4411,7 +4411,7 @@ InitializationSequence::InitializationSequence(Sema &S,
const InitializationKind &Kind,
MultiExprArg Args,
bool TopLevelOfInitList)
- : FailedCandidateSet(Kind.getLocation()) {
+ : FailedCandidateSet(Kind.getLocation(), OverloadCandidateSet::CSK_Normal) {
InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList);
}
@@ -4945,7 +4945,7 @@ static ExprResult CopyObject(Sema &S,
// Only consider constructors and constructor templates. Per
// C++0x [dcl.init]p16, second bullet to class types, this initialization
// is direct-initialization.
- OverloadCandidateSet CandidateSet(Loc);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
LookupCopyAndMoveConstructors(S, CandidateSet, Class, CurInitExpr);
bool HadMultipleCandidates = (CandidateSet.size() > 1);
@@ -5053,7 +5053,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
return;
// Find constructors which would have been considered.
- OverloadCandidateSet CandidateSet(Loc);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
LookupCopyAndMoveConstructors(
S, CandidateSet, cast<CXXRecordDecl>(Record->getDecl()), CurInitExpr);
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 0d287f7210..537f1ec8ab 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -1139,6 +1139,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,
bool IsInstantiation) {
+ LambdaScopeInfo *LSI = getCurLambda();
+
// Leave the expression-evaluation context.
DiscardCleanupsInEvaluationContext();
PopExpressionEvaluationContext();
@@ -1148,7 +1150,6 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,
PopDeclContext();
// Finalize the lambda.
- LambdaScopeInfo *LSI = getCurLambda();
CXXRecordDecl *Class = LSI->Lambda;
Class->setInvalidDecl();
SmallVector<Decl*, 4> Fields(Class->fields());
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index ac6fb25cae..e8ef5ac6b9 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/Overload.h"
@@ -244,10 +245,11 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
IDNS = Decl::IDNS_Tag;
}
break;
+
case Sema::LookupLabel:
IDNS = Decl::IDNS_Label;
break;
-
+
case Sema::LookupMemberName:
IDNS = Decl::IDNS_Member;
if (CPlusPlus)
@@ -263,8 +265,10 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
break;
case Sema::LookupUsingDeclName:
- IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag
- | Decl::IDNS_Member | Decl::IDNS_Using;
+ assert(Redeclaration && "should only be used for redecl lookup");
+ IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member |
+ Decl::IDNS_Using | Decl::IDNS_TagFriend | Decl::IDNS_OrdinaryFriend |
+ Decl::IDNS_LocalExtern;
break;
case Sema::LookupObjCProtocolName:
@@ -2308,43 +2312,6 @@ void Sema::FindAssociatedClassesAndNamespaces(
}
}
-/// IsAcceptableNonMemberOperatorCandidate - Determine whether Fn is
-/// an acceptable non-member overloaded operator for a call whose
-/// arguments have types T1 (and, if non-empty, T2). This routine
-/// implements the check in C++ [over.match.oper]p3b2 concerning
-/// enumeration types.
-static bool
-IsAcceptableNonMemberOperatorCandidate(FunctionDecl *Fn,
- QualType T1, QualType T2,
- ASTContext &Context) {
- if (T1->isDependentType() || (!T2.isNull() && T2->isDependentType()))
- return true;
-
- if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
- return true;
-
- const FunctionProtoType *Proto = Fn->getType()->getAs<FunctionProtoType>();
- if (Proto->getNumParams() < 1)
- return false;
-
- if (T1->isEnumeralType()) {
- QualType ArgType = Proto->getParamType(0).getNonReferenceType();
- if (Context.hasSameUnqualifiedType(T1, ArgType))
- return true;
- }
-
- if (Proto->getNumParams() < 2)
- return false;
-
- if (!T2.isNull() && T2->isEnumeralType()) {
- QualType ArgType = Proto->getParamType(1).getNonReferenceType();
- if (Context.hasSameUnqualifiedType(T2, ArgType))
- return true;
- }
-
- return false;
-}
-
NamedDecl *Sema::LookupSingleName(Scope *S, DeclarationName Name,
SourceLocation Loc,
LookupNameKind NameKind,
@@ -2371,37 +2338,13 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
// unqualified lookup of operator@ in the context of the
// expression according to the usual rules for name lookup in
// unqualified function calls (3.4.2) except that all member
- // functions are ignored. However, if no operand has a class
- // type, only those non-member functions in the lookup set
- // that have a first parameter of type T1 or "reference to
- // (possibly cv-qualified) T1", when T1 is an enumeration
- // type, or (if there is a right operand) a second parameter
- // of type T2 or "reference to (possibly cv-qualified) T2",
- // when T2 is an enumeration type, are candidate functions.
+ // functions are ignored.
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
LookupResult Operators(*this, OpName, SourceLocation(), LookupOperatorName);
LookupName(Operators, S);
assert(!Operators.isAmbiguous() && "Operator lookup cannot be ambiguous");
-
- if (Operators.empty())
- return;
-
- for (LookupResult::iterator Op = Operators.begin(), OpEnd = Operators.end();
- Op != OpEnd; ++Op) {
- NamedDecl *Found = (*Op)->getUnderlyingDecl();
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Found)) {
- if (IsAcceptableNonMemberOperatorCandidate(FD, T1, T2, Context))
- Functions.addDecl(*Op, Op.getAccess()); // FIXME: canonical FD
- } else if (FunctionTemplateDecl *FunTmpl
- = dyn_cast<FunctionTemplateDecl>(Found)) {
- // FIXME: friend operators?
- // FIXME: do we need to check IsAcceptableNonMemberOperatorCandidate,
- // later?
- if (!FunTmpl->getDeclContext()->isRecord())
- Functions.addDecl(*Op, Op.getAccess());
- }
- }
+ Functions.append(Operators.begin(), Operators.end());
}
Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
@@ -2522,7 +2465,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
// Now we perform lookup on the name we computed earlier and do overload
// resolution. Lookup is only performed directly into the class since there
// will always be a (possibly implicit) declaration to shadow any others.
- OverloadCandidateSet OCS(RD->getLocation());
+ OverloadCandidateSet OCS(RD->getLocation(), OverloadCandidateSet::CSK_Normal);
DeclContext::lookup_result R = RD->lookup(Name);
assert(!R.empty() &&
"lookup for a constructor or assignment operator was empty");
@@ -2842,9 +2785,8 @@ void ADLResult::insert(NamedDecl *New) {
Old = New;
}
-void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
- SourceLocation Loc, ArrayRef<Expr *> Args,
- ADLResult &Result) {
+void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
+ ArrayRef<Expr *> Args, ADLResult &Result) {
// Find all of the associated namespaces and classes based on the
// arguments we have.
AssociatedNamespaceSet AssociatedNamespaces;
@@ -2853,13 +2795,6 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
AssociatedNamespaces,
AssociatedClasses);
- QualType T1, T2;
- if (Operator) {
- T1 = Args[0]->getType();
- if (Args.size() >= 2)
- T2 = Args[1]->getType();
- }
-
// C++ [basic.lookup.argdep]p3:
// Let X be the lookup set produced by unqualified lookup (3.4.1)
// and let Y be the lookup set produced by argument dependent
@@ -2912,12 +2847,7 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
- if (isa<FunctionDecl>(D)) {
- if (Operator &&
- !IsAcceptableNonMemberOperatorCandidate(cast<FunctionDecl>(D),
- T1, T2, Context))
- continue;
- } else if (!isa<FunctionTemplateDecl>(D))
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D))
continue;
Result.insert(D);
@@ -3995,6 +3925,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
Sema::LookupNameKind LookupKind,
Scope *S, CXXScopeSpec *SS,
CorrectionCandidateCallback &CCC,
+ CorrectTypoKind Mode,
DeclContext *MemberContext,
bool EnteringContext,
const ObjCObjectPointerType *OPT,
@@ -4049,10 +3980,20 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (getLangOpts().AltiVec && Typo->isStr("vector"))
return TypoCorrection();
- NamespaceSpecifierSet Namespaces(Context, CurContext, SS);
-
TypoCorrectionConsumer Consumer(*this, Typo);
+ if ((Mode == CTK_ErrorRecovery) && getLangOpts().Modules &&
+ getLangOpts().ModulesSearchAll) {
+ if (PP.getModuleLoader().lookupMissingImports(Typo->getName(),
+ TypoName.getLocStart())) {
+ TypoCorrection TC(TypoName.getName(), (NestedNameSpecifier *)0, 0);
+ TC.setCorrectionRange(SS, TypoName);
+ TC.setRequiresImport(true);
+ }
+ }
+
+ NamespaceSpecifierSet Namespaces(Context, CurContext, SS);
+
// If a callback object considers an empty typo correction candidate to be
// viable, assume it does not do any actual validation of the candidates.
TypoCorrection EmptyCorrection;
@@ -4511,10 +4452,9 @@ bool CorrectionCandidateCallback::ValidateCandidate(const TypoCorrection &candid
FunctionCallFilterCCC::FunctionCallFilterCCC(Sema &SemaRef, unsigned NumArgs,
bool HasExplicitTemplateArgs,
- bool AllowNonStaticMethods)
+ MemberExpr *ME)
: NumArgs(NumArgs), HasExplicitTemplateArgs(HasExplicitTemplateArgs),
- AllowNonStaticMethods(AllowNonStaticMethods),
- CurContext(SemaRef.CurContext) {
+ CurContext(SemaRef.CurContext), MemberFn(ME) {
WantTypeSpecifiers = SemaRef.getLangOpts().CPlusPlus;
WantRemainingKeywords = false;
}
@@ -4550,13 +4490,16 @@ bool FunctionCallFilterCCC::ValidateCandidate(const TypoCorrection &candidate) {
FD->getMinRequiredArguments() <= NumArgs))
continue;
- // If the current candidate is a non-static C++ method and non-static
- // methods are being excluded, then skip the candidate unless the current
- // DeclContext is a method in the same class or a descendent class of the
- // candidate's parent class.
+ // If the current candidate is a non-static C++ method, skip the candidate
+ // unless the method being corrected--or the current DeclContext, if the
+ // function being corrected is not a method--is a method in the same class
+ // or a descendent class of the candidate's parent class.
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
- if (!AllowNonStaticMethods && !MD->isStatic()) {
- CXXMethodDecl *CurMD = dyn_cast_or_null<CXXMethodDecl>(CurContext);
+ if (MemberFn || !MD->isStatic()) {
+ CXXMethodDecl *CurMD =
+ MemberFn
+ ? dyn_cast_or_null<CXXMethodDecl>(MemberFn->getMemberDecl())
+ : dyn_cast_or_null<CXXMethodDecl>(CurContext);
CXXRecordDecl *CurRD =
CurMD ? CurMD->getParent()->getCanonicalDecl() : 0;
CXXRecordDecl *RD = MD->getParent()->getCanonicalDecl();
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 3f37efa7c1..75dc5cfd90 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -1969,8 +1969,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
ObjCReturnsInnerPointerAttr::CreateImplicit(Context, Loc));
if (const SectionAttr *SA = property->getAttr<SectionAttr>())
- GetterMethod->addAttr(SectionAttr::CreateImplicit(Context, SA->getName(),
- Loc));
+ GetterMethod->addAttr(
+ SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section,
+ SA->getName(), Loc));
if (getLangOpts().ObjCAutoRefCount)
CheckARCMethodDecl(GetterMethod);
@@ -2022,8 +2023,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
if (lexicalDC)
SetterMethod->setLexicalDeclContext(lexicalDC);
if (const SectionAttr *SA = property->getAttr<SectionAttr>())
- SetterMethod->addAttr(SectionAttr::CreateImplicit(Context,
- SA->getName(), Loc));
+ SetterMethod->addAttr(
+ SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section,
+ SA->getName(), Loc));
// It's possible for the user to have set a very odd custom
// setter selector that causes it to have a method family.
if (getLangOpts().ObjCAutoRefCount)
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index 78f73c0c26..b4d359edb4 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -256,8 +256,7 @@ DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) {
if (Stack.size() > 2) {
reverse_iterator I = Iter, E = Stack.rend() - 1;
Scope *TopScope = 0;
- while (I != E &&
- I->Directive != OMPD_parallel) {
+ while (I != E && I->Directive != OMPD_parallel) {
++I;
}
if (I == E) return false;
@@ -295,9 +294,10 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) {
if (Kind != OMPD_parallel) {
if (isOpenMPLocal(D, std::next(Stack.rbegin())) && D->isLocalVarDecl() &&
(D->getStorageClass() == SC_Auto ||
- D->getStorageClass() == SC_None))
+ D->getStorageClass() == SC_None)) {
DVar.CKind = OMPC_private;
return DVar;
+ }
}
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
@@ -429,7 +429,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
if (!Lookup.isSingleResult()) {
VarDeclFilterCCC Validator(*this);
if (TypoCorrection Corrected = CorrectTypo(Id, LookupOrdinaryName, CurScope,
- 0, Validator)) {
+ 0, Validator, CTK_ErrorRecovery)) {
diagnoseTypo(Corrected,
PDiag(Lookup.empty()? diag::err_undeclared_var_use_suggest
: diag::err_omp_expected_var_arg_suggest)
@@ -775,6 +775,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
+ case OMPC_linear:
case OMPC_copyin:
case OMPC_threadprivate:
case OMPC_unknown:
@@ -930,6 +931,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind,
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
+ case OMPC_linear:
case OMPC_copyin:
case OMPC_threadprivate:
case OMPC_unknown:
@@ -987,8 +989,10 @@ OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,
OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
ArrayRef<Expr *> VarList,
+ Expr *TailExpr,
SourceLocation StartLoc,
SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
SourceLocation EndLoc) {
OMPClause *Res = 0;
switch (Kind) {
@@ -1001,6 +1005,10 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
case OMPC_shared:
Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_linear:
+ Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc,
+ ColonLoc, EndLoc);
+ break;
case OMPC_copyin:
Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
@@ -1383,6 +1391,135 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
return OMPSharedClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
}
+OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end();
+ I != E; ++I) {
+ assert(*I && "NULL expr in OpenMP linear clause.");
+ if (isa<DependentScopeDeclRefExpr>(*I)) {
+ // It will be analyzed later.
+ Vars.push_back(*I);
+ continue;
+ }
+
+ // OpenMP [2.14.3.7, linear clause]
+ // A list item that appears in a linear clause is subject to the private
+ // clause semantics described in Section 2.14.3.3 on page 159 except as
+ // noted. In addition, the value of the new list item on each iteration
+ // of the associated loop(s) corresponds to the value of the original
+ // list item before entering the construct plus the logical number of
+ // the iteration times linear-step.
+
+ SourceLocation ELoc = (*I)->getExprLoc();
+ // OpenMP [2.1, C/C++]
+ // A list item is a variable name.
+ // OpenMP [2.14.3.3, Restrictions, p.1]
+ // A variable that is part of another variable (as an array or
+ // structure element) cannot appear in a private clause.
+ DeclRefExpr *DE = dyn_cast<DeclRefExpr>(*I);
+ if (!DE || !isa<VarDecl>(DE->getDecl())) {
+ Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange();
+ continue;
+ }
+
+ VarDecl *VD = cast<VarDecl>(DE->getDecl());
+
+ // OpenMP [2.14.3.7, linear clause]
+ // A list-item cannot appear in more than one linear clause.
+ // A list-item that appears in a linear clause cannot appear in any
+ // other data-sharing attribute clause.
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
+ if (DVar.RefExpr) {
+ Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_linear);
+ Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(DVar.CKind);
+ continue;
+ }
+
+ QualType QType = VD->getType();
+ if (QType->isDependentType() || QType->isInstantiationDependentType()) {
+ // It will be analyzed later.
+ Vars.push_back(DE);
+ continue;
+ }
+
+ // A variable must not have an incomplete type or a reference type.
+ if (RequireCompleteType(ELoc, QType,
+ diag::err_omp_linear_incomplete_type)) {
+ continue;
+ }
+ if (QType->isReferenceType()) {
+ Diag(ELoc, diag::err_omp_clause_ref_type_arg)
+ << getOpenMPClauseName(OMPC_linear) << QType;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+
+ // A list item must not be const-qualified.
+ if (QType.isConstant(Context)) {
+ Diag(ELoc, diag::err_omp_const_variable)
+ << getOpenMPClauseName(OMPC_linear);
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+
+ // A list item must be of integral or pointer type.
+ QType = QType.getUnqualifiedType().getCanonicalType();
+ const Type *Ty = QType.getTypePtrOrNull();
+ if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) &&
+ !Ty->isPointerType())) {
+ Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << QType;
+ bool IsDecl =
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+
+ DSAStack->addDSA(VD, DE, OMPC_linear);
+ Vars.push_back(DE);
+ }
+
+ if (Vars.empty())
+ return 0;
+
+ Expr *StepExpr = Step;
+ if (Step && !Step->isValueDependent() && !Step->isTypeDependent() &&
+ !Step->isInstantiationDependent() &&
+ !Step->containsUnexpandedParameterPack()) {
+ SourceLocation StepLoc = Step->getLocStart();
+ ExprResult Val = PerformImplicitIntegerConversion(StepLoc, Step);
+ if (Val.isInvalid())
+ return 0;
+ StepExpr = Val.take();
+
+ // Warn about zero linear step (it would be probably better specified as
+ // making corresponding variables 'const').
+ llvm::APSInt Result;
+ if (StepExpr->isIntegerConstantExpr(Result, Context) &&
+ !Result.isNegative() && !Result.isStrictlyPositive())
+ Diag(StepLoc, diag::warn_omp_linear_step_zero) << Vars[0]
+ << (Vars.size() > 1);
+ }
+
+ return OMPLinearClause::Create(Context, StartLoc, LParenLoc, ColonLoc, EndLoc,
+ Vars, StepExpr);
+}
+
OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index ee1feb5c82..1f2875cd6f 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1127,7 +1127,8 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
}
// Attempt user-defined conversion.
- OverloadCandidateSet Conversions(From->getExprLoc());
+ OverloadCandidateSet Conversions(From->getExprLoc(),
+ OverloadCandidateSet::CSK_Normal);
OverloadingResult UserDefResult
= IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions,
AllowExplicit, AllowObjCConversionOnExplicit);
@@ -3244,7 +3245,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
bool
Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
ImplicitConversionSequence ICS;
- OverloadCandidateSet CandidateSet(From->getExprLoc());
+ OverloadCandidateSet CandidateSet(From->getExprLoc(),
+ OverloadCandidateSet::CSK_Normal);
OverloadingResult OvResult =
IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined,
CandidateSet, false, false);
@@ -4071,7 +4073,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
CXXRecordDecl *T2RecordDecl
= dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
- OverloadCandidateSet CandidateSet(DeclLoc);
+ OverloadCandidateSet CandidateSet(DeclLoc, OverloadCandidateSet::CSK_Normal);
std::pair<CXXRecordDecl::conversion_iterator,
CXXRecordDecl::conversion_iterator>
Conversions = T2RecordDecl->getVisibleConversionFunctions();
@@ -5419,7 +5421,7 @@ ExprResult Sema::PerformContextualImplicitConversion(
// If one unique T is found:
// First, build a candidate set from the previously recorded
// potentially viable conversions.
- OverloadCandidateSet CandidateSet(Loc);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal);
collectViableConversionCandidates(*this, From, ToType, ViableConversions,
CandidateSet);
@@ -5476,6 +5478,45 @@ ExprResult Sema::PerformContextualImplicitConversion(
return finishContextualImplicitConversion(*this, Loc, From, Converter);
}
+/// IsAcceptableNonMemberOperatorCandidate - Determine whether Fn is
+/// an acceptable non-member overloaded operator for a call whose
+/// arguments have types T1 (and, if non-empty, T2). This routine
+/// implements the check in C++ [over.match.oper]p3b2 concerning
+/// enumeration types.
+static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context,
+ FunctionDecl *Fn,
+ ArrayRef<Expr *> Args) {
+ QualType T1 = Args[0]->getType();
+ QualType T2 = Args.size() > 1 ? Args[1]->getType() : QualType();
+
+ if (T1->isDependentType() || (!T2.isNull() && T2->isDependentType()))
+ return true;
+
+ if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType()))
+ return true;
+
+ const FunctionProtoType *Proto = Fn->getType()->getAs<FunctionProtoType>();
+ if (Proto->getNumParams() < 1)
+ return false;
+
+ if (T1->isEnumeralType()) {
+ QualType ArgType = Proto->getParamType(0).getNonReferenceType();
+ if (Context.hasSameUnqualifiedType(T1, ArgType))
+ return true;
+ }
+
+ if (Proto->getNumParams() < 2)
+ return false;
+
+ if (!T2.isNull() && T2->isEnumeralType()) {
+ QualType ArgType = Proto->getParamType(1).getNonReferenceType();
+ if (Context.hasSameUnqualifiedType(T2, ArgType))
+ return true;
+ }
+
+ return false;
+}
+
/// AddOverloadCandidate - Adds the given function to the set of
/// candidate functions, using the given function call arguments. If
/// @p SuppressUserConversions, then don't allow user-defined
@@ -5519,6 +5560,17 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
if (!CandidateSet.isNewCandidate(Function))
return;
+ // C++ [over.match.oper]p3:
+ // if no operand has a class type, only those non-member functions in the
+ // lookup set that have a first parameter of type T1 or "reference to
+ // (possibly cv-qualified) T1", when T1 is an enumeration type, or (if there
+ // is a right operand) a second parameter of type T2 or "reference to
+ // (possibly cv-qualified) T2", when T2 is an enumeration type, are
+ // candidate functions.
+ if (CandidateSet.getKind() == OverloadCandidateSet::CSK_Operator &&
+ !IsAcceptableNonMemberOperatorCandidate(Context, Function, Args))
+ return;
+
// C++11 [class.copy]p11: [DR1402]
// A defaulted move constructor that is defined as deleted is ignored by
// overload resolution.
@@ -8084,7 +8136,7 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
/// candidate set (C++ [basic.lookup.argdep]).
void
Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
- bool Operator, SourceLocation Loc,
+ SourceLocation Loc,
ArrayRef<Expr *> Args,
TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
@@ -8099,7 +8151,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
// we supposed to consider on ADL candidates, anyway?
// FIXME: Pass in the explicit template arguments?
- ArgumentDependentLookup(Name, Operator, Loc, Args, Fns);
+ ArgumentDependentLookup(Name, Loc, Args, Fns);
// Erase all of the candidates we already knew about.
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
@@ -10197,8 +10249,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
/*KnownValid*/ true);
if (ULE->requiresADL())
- AddArgumentDependentLookupCandidates(ULE->getName(), /*Operator*/ false,
- ULE->getExprLoc(),
+ AddArgumentDependentLookupCandidates(ULE->getName(), ULE->getExprLoc(),
Args, ExplicitTemplateArgs,
CandidateSet, PartialOverloading);
}
@@ -10225,6 +10276,7 @@ static bool canBeDeclaredInNamespace(const DeclarationName &Name) {
static bool
DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
const CXXScopeSpec &SS, LookupResult &R,
+ OverloadCandidateSet::CandidateSetKind CSK,
TemplateArgumentListInfo *ExplicitTemplateArgs,
ArrayRef<Expr *> Args) {
if (SemaRef.ActiveTemplateInstantiations.empty() || !SS.isEmpty())
@@ -10246,7 +10298,7 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
return false;
}
- OverloadCandidateSet Candidates(FnLoc);
+ OverloadCandidateSet Candidates(FnLoc, CSK);
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
AddOverloadedCallCandidate(SemaRef, I.getPair(),
ExplicitTemplateArgs, Args,
@@ -10330,6 +10382,7 @@ DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op,
SemaRef.Context.DeclarationNames.getCXXOperatorName(Op);
LookupResult R(SemaRef, OpName, OpLoc, Sema::LookupOperatorName);
return DiagnoseTwoPhaseLookup(SemaRef, OpLoc, CXXScopeSpec(), R,
+ OverloadCandidateSet::CSK_Operator,
/*ExplicitTemplateArgs=*/0, Args);
}
@@ -10383,12 +10436,14 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(),
Sema::LookupOrdinaryName);
FunctionCallFilterCCC Validator(SemaRef, Args.size(),
- ExplicitTemplateArgs != 0, false);
+ ExplicitTemplateArgs != 0,
+ dyn_cast<MemberExpr>(Fn));
NoTypoCorrectionCCC RejectAll;
CorrectionCandidateCallback *CCC = AllowTypoCorrection ?
(CorrectionCandidateCallback*)&Validator :
(CorrectionCandidateCallback*)&RejectAll;
if (!DiagnoseTwoPhaseLookup(SemaRef, Fn->getExprLoc(), SS, R,
+ OverloadCandidateSet::CSK_Normal,
ExplicitTemplateArgs, Args) &&
(!EmptyLookup ||
SemaRef.DiagnoseEmptyLookup(S, SS, R, *CCC,
@@ -10567,7 +10622,8 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn,
SourceLocation RParenLoc,
Expr *ExecConfig,
bool AllowTypoCorrection) {
- OverloadCandidateSet CandidateSet(Fn->getExprLoc());
+ OverloadCandidateSet CandidateSet(Fn->getExprLoc(),
+ OverloadCandidateSet::CSK_Normal);
ExprResult result;
if (buildOverloadedCallSet(S, Fn, ULE, Args, LParenLoc, &CandidateSet,
@@ -10656,7 +10712,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
}
// Build an empty overload set.
- OverloadCandidateSet CandidateSet(OpLoc);
+ OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);
// Add the candidates from the given function set.
AddFunctionCandidates(Fns, ArgsArray, CandidateSet, false);
@@ -10665,9 +10721,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
AddMemberOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
// Add candidates from ADL.
- AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true, OpLoc,
- ArgsArray, /*ExplicitTemplateArgs*/ 0,
- CandidateSet);
+ AddArgumentDependentLookupCandidates(OpName, OpLoc, ArgsArray,
+ /*ExplicitTemplateArgs*/0, CandidateSet);
// Add builtin operator candidates.
AddBuiltinOperatorCandidates(Op, OpLoc, ArgsArray, CandidateSet);
@@ -10871,7 +10926,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]);
// Build an empty overload set.
- OverloadCandidateSet CandidateSet(OpLoc);
+ OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator);
// Add the candidates from the given function set.
AddFunctionCandidates(Fns, Args, CandidateSet, false);
@@ -10880,8 +10935,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet);
// Add candidates from ADL.
- AddArgumentDependentLookupCandidates(OpName, /*Operator*/ true,
- OpLoc, Args,
+ AddArgumentDependentLookupCandidates(OpName, OpLoc, Args,
/*ExplicitTemplateArgs*/ 0,
CandidateSet);
@@ -11107,7 +11161,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
return ExprError();
// Build an empty overload set.
- OverloadCandidateSet CandidateSet(LLoc);
+ OverloadCandidateSet CandidateSet(LLoc, OverloadCandidateSet::CSK_Operator);
// Subscript can only be overloaded as a member function.
@@ -11330,7 +11384,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
: UnresExpr->getBase()->Classify(Context);
// Add overload candidates
- OverloadCandidateSet CandidateSet(UnresExpr->getMemberLoc());
+ OverloadCandidateSet CandidateSet(UnresExpr->getMemberLoc(),
+ OverloadCandidateSet::CSK_Normal);
// FIXME: avoid copy.
TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
@@ -11514,7 +11569,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// operators of T. The function call operators of T are obtained by
// ordinary lookup of the name operator() in the context of
// (E).operator().
- OverloadCandidateSet CandidateSet(LParenLoc);
+ OverloadCandidateSet CandidateSet(LParenLoc,
+ OverloadCandidateSet::CSK_Operator);
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call);
if (RequireCompleteType(LParenLoc, Object.get()->getType(),
@@ -11793,7 +11849,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
// overload resolution mechanism (13.3).
DeclarationName OpName =
Context.DeclarationNames.getCXXOperatorName(OO_Arrow);
- OverloadCandidateSet CandidateSet(Loc);
+ OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Operator);
const RecordType *BaseRecord = Base->getType()->getAs<RecordType>();
if (RequireCompleteType(Loc, Base->getType(),
@@ -11895,7 +11951,8 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
TemplateArgumentListInfo *TemplateArgs) {
SourceLocation UDSuffixLoc = SuffixInfo.getCXXLiteralOperatorNameLoc();
- OverloadCandidateSet CandidateSet(UDSuffixLoc);
+ OverloadCandidateSet CandidateSet(UDSuffixLoc,
+ OverloadCandidateSet::CSK_Normal);
AddFunctionCandidates(R.asUnresolvedSet(), Args, CandidateSet, true,
TemplateArgs);
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index de02fa935e..a8463cdbd4 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -681,7 +681,8 @@ ExprResult ObjCPropertyOpBuilder::buildGet() {
// Build a message-send.
ExprResult msg;
- if (Getter->isInstanceMethod() || RefExpr->isObjectReceiver()) {
+ if ((Getter->isInstanceMethod() && !RefExpr->isClassReceiver()) ||
+ RefExpr->isObjectReceiver()) {
assert(InstanceReceiver || RefExpr->isSuperReceiver());
msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType,
GenericLoc, Getter->getSelector(),
@@ -750,7 +751,8 @@ ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
// Build a message-send.
ExprResult msg;
- if (Setter->isInstanceMethod() || RefExpr->isObjectReceiver()) {
+ if ((Setter->isInstanceMethod() && !RefExpr->isClassReceiver()) ||
+ RefExpr->isObjectReceiver()) {
msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType,
GenericLoc, SetterSelector, Setter,
MultiExprArg(args, 1));
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 2be5d5cb83..f40b409c92 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -2194,7 +2194,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
return StmtError();
}
} else {
- OverloadCandidateSet CandidateSet(RangeLoc);
+ OverloadCandidateSet CandidateSet(RangeLoc,
+ OverloadCandidateSet::CSK_Normal);
Sema::BeginEndFunction BEFFailure;
ForRangeStatus RangeStatus =
BuildNonArrayForRange(*this, S, BeginRangeRef.get(),
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 9be7189ba9..fb35f9084f 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -325,7 +325,8 @@ void Sema::LookupTemplateName(LookupResult &Found,
FilterCCC.WantCXXNamedCasts = true;
if (TypoCorrection Corrected = CorrectTypo(Found.getLookupNameInfo(),
Found.getLookupKind(), S, &SS,
- FilterCCC, LookupCtx)) {
+ FilterCCC, CTK_ErrorRecovery,
+ LookupCtx)) {
Found.setLookupName(Corrected.getCorrection());
if (Corrected.getCorrectionDecl())
Found.addDecl(Corrected.getCorrectionDecl());
@@ -1593,6 +1594,9 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context,
/// parameter lists. This scope specifier precedes a qualified name that is
/// being declared.
///
+/// \param TemplateId The template-id following the scope specifier, if there
+/// is one. Used to check for a missing 'template<>'.
+///
/// \param ParamLists the template parameter lists, from the outermost to the
/// innermost template parameter lists.
///
@@ -1611,6 +1615,7 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context,
/// itself a template).
TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS,
+ TemplateIdAnnotation *TemplateId,
ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend,
bool &IsExplicitSpecialization, bool &Invalid) {
IsExplicitSpecialization = false;
@@ -1717,6 +1722,37 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// template<> for each enclosing class template that is
// explicitly specialized.
bool SawNonEmptyTemplateParameterList = false;
+
+ auto CheckExplicitSpecialization = [&](SourceRange Range, bool Recovery) {
+ if (SawNonEmptyTemplateParameterList) {
+ Diag(DeclLoc, diag::err_specialize_member_of_template)
+ << !Recovery << Range;
+ Invalid = true;
+ IsExplicitSpecialization = false;
+ return true;
+ }
+
+ return false;
+ };
+
+ auto DiagnoseMissingExplicitSpecialization = [&] (SourceRange Range) {
+ // Check that we can have an explicit specialization here.
+ if (CheckExplicitSpecialization(Range, true))
+ return true;
+
+ // We don't have a template header, but we should.
+ SourceLocation ExpectedTemplateLoc;
+ if (!ParamLists.empty())
+ ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc();
+ else
+ ExpectedTemplateLoc = DeclStartLoc;
+
+ Diag(DeclLoc, diag::err_template_spec_needs_header)
+ << Range
+ << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
+ return false;
+ };
+
unsigned ParamIdx = 0;
for (unsigned TypeIdx = 0, NumTypes = NestedTypes.size(); TypeIdx != NumTypes;
++TypeIdx) {
@@ -1787,13 +1823,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// are not explicitly specialized as well.
if (ParamIdx < ParamLists.size()) {
if (ParamLists[ParamIdx]->size() == 0) {
- if (SawNonEmptyTemplateParameterList) {
- Diag(DeclLoc, diag::err_specialize_member_of_template)
- << ParamLists[ParamIdx]->getSourceRange();
- Invalid = true;
- IsExplicitSpecialization = false;
+ if (CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange(),
+ false))
return 0;
- }
} else
SawNonEmptyTemplateParameterList = true;
}
@@ -1816,28 +1848,20 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
Invalid = true;
return 0;
}
-
+
// Consume this template header.
++ParamIdx;
continue;
- }
-
- if (!IsFriend) {
- // We don't have a template header, but we should.
- SourceLocation ExpectedTemplateLoc;
- if (!ParamLists.empty())
- ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc();
- else
- ExpectedTemplateLoc = DeclStartLoc;
-
- Diag(DeclLoc, diag::err_template_spec_needs_header)
- << getRangeOfTypeInNestedNameSpecifier(Context, T, SS)
- << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
}
-
+
+ if (!IsFriend)
+ if (DiagnoseMissingExplicitSpecialization(
+ getRangeOfTypeInNestedNameSpecifier(Context, T, SS)))
+ return 0;
+
continue;
}
-
+
if (NeedNonemptyTemplateHeader) {
// In friend declarations we can have template-ids which don't
// depend on the corresponding template parameter lists. But
@@ -1875,12 +1899,26 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
continue;
}
}
-
+
// If there were at least as many template-ids as there were template
// parameter lists, then there are no template parameter lists remaining for
// the declaration itself.
- if (ParamIdx >= ParamLists.size())
+ if (ParamIdx >= ParamLists.size()) {
+ if (TemplateId && !IsFriend) {
+ // We don't have a template header for the declaration itself, but we
+ // should.
+ IsExplicitSpecialization = true;
+ DiagnoseMissingExplicitSpecialization(SourceRange(TemplateId->LAngleLoc,
+ TemplateId->RAngleLoc));
+
+ // Fabricate an empty template parameter list for the invented header.
+ return TemplateParameterList::Create(Context, SourceLocation(),
+ SourceLocation(), 0, 0,
+ SourceLocation());
+ }
+
return 0;
+ }
// If there were too many template parameter lists, complain about that now.
if (ParamIdx < ParamLists.size() - 1) {
@@ -1921,14 +1959,11 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
// unspecialized, except that the declaration shall not explicitly
// specialize a class member template if its en- closing class templates
// are not explicitly specialized as well.
- if (ParamLists.back()->size() == 0 && SawNonEmptyTemplateParameterList) {
- Diag(DeclLoc, diag::err_specialize_member_of_template)
- << ParamLists[ParamIdx]->getSourceRange();
- Invalid = true;
- IsExplicitSpecialization = false;
+ if (ParamLists.back()->size() == 0 &&
+ CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange(),
+ false))
return 0;
- }
-
+
// Return the last template parameter list, which corresponds to the
// entity being declared.
return ParamLists.back();
@@ -2355,6 +2390,17 @@ static bool isSameAsPrimaryTemplate(TemplateParameterList *Params,
return true;
}
+/// Convert the parser's template argument list representation into our form.
+static TemplateArgumentListInfo
+makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {
+ TemplateArgumentListInfo TemplateArgs(TemplateId.LAngleLoc,
+ TemplateId.RAngleLoc);
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId.getTemplateArgs(),
+ TemplateId.NumArgs);
+ S.translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
+ return TemplateArgs;
+}
+
DeclResult Sema::ActOnVarTemplateSpecialization(
Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc,
TemplateParameterList *TemplateParams, VarDecl::StorageClass SC,
@@ -2364,13 +2410,12 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
"Variable template specialization is declared with a template it.");
TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
+ TemplateArgumentListInfo TemplateArgs =
+ makeTemplateArgumentListInfo(*this, *TemplateId);
SourceLocation TemplateNameLoc = D.getIdentifierLoc();
SourceLocation LAngleLoc = TemplateId->LAngleLoc;
SourceLocation RAngleLoc = TemplateId->RAngleLoc;
- ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
- TemplateId->NumArgs);
- TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
- translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
+
TemplateName Name = TemplateId->Template.get();
// The template-id must name a variable template.
@@ -5840,23 +5885,23 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
TagUseKind TUK,
SourceLocation KWLoc,
SourceLocation ModulePrivateLoc,
- CXXScopeSpec &SS,
- TemplateTy TemplateD,
- SourceLocation TemplateNameLoc,
- SourceLocation LAngleLoc,
- ASTTemplateArgsPtr TemplateArgsIn,
- SourceLocation RAngleLoc,
+ TemplateIdAnnotation &TemplateId,
AttributeList *Attr,
MultiTemplateParamsArg TemplateParameterLists) {
assert(TUK != TUK_Reference && "References are not specializations");
+ CXXScopeSpec &SS = TemplateId.SS;
+
// NOTE: KWLoc is the location of the tag keyword. This will instead
// store the location of the outermost template keyword in the declaration.
SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0
- ? TemplateParameterLists[0]->getTemplateLoc() : SourceLocation();
+ ? TemplateParameterLists[0]->getTemplateLoc() : KWLoc;
+ SourceLocation TemplateNameLoc = TemplateId.TemplateNameLoc;
+ SourceLocation LAngleLoc = TemplateId.LAngleLoc;
+ SourceLocation RAngleLoc = TemplateId.RAngleLoc;
// Find the class template we're specializing
- TemplateName Name = TemplateD.get();
+ TemplateName Name = TemplateId.Template.get();
ClassTemplateDecl *ClassTemplate
= dyn_cast_or_null<ClassTemplateDecl>(Name.getAsTemplateDecl());
@@ -5877,8 +5922,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
bool Invalid = false;
TemplateParameterList *TemplateParams =
MatchTemplateParametersToScopeSpecifier(
- TemplateNameLoc, TemplateNameLoc, SS, TemplateParameterLists,
- TUK == TUK_Friend, isExplicitSpecialization, Invalid);
+ KWLoc, TemplateNameLoc, SS, &TemplateId,
+ TemplateParameterLists, TUK == TUK_Friend, isExplicitSpecialization,
+ Invalid);
if (Invalid)
return true;
@@ -5929,11 +5975,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
<< SourceRange(LAngleLoc, RAngleLoc);
else
isExplicitSpecialization = true;
- } else if (TUK != TUK_Friend) {
- Diag(KWLoc, diag::err_template_spec_needs_header)
- << FixItHint::CreateInsertion(KWLoc, "template<> ");
- TemplateKWLoc = KWLoc;
- isExplicitSpecialization = true;
+ } else {
+ assert(TUK == TUK_Friend && "should have a 'template<>' for this decl");
}
// Check that the specialization uses the same tag kind as the
@@ -5953,10 +5996,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
}
// Translate the parser's template argument list in our AST format.
- TemplateArgumentListInfo TemplateArgs;
- TemplateArgs.setLAngleLoc(LAngleLoc);
- TemplateArgs.setRAngleLoc(RAngleLoc);
- translateTemplateArguments(TemplateArgsIn, TemplateArgs);
+ TemplateArgumentListInfo TemplateArgs =
+ makeTemplateArgumentListInfo(*this, TemplateId);
// Check for unexpanded parameter packs in any of the template arguments.
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
@@ -7147,6 +7188,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// TSK_ExplicitInstantiationDefinition
if (Old_TSK == TSK_ExplicitInstantiationDeclaration &&
TSK == TSK_ExplicitInstantiationDefinition)
+ // FIXME: Need to notify the ASTMutationListener that we did this.
Def->setTemplateSpecializationKind(TSK);
InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK);
@@ -7416,13 +7458,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
}
// Translate the parser's template argument list into our AST format.
- TemplateArgumentListInfo TemplateArgs;
- TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
- TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
- TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
- TemplateId->NumArgs);
- translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
+ TemplateArgumentListInfo TemplateArgs =
+ makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc,
D.getIdentifierLoc(), TemplateArgs);
@@ -7492,12 +7529,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
bool HasExplicitTemplateArgs = false;
TemplateArgumentListInfo TemplateArgs;
if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
- TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
- TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc);
- TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc);
- ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
- TemplateId->NumArgs);
- translateTemplateArguments(TemplateArgsPtr, TemplateArgs);
+ TemplateArgs = makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
HasExplicitTemplateArgs = true;
}
@@ -7593,7 +7625,11 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (Attr)
ProcessDeclAttributeList(S, Specialization, Attr);
- if (TSK == TSK_ExplicitInstantiationDefinition)
+ if (Specialization->isDefined()) {
+ // Let the ASTConsumer know that this function has been explicitly
+ // instantiated now, and its linkage might have changed.
+ Consumer.HandleTopLevelDecl(DeclGroupRef(Specialization));
+ } else if (TSK == TSK_ExplicitInstantiationDefinition)
InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization);
// C++0x [temp.explicit]p2:
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 1ee3e4b23a..657ea6488a 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2369,6 +2369,9 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation,
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateSpecializationKind TSK) {
+ // FIXME: We need to notify the ASTMutationListener that we did all of these
+ // things, in case we have an explicit instantiation definition in a PCM, a
+ // module, or preamble, and the declaration is in an imported AST.
assert(
(TSK == TSK_ExplicitInstantiationDefinition ||
TSK == TSK_ExplicitInstantiationDeclaration ||
@@ -2393,28 +2396,27 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
SuppressNew) ||
SuppressNew)
continue;
-
- if (Function->isDefined())
+
+ // C++11 [temp.explicit]p8:
+ // An explicit instantiation definition that names a class template
+ // specialization explicitly instantiates the class template
+ // specialization and is only an explicit instantiation definition
+ // of members whose definition is visible at the point of
+ // instantiation.
+ if (TSK == TSK_ExplicitInstantiationDefinition && !Pattern->isDefined())
continue;
- if (TSK == TSK_ExplicitInstantiationDefinition) {
- // C++0x [temp.explicit]p8:
- // An explicit instantiation definition that names a class template
- // specialization explicitly instantiates the class template
- // specialization and is only an explicit instantiation definition
- // of members whose definition is visible at the point of
- // instantiation.
- if (!Pattern->isDefined())
- continue;
-
- Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
-
+ Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
+
+ if (Function->isDefined()) {
+ // Let the ASTConsumer know that this function has been explicitly
+ // instantiated now, and its linkage might have changed.
+ Consumer.HandleTopLevelDecl(DeclGroupRef(Function));
+ } else if (TSK == TSK_ExplicitInstantiationDefinition) {
InstantiateFunctionDefinition(PointOfInstantiation, Function);
- } else {
- Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
- if (TSK == TSK_ImplicitInstantiation)
- PendingLocalImplicitInstantiations.push_back(
- std::make_pair(Function, PointOfInstantiation));
+ } else if (TSK == TSK_ImplicitInstantiation) {
+ PendingLocalImplicitInstantiations.push_back(
+ std::make_pair(Function, PointOfInstantiation));
}
}
} else if (auto *Var = dyn_cast<VarDecl>(D)) {
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index de850e3901..8439f9f7d0 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -810,7 +810,7 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
case LookupResult::NotFoundInCurrentInstantiation:
if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
R.getLookupKind(), S, 0,
- Validator)) {
+ Validator, CTK_ErrorRecovery)) {
diagnoseTypo(Corrected,
PDiag(diag::err_sizeof_pack_no_pack_name_suggest) << &Name,
PDiag(diag::note_parameter_pack_here));
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index f78fca7a29..f113891882 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1382,6 +1382,19 @@ public:
EndLoc);
}
+ /// \brief Build a new OpenMP 'linear' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation ColonLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPLinearClause(VarList, Step, StartLoc, LParenLoc,
+ ColonLoc, EndLoc);
+ }
+
/// \brief Build a new OpenMP 'copyin' clause.
///
/// By default, performs semantic analysis to build the new statement.
@@ -6387,8 +6400,8 @@ OMPClause *
TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
- for (auto *I : C->varlists()) {
- ExprResult EVar = getDerived().TransformExpr(cast<Expr>(I));
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
if (EVar.isInvalid())
return 0;
Vars.push_back(EVar.take());
@@ -6405,8 +6418,8 @@ TreeTransform<Derived>::TransformOMPFirstprivateClause(
OMPFirstprivateClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
- for (auto *I : C->varlists()) {
- ExprResult EVar = getDerived().TransformExpr(cast<Expr>(I));
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
if (EVar.isInvalid())
return 0;
Vars.push_back(EVar.take());
@@ -6422,8 +6435,8 @@ OMPClause *
TreeTransform<Derived>::TransformOMPSharedClause(OMPSharedClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
- for (auto *I : C->varlists()) {
- ExprResult EVar = getDerived().TransformExpr(cast<Expr>(I));
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
if (EVar.isInvalid())
return 0;
Vars.push_back(EVar.take());
@@ -6436,11 +6449,30 @@ TreeTransform<Derived>::TransformOMPSharedClause(OMPSharedClause *C) {
template<typename Derived>
OMPClause *
+TreeTransform<Derived>::TransformOMPLinearClause(OMPLinearClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return 0;
+ Vars.push_back(EVar.take());
+ }
+ ExprResult Step = getDerived().TransformExpr(C->getStep());
+ if (Step.isInvalid())
+ return 0;
+ return getDerived().RebuildOMPLinearClause(
+ Vars, Step.take(), C->getLocStart(), C->getLParenLoc(), C->getColonLoc(),
+ C->getLocEnd());
+}
+
+template<typename Derived>
+OMPClause *
TreeTransform<Derived>::TransformOMPCopyinClause(OMPCopyinClause *C) {
llvm::SmallVector<Expr *, 16> Vars;
Vars.reserve(C->varlist_size());
- for (auto *I : C->varlists()) {
- ExprResult EVar = getDerived().TransformExpr(cast<Expr>(I));
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
if (EVar.isInvalid())
return 0;
Vars.push_back(EVar.take());
@@ -9759,9 +9791,6 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(Callee)) {
assert(ULE->requiresADL());
-
- // FIXME: Do we have to check
- // IsAcceptableNonMemberOperatorCandidate for each of these?
Functions.append(ULE->decls_begin(), ULE->decls_end());
} else {
// If we've resolved this to a particular non-member function, just call
diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h
index 524a9c2fdc..c766974926 100644
--- a/lib/Serialization/ASTCommon.h
+++ b/lib/Serialization/ASTCommon.h
@@ -27,6 +27,7 @@ enum DeclUpdateKind {
UPD_CXX_ADDED_ANONYMOUS_NAMESPACE,
UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION,
+ UPD_CXX_INSTANTIATED_CLASS_DEFINITION,
UPD_CXX_RESOLVED_EXCEPTION_SPEC,
UPD_CXX_DEDUCED_RETURN_TYPE,
UPD_DECL_MARKED_USED,
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index ff0b1dd629..834917de1d 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -70,6 +70,14 @@ ChainedASTReaderListener::ReadFullVersionInformation(StringRef FullVersion) {
return First->ReadFullVersionInformation(FullVersion) ||
Second->ReadFullVersionInformation(FullVersion);
}
+void ChainedASTReaderListener::ReadModuleName(StringRef ModuleName) {
+ First->ReadModuleName(ModuleName);
+ Second->ReadModuleName(ModuleName);
+}
+void ChainedASTReaderListener::ReadModuleMapFile(StringRef ModuleMapPath) {
+ First->ReadModuleMapFile(ModuleMapPath);
+ Second->ReadModuleMapFile(ModuleMapPath);
+}
bool ChainedASTReaderListener::ReadLanguageOptions(const LangOptions &LangOpts,
bool Complain) {
return First->ReadLanguageOptions(LangOpts, Complain) ||
@@ -851,11 +859,11 @@ bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
Error("Expected visible lookup table block");
return true;
}
- Info.NameLookupTableData
- = ASTDeclContextNameLookupTable::Create(
- (const unsigned char *)Blob.data() + Record[0],
- (const unsigned char *)Blob.data(),
- ASTDeclContextNameLookupTrait(*this, M));
+ Info.NameLookupTableData = ASTDeclContextNameLookupTable::Create(
+ (const unsigned char *)Blob.data() + Record[0],
+ (const unsigned char *)Blob.data() + sizeof(uint32_t),
+ (const unsigned char *)Blob.data(),
+ ASTDeclContextNameLookupTrait(*this, M));
}
return false;
@@ -1161,7 +1169,7 @@ std::pair<SourceLocation, StringRef> ASTReader::getModuleImportLoc(int ID) {
// FIXME: Can we map this down to a particular submodule? That would be
// ideal.
- return std::make_pair(M->ImportLoc, llvm::sys::path::stem(M->FileName));
+ return std::make_pair(M->ImportLoc, StringRef(M->ModuleName));
}
/// \brief Find the location where the module F is imported.
@@ -1172,14 +1180,10 @@ SourceLocation ASTReader::getImportLocation(ModuleFile *F) {
// Otherwise we have a PCH. It's considered to be "imported" at the first
// location of its includer.
if (F->ImportedBy.empty() || !F->ImportedBy[0]) {
- // Main file is the importer. We assume that it is the first entry in the
- // entry table. We can't ask the manager, because at the time of PCH loading
- // the main file entry doesn't exist yet.
- // The very first entry is the invalid instantiation loc, which takes up
- // offsets 0 and 1.
- return SourceLocation::getFromRawEncoding(2U);
- }
- //return F->Loaders[0]->FirstLoc;
+ // Main file is the importer.
+ assert(!SourceMgr.getMainFileID().isInvalid() && "missing main file");
+ return SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
+ }
return F->ImportedBy[0]->FirstLoc;
}
@@ -1271,6 +1275,7 @@ MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
MacroInfo *MI = PP.AllocateDeserializedMacroInfo(Loc, SubModID);
MI->setDefinitionEndLoc(ReadSourceLocation(F, Record, NextIndex));
MI->setIsUsed(Record[NextIndex++]);
+ MI->setUsedForHeaderGuard(Record[NextIndex++]);
if (RecType == PP_MACRO_FUNCTION_LIKE) {
// Decode function-like macro info.
@@ -2088,6 +2093,7 @@ void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M,
ASTReader::ASTReadResult
ASTReader::ReadControlBlock(ModuleFile &F,
SmallVectorImpl<ImportedModule> &Loaded,
+ const ModuleFile *ImportedBy,
unsigned ClientLoadCapabilities) {
BitstreamCursor &Stream = F.Stream;
@@ -2117,7 +2123,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
unsigned NumUserInputs = Record[1];
if (!DisableValidation &&
- (!HSOpts.ModulesValidateOncePerBuildSession ||
+ (ValidateSystemInputs || !HSOpts.ModulesValidateOncePerBuildSession ||
F.InputFilesValidationTimestamp <= HSOpts.BuildSessionTimestamp)) {
bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
@@ -2313,6 +2319,49 @@ ASTReader::ReadControlBlock(ModuleFile &F,
F.OriginalDir = Blob;
break;
+ case MODULE_NAME:
+ F.ModuleName = Blob;
+ if (Listener)
+ Listener->ReadModuleName(F.ModuleName);
+ break;
+
+ case MODULE_MAP_FILE:
+ F.ModuleMapPath = Blob;
+
+ // Try to resolve ModuleName in the current header search context and
+ // verify that it is found in the same module map file as we saved. If the
+ // top-level AST file is a main file, skip this check because there is no
+ // usable header search context.
+ assert(!F.ModuleName.empty() &&
+ "MODULE_NAME should come before MOUDLE_MAP_FILE");
+ if (F.Kind == MK_Module &&
+ (*ModuleMgr.begin())->Kind != MK_MainFile) {
+ Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName);
+ if (!M) {
+ assert(ImportedBy && "top-level import should be verified");
+ if ((ClientLoadCapabilities & ARR_Missing) == 0)
+ Diag(diag::err_imported_module_not_found)
+ << F.ModuleName << ImportedBy->FileName;
+ return Missing;
+ }
+
+ const FileEntry *StoredModMap = FileMgr.getFile(F.ModuleMapPath);
+ if (StoredModMap == nullptr || StoredModMap != M->ModuleMap) {
+ assert(M->ModuleMap && "found module is missing module map file");
+ assert(M->Name == F.ModuleName && "found module with different name");
+ assert(ImportedBy && "top-level import should be verified");
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Diag(diag::err_imported_module_modmap_changed)
+ << F.ModuleName << ImportedBy->FileName
+ << M->ModuleMap->getName() << F.ModuleMapPath;
+ return OutOfDate;
+ }
+ }
+
+ if (Listener)
+ Listener->ReadModuleMapFile(F.ModuleMapPath);
+ break;
+
case INPUT_FILE_OFFSETS:
F.InputFileOffsets = (const uint32_t *)Blob.data();
F.InputFilesLoaded.resize(Record[0]);
@@ -2321,12 +2370,13 @@ ASTReader::ReadControlBlock(ModuleFile &F,
}
}
-bool ASTReader::ReadASTBlock(ModuleFile &F) {
+ASTReader::ASTReadResult
+ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
BitstreamCursor &Stream = F.Stream;
if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
Error("malformed block record in AST file");
- return true;
+ return Failure;
}
// Read all of the records and blocks for the AST file.
@@ -2337,7 +2387,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
switch (Entry.Kind) {
case llvm::BitstreamEntry::Error:
Error("error at end of module block in AST file");
- return true;
+ return Failure;
case llvm::BitstreamEntry::EndBlock: {
// Outside of C++, we do not store a lookup map for the translation unit.
// Instead, mark it as needing a lookup map to be built if this module
@@ -2349,7 +2399,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
!getContext().getLangOpts().CPlusPlus)
DC->setMustBuildLookupTable();
- return false;
+ return Success;
}
case llvm::BitstreamEntry::SubBlock:
switch (Entry.ID) {
@@ -2363,7 +2413,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
// Read the abbrevs.
ReadBlockAbbrevs(F.DeclsCursor, DECLTYPES_BLOCK_ID)) {
Error("malformed block record in AST file");
- return true;
+ return Failure;
}
break;
@@ -2375,7 +2425,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
if (Stream.SkipBlock() ||
ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) {
Error("malformed block record in AST file");
- return true;
+ return Failure;
}
F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo();
break;
@@ -2386,7 +2436,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
ReadBlockAbbrevs(F.PreprocessorDetailCursor,
PREPROCESSOR_DETAIL_BLOCK_ID)) {
Error("malformed preprocessor detail record in AST file");
- return true;
+ return Failure;
}
F.PreprocessorDetailStartOffset
= F.PreprocessorDetailCursor.GetCurrentBitNo();
@@ -2399,12 +2449,12 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case SOURCE_MANAGER_BLOCK_ID:
if (ReadSourceManagerBlock(F))
- return true;
+ return Failure;
break;
case SUBMODULE_BLOCK_ID:
- if (ReadSubmoduleBlock(F))
- return true;
+ if (ASTReadResult Result = ReadSubmoduleBlock(F, ClientLoadCapabilities))
+ return Result;
break;
case COMMENTS_BLOCK_ID: {
@@ -2412,7 +2462,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
if (Stream.SkipBlock() ||
ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) {
Error("malformed comments block in AST file");
- return true;
+ return Failure;
}
CommentsCursors.push_back(std::make_pair(C, &F));
break;
@@ -2421,7 +2471,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
default:
if (Stream.SkipBlock()) {
Error("malformed block record in AST file");
- return true;
+ return Failure;
}
break;
}
@@ -2442,7 +2492,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case TYPE_OFFSET: {
if (F.LocalNumTypes != 0) {
Error("duplicate TYPE_OFFSET record in AST file");
- return true;
+ return Failure;
}
F.TypeOffsets = (const uint32_t *)Blob.data();
F.LocalNumTypes = Record[0];
@@ -2466,7 +2516,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case DECL_OFFSET: {
if (F.LocalNumDecls != 0) {
Error("duplicate DECL_OFFSET record in AST file");
- return true;
+ return Failure;
}
F.DeclOffsets = (const DeclOffset *)Blob.data();
F.LocalNumDecls = Record[0];
@@ -2507,18 +2557,16 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
unsigned Idx = 0;
serialization::DeclID ID = ReadDeclID(F, Record, Idx);
ASTDeclContextNameLookupTable *Table =
- ASTDeclContextNameLookupTable::Create(
- (const unsigned char *)Blob.data() + Record[Idx++],
- (const unsigned char *)Blob.data(),
- ASTDeclContextNameLookupTrait(*this, F));
- if (ID == PREDEF_DECL_TRANSLATION_UNIT_ID) { // Is it the TU?
- DeclContext *TU = Context.getTranslationUnitDecl();
- F.DeclContextInfos[TU].NameLookupTableData = Table;
- TU->setHasExternalVisibleStorage(true);
- } else if (Decl *D = DeclsLoaded[ID - NUM_PREDEF_DECL_IDS]) {
+ ASTDeclContextNameLookupTable::Create(
+ (const unsigned char *)Blob.data() + Record[Idx++],
+ (const unsigned char *)Blob.data() + sizeof(uint32_t),
+ (const unsigned char *)Blob.data(),
+ ASTDeclContextNameLookupTrait(*this, F));
+ if (Decl *D = GetExistingDecl(ID)) {
auto *DC = cast<DeclContext>(D);
DC->getPrimaryContext()->setHasExternalVisibleStorage(true);
auto *&LookupTable = F.DeclContextInfos[DC].NameLookupTableData;
+ // FIXME: There should never be an existing lookup table.
delete LookupTable;
LookupTable = Table;
} else
@@ -2529,11 +2577,11 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case IDENTIFIER_TABLE:
F.IdentifierTableData = Blob.data();
if (Record[0]) {
- F.IdentifierLookupTable
- = ASTIdentifierLookupTable::Create(
- (const unsigned char *)F.IdentifierTableData + Record[0],
- (const unsigned char *)F.IdentifierTableData,
- ASTIdentifierLookupTrait(*this, F));
+ F.IdentifierLookupTable = ASTIdentifierLookupTable::Create(
+ (const unsigned char *)F.IdentifierTableData + Record[0],
+ (const unsigned char *)F.IdentifierTableData + sizeof(uint32_t),
+ (const unsigned char *)F.IdentifierTableData,
+ ASTIdentifierLookupTrait(*this, F));
PP.getIdentifierTable().setExternalIdentifierLookup(this);
}
@@ -2542,7 +2590,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case IDENTIFIER_OFFSET: {
if (F.LocalNumIdentifiers != 0) {
Error("duplicate IDENTIFIER_OFFSET record in AST file");
- return true;
+ return Failure;
}
F.IdentifierOffsets = (const uint32_t *)Blob.data();
F.LocalNumIdentifiers = Record[0];
@@ -2581,7 +2629,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
if (SpecialTypes.size() != Record.size()) {
Error("invalid special-types record");
- return true;
+ return Failure;
}
for (unsigned I = 0, N = Record.size(); I != N; ++I) {
@@ -2613,7 +2661,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case WEAK_UNDECLARED_IDENTIFIERS:
if (Record.size() % 4 != 0) {
Error("invalid weak identifiers record");
- return true;
+ return Failure;
}
// FIXME: Ignore weak undeclared identifiers from non-original PCH
@@ -2757,7 +2805,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
ModuleFile *OM = ModuleMgr.lookup(Name);
if (!OM) {
Error("SourceLocation remap refers to unknown module");
- return true;
+ return Failure;
}
uint32_t SLocOffset =
@@ -2806,7 +2854,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case SOURCE_MANAGER_LINE_TABLE:
if (ParseLineTable(F, Record))
- return true;
+ return Failure;
break;
case SOURCE_LOCATION_PRELOADS: {
@@ -2814,7 +2862,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
// which is based off F.SLocEntryBaseID.
if (!F.PreloadSLocEntries.empty()) {
Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file");
- return true;
+ return Failure;
}
F.PreloadSLocEntries.swap(Record);
@@ -2829,7 +2877,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case VTABLE_USES:
if (Record.size() % 3 != 0) {
Error("Invalid VTABLE_USES record");
- return true;
+ return Failure;
}
// Later tables overwrite earlier ones.
@@ -2853,12 +2901,12 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case PENDING_IMPLICIT_INSTANTIATIONS:
if (PendingInstantiations.size() % 2 != 0) {
Error("Invalid existing PendingInstantiations");
- return true;
+ return Failure;
}
if (Record.size() % 2 != 0) {
Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block");
- return true;
+ return Failure;
}
for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
@@ -2871,7 +2919,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case SEMA_DECL_REFS:
if (Record.size() != 2) {
Error("Invalid SEMA_DECL_REFS block");
- return true;
+ return Failure;
}
for (unsigned I = 0, N = Record.size(); I != N; ++I)
SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I]));
@@ -2912,19 +2960,24 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case DECL_UPDATE_OFFSETS: {
if (Record.size() % 2 != 0) {
Error("invalid DECL_UPDATE_OFFSETS block in AST file");
- return true;
+ return Failure;
+ }
+ for (unsigned I = 0, N = Record.size(); I != N; I += 2) {
+ GlobalDeclID ID = getGlobalDeclID(F, Record[I]);
+ DeclUpdateOffsets[ID].push_back(std::make_pair(&F, Record[I + 1]));
+
+ // If we've already loaded the decl, perform the updates when we finish
+ // loading this block.
+ if (Decl *D = GetExistingDecl(ID))
+ PendingUpdateRecords.push_back(std::make_pair(ID, D));
}
- // FIXME: If we've already loaded the decl, perform the updates now.
- for (unsigned I = 0, N = Record.size(); I != N; I += 2)
- DeclUpdateOffsets[getGlobalDeclID(F, Record[I])]
- .push_back(std::make_pair(&F, Record[I+1]));
break;
}
case DECL_REPLACEMENTS: {
if (Record.size() % 3 != 0) {
Error("invalid DECL_REPLACEMENTS block in AST file");
- return true;
+ return Failure;
}
for (unsigned I = 0, N = Record.size(); I != N; I += 3)
ReplacedDecls[getGlobalDeclID(F, Record[I])]
@@ -2935,7 +2988,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case OBJC_CATEGORIES_MAP: {
if (F.LocalNumObjCCategoriesInMap != 0) {
Error("duplicate OBJC_CATEGORIES_MAP record in AST file");
- return true;
+ return Failure;
}
F.LocalNumObjCCategoriesInMap = Record[0];
@@ -2950,7 +3003,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case CXX_BASE_SPECIFIER_OFFSETS: {
if (F.LocalNumCXXBaseSpecifiers != 0) {
Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file");
- return true;
+ return Failure;
}
F.LocalNumCXXBaseSpecifiers = Record[0];
@@ -3017,12 +3070,12 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case UNDEFINED_BUT_USED:
if (UndefinedButUsed.size() % 2 != 0) {
Error("Invalid existing UndefinedButUsed");
- return true;
+ return Failure;
}
if (Record.size() % 2 != 0) {
Error("invalid undefined-but-used record");
- return true;
+ return Failure;
}
for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
UndefinedButUsed.push_back(getGlobalDeclID(F, Record[I++]));
@@ -3054,7 +3107,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case LOCAL_REDECLARATIONS_MAP: {
if (F.LocalNumRedeclarationsInMap != 0) {
Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file");
- return true;
+ return Failure;
}
F.LocalNumRedeclarationsInMap = Record[0];
@@ -3075,7 +3128,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case MACRO_OFFSET: {
if (F.LocalNumMacros != 0) {
Error("duplicate MACRO_OFFSET record in AST file");
- return true;
+ return Failure;
}
F.MacroOffsets = (const uint32_t *)Blob.data();
F.LocalNumMacros = Record[0];
@@ -3302,8 +3355,8 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ModuleFile &F = *M->Mod;
// Read the AST block.
- if (ReadASTBlock(F))
- return Failure;
+ if (ASTReadResult Result = ReadASTBlock(F, ClientLoadCapabilities))
+ return Result;
// Once read, set the ModuleFile bit base offset and update the size in
// bits of all files we've seen.
@@ -3534,7 +3587,7 @@ ASTReader::ReadASTCore(StringRef FileName,
break;
case CONTROL_BLOCK_ID:
HaveReadControlBlock = true;
- switch (ReadControlBlock(F, Loaded, ClientLoadCapabilities)) {
+ switch (ReadControlBlock(F, Loaded, ImportedBy, ClientLoadCapabilities)) {
case Success:
break;
@@ -3575,11 +3628,24 @@ void ASTReader::InitializeContext() {
DeserializationListener->DeclRead(PREDEF_DECL_TRANSLATION_UNIT_ID,
Context.getTranslationUnitDecl());
- // Make sure we load the declaration update records for the translation unit,
- // if there are any.
- loadDeclUpdateRecords(PREDEF_DECL_TRANSLATION_UNIT_ID,
- Context.getTranslationUnitDecl());
-
+ // For any declarations we have already loaded, load any update records.
+ {
+ // We're not back to a consistent state until all our pending update
+ // records have been loaded. There can be interdependencies between them.
+ Deserializing SomeUpdateRecords(this);
+ ReadingKindTracker ReadingKind(Read_Decl, *this);
+
+ // Make sure we load the declaration update records for the translation
+ // unit, if there are any.
+ // FIXME: Is this necessary any more?
+ loadDeclUpdateRecords(PREDEF_DECL_TRANSLATION_UNIT_ID,
+ Context.getTranslationUnitDecl());
+
+ for (auto &Update : PendingUpdateRecords)
+ loadDeclUpdateRecords(Update.first, Update.second);
+ PendingUpdateRecords.clear();
+ }
+
// FIXME: Find a better way to deal with collisions between these
// built-in types. Right now, we just ignore the problem.
@@ -3914,6 +3980,12 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
break;
}
+ case MODULE_NAME:
+ Listener.ReadModuleName(Blob);
+ break;
+ case MODULE_MAP_FILE:
+ Listener.ReadModuleMapFile(Blob);
+ break;
case LANGUAGE_OPTIONS:
if (ParseLanguageOptions(Record, false, Listener))
return true;
@@ -3998,11 +4070,12 @@ bool ASTReader::isAcceptableASTFile(StringRef Filename,
return !readASTFileControlBlock(Filename, FileMgr, validator);
}
-bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
+ASTReader::ASTReadResult
+ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// Enter the submodule block.
if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) {
Error("malformed submodule block record in AST file");
- return true;
+ return Failure;
}
ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
@@ -4016,9 +4089,9 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case llvm::BitstreamEntry::SubBlock: // Handled for us already.
case llvm::BitstreamEntry::Error:
Error("malformed block record in AST file");
- return true;
+ return Failure;
case llvm::BitstreamEntry::EndBlock:
- return false;
+ return Success;
case llvm::BitstreamEntry::Record:
// The interesting case.
break;
@@ -4034,12 +4107,12 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_DEFINITION: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (Record.size() < 8) {
Error("malformed module definition");
- return true;
+ return Failure;
}
StringRef Name = Blob;
@@ -4055,20 +4128,26 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
bool InferExportWildcard = Record[Idx++];
bool ConfigMacrosExhaustive = Record[Idx++];
- Module *ParentModule = 0;
- if (Parent)
+ Module *ParentModule = nullptr;
+ const FileEntry *ModuleMap = nullptr;
+ if (Parent) {
ParentModule = getSubmodule(Parent);
-
+ ModuleMap = ParentModule->ModuleMap;
+ }
+
+ if (!F.ModuleMapPath.empty())
+ ModuleMap = FileMgr.getFile(F.ModuleMapPath);
+
// Retrieve this (sub)module from the module map, creating it if
// necessary.
- CurrentModule = ModMap.findOrCreateModule(Name, ParentModule,
+ CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, ModuleMap,
IsFramework,
IsExplicit).first;
SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS;
if (GlobalIndex >= SubmodulesLoaded.size() ||
SubmodulesLoaded[GlobalIndex]) {
Error("too many submodules");
- return true;
+ return Failure;
}
if (!ParentModule) {
@@ -4080,13 +4159,13 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
<< CurFile->getName()
<< F.File->getName();
}
- return true;
+ return Failure;
}
}
CurrentModule->setASTFile(F.File);
}
-
+
CurrentModule->IsFromModuleFile = true;
CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem;
CurrentModule->IsExternC = IsExternC;
@@ -4110,7 +4189,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_UMBRELLA_HEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -4120,8 +4199,9 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (!CurrentModule->getUmbrellaHeader())
ModMap.setUmbrellaHeader(CurrentModule, Umbrella);
else if (CurrentModule->getUmbrellaHeader() != Umbrella) {
- Error("mismatched umbrella headers in submodule");
- return true;
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Error("mismatched umbrella headers in submodule");
+ return OutOfDate;
}
}
break;
@@ -4130,7 +4210,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_HEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -4145,7 +4225,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_EXCLUDED_HEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -4160,7 +4240,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_PRIVATE_HEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -4175,7 +4255,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_TOPHEADER: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -4188,7 +4268,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_UMBRELLA_DIR: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -4199,8 +4279,9 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (!CurrentModule->getUmbrellaDir())
ModMap.setUmbrellaDir(CurrentModule, Umbrella);
else if (CurrentModule->getUmbrellaDir() != Umbrella) {
- Error("mismatched umbrella directories in submodule");
- return true;
+ if ((ClientLoadCapabilities & ARR_OutOfDate) == 0)
+ Error("mismatched umbrella directories in submodule");
+ return OutOfDate;
}
}
break;
@@ -4209,7 +4290,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_METADATA: {
if (!First) {
Error("submodule metadata record not at beginning of block");
- return true;
+ return Failure;
}
First = false;
@@ -4235,7 +4316,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_IMPORTS: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -4256,7 +4337,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_EXPORTS: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -4280,7 +4361,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_REQUIRES: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -4294,7 +4375,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_LINK_LIBRARY:
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -4307,7 +4388,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_CONFIG_MACRO:
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -4319,7 +4400,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
case SUBMODULE_CONFLICT: {
if (First) {
Error("missing submodule metadata record at beginning of block");
- return true;
+ return Failure;
}
if (!CurrentModule)
@@ -5234,8 +5315,14 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
QualType TST = readType(*Loc.F, Record, Idx); // probably derivable
// FIXME: ASTContext::getInjectedClassNameType is not currently suitable
// for AST reading, too much interdependencies.
- return
- QualType(new (Context, TypeAlignment) InjectedClassNameType(D, TST), 0);
+ const Type *T;
+ if (const Type *Existing = D->getTypeForDecl())
+ T = Existing;
+ else if (auto *Prev = D->getPreviousDecl())
+ T = Prev->getTypeForDecl();
+ else
+ T = new (Context, TypeAlignment) InjectedClassNameType(D, TST);
+ return QualType(T, 0);
}
case TYPE_TEMPLATE_TYPE_PARM: {
@@ -5778,11 +5865,14 @@ Decl *ASTReader::GetExternalDecl(uint32_t ID) {
return GetDecl(ID);
}
-uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Record,
- unsigned &Idx){
- if (Idx >= Record.size())
+uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M,
+ const RecordData &Record,
+ unsigned &Idx) {
+ if (Idx >= Record.size() || Record[Idx] > M.LocalNumCXXBaseSpecifiers) {
+ Error("malformed AST file: missing C++ base specifier");
return 0;
-
+ }
+
unsigned LocalID = Record[Idx++];
return getGlobalBitOffset(M, M.CXXBaseSpecifiersOffsets[LocalID - 1]);
}
@@ -5797,7 +5887,7 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
unsigned Code = Cursor.ReadCode();
unsigned RecCode = Cursor.readRecord(Code, Record);
if (RecCode != DECL_CXX_BASE_SPECIFIERS) {
- Error("Malformed AST file: missing C++ base specifiers");
+ Error("malformed AST file: missing C++ base specifiers");
return 0;
}
@@ -5840,14 +5930,14 @@ ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) {
SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) {
if (ID < NUM_PREDEF_DECL_IDS)
return SourceLocation();
-
+
unsigned Index = ID - NUM_PREDEF_DECL_IDS;
if (Index > DeclsLoaded.size()) {
Error("declaration ID out-of-range for AST file");
return SourceLocation();
}
-
+
if (Decl *D = DeclsLoaded[Index])
return D->getLocation();
@@ -5856,15 +5946,15 @@ SourceLocation ASTReader::getSourceLocationForDeclID(GlobalDeclID ID) {
return ReadSourceLocation(*Rec.F, RawLocation);
}
-Decl *ASTReader::GetDecl(DeclID ID) {
- if (ID < NUM_PREDEF_DECL_IDS) {
+Decl *ASTReader::GetExistingDecl(DeclID ID) {
+ if (ID < NUM_PREDEF_DECL_IDS) {
switch ((PredefinedDeclIDs)ID) {
case PREDEF_DECL_NULL_ID:
return 0;
-
+
case PREDEF_DECL_TRANSLATION_UNIT_ID:
return Context.getTranslationUnitDecl();
-
+
case PREDEF_DECL_OBJC_ID_ID:
return Context.getObjCIdDecl();
@@ -5873,16 +5963,16 @@ Decl *ASTReader::GetDecl(DeclID ID) {
case PREDEF_DECL_OBJC_CLASS_ID:
return Context.getObjCClassDecl();
-
+
case PREDEF_DECL_OBJC_PROTOCOL_ID:
return Context.getObjCProtocolDecl();
-
+
case PREDEF_DECL_INT_128_ID:
return Context.getInt128Decl();
case PREDEF_DECL_UNSIGNED_INT_128_ID:
return Context.getUInt128Decl();
-
+
case PREDEF_DECL_OBJC_INSTANCETYPE_ID:
return Context.getObjCInstanceTypeDecl();
@@ -5890,7 +5980,7 @@ Decl *ASTReader::GetDecl(DeclID ID) {
return Context.getBuiltinVaListDecl();
}
}
-
+
unsigned Index = ID - NUM_PREDEF_DECL_IDS;
if (Index >= DeclsLoaded.size()) {
@@ -5898,7 +5988,22 @@ Decl *ASTReader::GetDecl(DeclID ID) {
Error("declaration ID out-of-range for AST file");
return 0;
}
-
+
+ return DeclsLoaded[Index];
+}
+
+Decl *ASTReader::GetDecl(DeclID ID) {
+ if (ID < NUM_PREDEF_DECL_IDS)
+ return GetExistingDecl(ID);
+
+ unsigned Index = ID - NUM_PREDEF_DECL_IDS;
+
+ if (Index >= DeclsLoaded.size()) {
+ assert(0 && "declaration ID out-of-range for AST file");
+ Error("declaration ID out-of-range for AST file");
+ return 0;
+ }
+
if (!DeclsLoaded[Index]) {
ReadDeclRecord(ID);
if (DeserializationListener)
@@ -6204,14 +6309,19 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
Contexts.push_back(DC);
if (DC->isNamespace()) {
- MergedDeclsMap::iterator Merged
- = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
+ auto Merged = MergedDecls.find(const_cast<Decl *>(cast<Decl>(DC)));
if (Merged != MergedDecls.end()) {
for (unsigned I = 0, N = Merged->second.size(); I != N; ++I)
Contexts.push_back(cast<DeclContext>(GetDecl(Merged->second[I])));
}
}
-
+ if (isa<CXXRecordDecl>(DC)) {
+ auto Merged = MergedLookups.find(DC);
+ if (Merged != MergedLookups.end())
+ Contexts.insert(Contexts.end(), Merged->second.begin(),
+ Merged->second.end());
+ }
+
DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls);
// If we can definitively determine which module file to look into,
@@ -7754,6 +7864,19 @@ void ASTReader::ReadComments() {
}
}
+std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) {
+ // If we know the owning module, use it.
+ if (Module *M = D->getOwningModule())
+ return M->getFullModuleName();
+
+ // Otherwise, use the name of the top-level module the decl is within.
+ if (ModuleFile *M = getOwningModuleFile(D))
+ return M->ModuleName;
+
+ // Not from a module.
+ return "";
+}
+
void ASTReader::finishPendingActions() {
while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() ||
!PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() ||
@@ -7821,6 +7944,20 @@ void ASTReader::finishPendingActions() {
Info.D->setDeclContextsImpl(SemaDC, LexicalDC, getContext());
}
+ // Trigger the import of the full definition of each class that had any
+ // odr-merging problems, so we can produce better diagnostics for them.
+ for (auto &Merge : PendingOdrMergeFailures) {
+ Merge.first->buildLookup();
+ Merge.first->decls_begin();
+ Merge.first->bases_begin();
+ Merge.first->vbases_begin();
+ for (auto *RD : Merge.second) {
+ RD->decls_begin();
+ RD->bases_begin();
+ RD->vbases_begin();
+ }
+ }
+
// For each declaration from a merged context, check that the canonical
// definition of that context also contains a declaration of the same
// entity.
@@ -7859,11 +7996,11 @@ void ASTReader::finishPendingActions() {
if (!Found) {
D->setInvalidDecl();
- Module *CanonDefModule = cast<Decl>(CanonDef)->getOwningModule();
+ std::string CanonDefModule =
+ getOwningModuleNameForDiagnostic(cast<Decl>(CanonDef));
Diag(D->getLocation(), diag::err_module_odr_violation_missing_decl)
- << D << D->getOwningModule()->getFullModuleName()
- << CanonDef << !CanonDefModule
- << (CanonDefModule ? CanonDefModule->getFullModuleName() : "");
+ << D << getOwningModuleNameForDiagnostic(D)
+ << CanonDef << CanonDefModule.empty() << CanonDefModule;
if (Candidates.empty())
Diag(cast<Decl>(CanonDef)->getLocation(),
@@ -7874,6 +8011,8 @@ void ASTReader::finishPendingActions() {
diag::note_module_odr_violation_possible_decl)
<< Candidates[I];
}
+
+ DiagnosedOdrMergeFailures.insert(CanonDef);
}
}
}
@@ -7886,7 +8025,7 @@ void ASTReader::finishPendingActions() {
DEnd = PendingDefinitions.end();
D != DEnd; ++D) {
if (TagDecl *TD = dyn_cast<TagDecl>(*D)) {
- if (const TagType *TagT = dyn_cast<TagType>(TD->TypeForDecl)) {
+ if (const TagType *TagT = dyn_cast<TagType>(TD->getTypeForDecl())) {
// Make sure that the TagType points at the definition.
const_cast<TagType*>(TagT)->decl = TD;
}
@@ -7943,6 +8082,46 @@ void ASTReader::finishPendingActions() {
MD->setLazyBody(PB->second);
}
PendingBodies.clear();
+
+ // Issue any pending ODR-failure diagnostics.
+ for (auto &Merge : PendingOdrMergeFailures) {
+ if (!DiagnosedOdrMergeFailures.insert(Merge.first))
+ continue;
+
+ bool Diagnosed = false;
+ for (auto *RD : Merge.second) {
+ // Multiple different declarations got merged together; tell the user
+ // where they came from.
+ if (Merge.first != RD) {
+ // FIXME: Walk the definition, figure out what's different,
+ // and diagnose that.
+ if (!Diagnosed) {
+ std::string Module = getOwningModuleNameForDiagnostic(Merge.first);
+ Diag(Merge.first->getLocation(),
+ diag::err_module_odr_violation_different_definitions)
+ << Merge.first << Module.empty() << Module;
+ Diagnosed = true;
+ }
+
+ Diag(RD->getLocation(),
+ diag::note_module_odr_violation_different_definitions)
+ << getOwningModuleNameForDiagnostic(RD);
+ }
+ }
+
+ if (!Diagnosed) {
+ // All definitions are updates to the same declaration. This happens if a
+ // module instantiates the declaration of a class template specialization
+ // and two or more other modules instantiate its definition.
+ //
+ // FIXME: Indicate which modules had instantiations of this definition.
+ // FIXME: How can this even happen?
+ Diag(Merge.first->getLocation(),
+ diag::err_module_odr_violation_different_instantiations)
+ << Merge.first;
+ }
+ }
+ PendingOdrMergeFailures.clear();
}
void ASTReader::FinishedDeserializing() {
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 7d95072930..96253ca301 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -99,9 +99,12 @@ namespace clang {
Module *readModule(const RecordData &R, unsigned &I) {
return Reader.getSubmodule(readSubmoduleID(R, I));
}
-
+
+ void ReadCXXRecordDefinition(CXXRecordDecl *D);
void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data,
const RecordData &R, unsigned &I);
+ void MergeDefinitionData(CXXRecordDecl *D,
+ struct CXXRecordDecl::DefinitionData &NewDD);
/// \brief RAII class used to capture the first ID within a redeclaration
/// chain and to introduce it into the list of pending redeclaration chains
@@ -264,7 +267,7 @@ namespace clang {
void VisitImplicitParamDecl(ImplicitParamDecl *PD);
void VisitParmVarDecl(ParmVarDecl *PD);
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
- void VisitTemplateDecl(TemplateDecl *D);
+ DeclID VisitTemplateDecl(TemplateDecl *D);
RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitVarTemplateDecl(VarTemplateDecl *D);
@@ -285,20 +288,26 @@ namespace clang {
void VisitEmptyDecl(EmptyDecl *D);
std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
-
- template<typename T>
+
+ template<typename T>
RedeclarableResult VisitRedeclarable(Redeclarable<T> *D);
template<typename T>
- void mergeRedeclarable(Redeclarable<T> *D, RedeclarableResult &Redecl);
+ void mergeRedeclarable(Redeclarable<T> *D, RedeclarableResult &Redecl,
+ DeclID TemplatePatternID = 0);
template<typename T>
void mergeRedeclarable(Redeclarable<T> *D, T *Existing,
- RedeclarableResult &Redecl);
+ RedeclarableResult &Redecl,
+ DeclID TemplatePatternID = 0);
template<typename T>
void mergeMergeable(Mergeable<T> *D);
+ void mergeTemplatePattern(RedeclarableTemplateDecl *D,
+ RedeclarableTemplateDecl *Existing,
+ DeclID DsID);
+
// FIXME: Reorder according to DeclNodes.td?
void VisitObjCMethodDecl(ObjCMethodDecl *D);
void VisitObjCContainerDecl(ObjCContainerDecl *D);
@@ -337,7 +346,7 @@ void ASTDeclReader::Visit(Decl *D) {
}
if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) {
- // if we have a fully initialized TypeDecl, we can safely read its type now.
+ // We have a fully initialized TypeDecl. Read its type now.
TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull());
} else if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
// if we have a fully initialized TypeDecl, we can safely read its type now.
@@ -474,7 +483,8 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTagDecl(TagDecl *TD) {
} else
TD->NamedDeclOrQualifier = ReadDeclAs<NamedDecl>(Record, Idx);
- mergeRedeclarable(TD, Redecl);
+ if (!isa<CXXRecordDecl>(TD))
+ mergeRedeclarable(TD, Redecl);
return Redecl;
}
@@ -576,9 +586,10 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
switch ((FunctionDecl::TemplatedKind)Record[Idx++]) {
case FunctionDecl::TK_NonTemplate:
- mergeRedeclarable(FD, Redecl);
+ mergeRedeclarable(FD, Redecl);
break;
case FunctionDecl::TK_FunctionTemplate:
+ // Merged when we merge the template.
FD->setDescribedFunctionTemplate(ReadDeclAs<FunctionTemplateDecl>(Record,
Idx));
break;
@@ -588,6 +599,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
SourceLocation POI = ReadSourceLocation(Record, Idx);
FD->setInstantiationOfMemberFunction(Reader.getContext(), InstFD, TSK);
FD->getMemberSpecializationInfo()->setPointOfInstantiation(POI);
+ mergeRedeclarable(FD, Redecl);
break;
}
case FunctionDecl::TK_FunctionTemplateSpecialization: {
@@ -673,6 +685,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->setDependentTemplateSpecialization(Reader.getContext(),
TemplDecls, TemplArgs);
+
+ // FIXME: Merging.
break;
}
}
@@ -977,10 +991,6 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
VD->getLexicalDeclContext()->isFunctionOrMethod())
VD->setLocalExternDecl();
- // Only true variables (not parameters or implicit parameters) can be merged.
- if (VD->getKind() != Decl::ParmVar && VD->getKind() != Decl::ImplicitParam)
- mergeRedeclarable(VD, Redecl);
-
if (uint64_t Val = Record[Idx++]) {
VD->setInit(Reader.ReadExpr(F));
if (Val > 1) {
@@ -995,8 +1005,12 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
};
switch ((VarKind)Record[Idx++]) {
case VarNotTemplate:
+ // Only true variables (not parameters or implicit parameters) can be merged
+ if (VD->getKind() != Decl::ParmVar && VD->getKind() != Decl::ImplicitParam)
+ mergeRedeclarable(VD, Redecl);
break;
case VarTemplate:
+ // Merged when we merge the template.
VD->setDescribedVarTemplate(ReadDeclAs<VarTemplateDecl>(Record, Idx));
break;
case StaticDataMemberSpecialization: { // HasMemberSpecializationInfo.
@@ -1004,6 +1018,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
SourceLocation POI = ReadSourceLocation(Record, Idx);
Reader.getContext().setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI);
+ mergeRedeclarable(VD, Redecl);
break;
}
}
@@ -1199,6 +1214,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.DefaultedMoveAssignmentIsDeleted = Record[Idx++];
Data.DefaultedDestructorIsDeleted = Record[Idx++];
Data.HasTrivialSpecialMembers = Record[Idx++];
+ Data.DeclaredNonTrivialSpecialMembers = Record[Idx++];
Data.HasIrrelevantDestructor = Record[Idx++];
Data.HasConstexprNonCopyMoveConstructor = Record[Idx++];
Data.DefaultedDefaultConstructorIsConstexpr = Record[Idx++];
@@ -1258,61 +1274,168 @@ void ASTDeclReader::ReadCXXDefinitionData(
}
}
+void ASTDeclReader::MergeDefinitionData(
+ CXXRecordDecl *D, struct CXXRecordDecl::DefinitionData &MergeDD) {
+ assert(D->DefinitionData && "merging class definition into non-definition");
+ auto &DD = *D->DefinitionData;
+
+ // If the new definition has new special members, let the name lookup
+ // code know that it needs to look in the new definition too.
+ if ((MergeDD.DeclaredSpecialMembers & ~DD.DeclaredSpecialMembers) &&
+ DD.Definition != MergeDD.Definition) {
+ Reader.MergedLookups[DD.Definition].push_back(MergeDD.Definition);
+ DD.Definition->setHasExternalVisibleStorage();
+ }
+
+ // FIXME: Move this out into a .def file?
+ // FIXME: Issue a diagnostic on a mismatched MATCH_FIELD, rather than
+ // asserting; this can happen in the case of an ODR violation.
+ bool DetectedOdrViolation = false;
+#define OR_FIELD(Field) DD.Field |= MergeDD.Field;
+#define MATCH_FIELD(Field) \
+ DetectedOdrViolation |= DD.Field != MergeDD.Field; \
+ OR_FIELD(Field)
+ MATCH_FIELD(UserDeclaredConstructor)
+ MATCH_FIELD(UserDeclaredSpecialMembers)
+ MATCH_FIELD(Aggregate)
+ MATCH_FIELD(PlainOldData)
+ MATCH_FIELD(Empty)
+ MATCH_FIELD(Polymorphic)
+ MATCH_FIELD(Abstract)
+ MATCH_FIELD(IsStandardLayout)
+ MATCH_FIELD(HasNoNonEmptyBases)
+ MATCH_FIELD(HasPrivateFields)
+ MATCH_FIELD(HasProtectedFields)
+ MATCH_FIELD(HasPublicFields)
+ MATCH_FIELD(HasMutableFields)
+ MATCH_FIELD(HasVariantMembers)
+ MATCH_FIELD(HasOnlyCMembers)
+ MATCH_FIELD(HasInClassInitializer)
+ MATCH_FIELD(HasUninitializedReferenceMember)
+ MATCH_FIELD(NeedOverloadResolutionForMoveConstructor)
+ MATCH_FIELD(NeedOverloadResolutionForMoveAssignment)
+ MATCH_FIELD(NeedOverloadResolutionForDestructor)
+ MATCH_FIELD(DefaultedMoveConstructorIsDeleted)
+ MATCH_FIELD(DefaultedMoveAssignmentIsDeleted)
+ MATCH_FIELD(DefaultedDestructorIsDeleted)
+ OR_FIELD(HasTrivialSpecialMembers)
+ OR_FIELD(DeclaredNonTrivialSpecialMembers)
+ MATCH_FIELD(HasIrrelevantDestructor)
+ OR_FIELD(HasConstexprNonCopyMoveConstructor)
+ MATCH_FIELD(DefaultedDefaultConstructorIsConstexpr)
+ OR_FIELD(HasConstexprDefaultConstructor)
+ MATCH_FIELD(HasNonLiteralTypeFieldsOrBases)
+ // ComputedVisibleConversions is handled below.
+ MATCH_FIELD(UserProvidedDefaultConstructor)
+ OR_FIELD(DeclaredSpecialMembers)
+ MATCH_FIELD(ImplicitCopyConstructorHasConstParam)
+ MATCH_FIELD(ImplicitCopyAssignmentHasConstParam)
+ OR_FIELD(HasDeclaredCopyConstructorWithConstParam)
+ OR_FIELD(HasDeclaredCopyAssignmentWithConstParam)
+ MATCH_FIELD(IsLambda)
+#undef OR_FIELD
+#undef MATCH_FIELD
+
+ if (DD.NumBases != MergeDD.NumBases || DD.NumVBases != MergeDD.NumVBases)
+ DetectedOdrViolation = true;
+ // FIXME: Issue a diagnostic if the base classes don't match when we come
+ // to lazily load them.
+
+ // FIXME: Issue a diagnostic if the list of conversion functions doesn't
+ // match when we come to lazily load them.
+ if (MergeDD.ComputedVisibleConversions && !DD.ComputedVisibleConversions) {
+ DD.VisibleConversions = std::move(MergeDD.VisibleConversions);
+ DD.ComputedVisibleConversions = true;
+ }
+
+ // FIXME: Issue a diagnostic if FirstFriend doesn't match when we come to
+ // lazily load it.
+
+ if (DD.IsLambda) {
+ // FIXME: ODR-checking for merging lambdas (this happens, for instance,
+ // when they occur within the body of a function template specialization).
+ }
+
+ if (DetectedOdrViolation)
+ Reader.PendingOdrMergeFailures[DD.Definition].push_back(MergeDD.Definition);
+}
+
+void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D) {
+ struct CXXRecordDecl::DefinitionData *DD;
+ ASTContext &C = Reader.getContext();
+
+ // Determine whether this is a lambda closure type, so that we can
+ // allocate the appropriate DefinitionData structure.
+ bool IsLambda = Record[Idx++];
+ if (IsLambda)
+ DD = new (C) CXXRecordDecl::LambdaDefinitionData(D, 0, false, false,
+ LCD_None);
+ else
+ DD = new (C) struct CXXRecordDecl::DefinitionData(D);
+
+ ReadCXXDefinitionData(*DD, Record, Idx);
+
+ // If we're reading an update record, we might already have a definition for
+ // this record. If so, just merge into it.
+ if (D->DefinitionData) {
+ MergeDefinitionData(D, *DD);
+ return;
+ }
+
+ // Propagate the DefinitionData pointer to the canonical declaration, so
+ // that all other deserialized declarations will see it.
+ CXXRecordDecl *Canon = D->getCanonicalDecl();
+ if (Canon == D) {
+ D->DefinitionData = DD;
+ D->IsCompleteDefinition = true;
+ } else if (!Canon->DefinitionData) {
+ Canon->DefinitionData = D->DefinitionData = DD;
+ D->IsCompleteDefinition = true;
+
+ // Note that we have deserialized a definition. Any declarations
+ // deserialized before this one will be be given the DefinitionData
+ // pointer at the end.
+ Reader.PendingDefinitions.insert(D);
+ } else {
+ // We have already deserialized a definition of this record. This
+ // definition is no longer really a definition. Note that the pre-existing
+ // definition is the *real* definition.
+ Reader.MergedDeclContexts.insert(
+ std::make_pair(D, Canon->DefinitionData->Definition));
+ D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
+ D->IsCompleteDefinition = false;
+ MergeDefinitionData(D, *DD);
+ }
+}
+
ASTDeclReader::RedeclarableResult
ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
RedeclarableResult Redecl = VisitRecordDeclImpl(D);
ASTContext &C = Reader.getContext();
- bool WasDefinition = Record[Idx++];
- if (WasDefinition) {
- // Determine whether this is a lambda closure type, so that we can
- // allocate the appropriate DefinitionData structure.
- bool IsLambda = Record[Idx++];
- if (IsLambda)
- D->DefinitionData = new (C) CXXRecordDecl::LambdaDefinitionData(D, 0,
- false,
- false, LCD_None);
- else
- D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D);
-
- ReadCXXDefinitionData(*D->DefinitionData, Record, Idx);
-
- // Propagate the DefinitionData pointer to the canonical declaration, so
- // that all other deserialized declarations will see it.
- CXXRecordDecl *Canon = D->getCanonicalDecl();
- if (Canon == D) {
- // Nothing to do.
- } else if (!Canon->DefinitionData) {
- Canon->DefinitionData = D->DefinitionData;
-
- // Note that we have deserialized a definition. Any declarations
- // deserialized before this one will be be given the DefinitionData
- // pointer at the end.
- Reader.PendingDefinitions.insert(D);
- } else {
- // We have already deserialized a definition of this record. This
- // definition is no longer really a definition. Note that the pre-existing
- // definition is the *real* definition.
- // FIXME: Check DefinitionData for consistency with prior definition.
- Reader.MergedDeclContexts.insert(
- std::make_pair(D, D->getCanonicalDecl()->DefinitionData->Definition));
- D->IsCompleteDefinition = false;
- D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
- }
- } else {
- // Propagate DefinitionData pointer from the canonical declaration.
- D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
- }
enum CXXRecKind {
CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization
};
switch ((CXXRecKind)Record[Idx++]) {
case CXXRecNotTemplate:
+ mergeRedeclarable(D, Redecl);
+ break;
+ case CXXRecTemplate: {
+ // Merged when we merge the template.
+ ClassTemplateDecl *Template = ReadDeclAs<ClassTemplateDecl>(Record, Idx);
+ D->TemplateOrInstantiation = Template;
+ if (!Template->getTemplatedDecl()) {
+ // We've not actually loaded the ClassTemplateDecl yet, because we're
+ // currently being loaded as its pattern. Rely on it to set up our
+ // TypeForDecl (see VisitClassTemplateDecl).
+ //
+ // Beware: we do not yet know our canonical declaration, and may still
+ // get merged once the surrounding class template has got off the ground.
+ TypeIDForTypeDecl = 0;
+ }
break;
- case CXXRecTemplate:
- D->TemplateOrInstantiation = ReadDeclAs<ClassTemplateDecl>(Record, Idx);
- break;
+ }
case CXXRecMemberSpecialization: {
CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(Record, Idx);
TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
@@ -1320,10 +1443,18 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
MemberSpecializationInfo *MSI = new (C) MemberSpecializationInfo(RD, TSK);
MSI->setPointOfInstantiation(POI);
D->TemplateOrInstantiation = MSI;
+ mergeRedeclarable(D, Redecl);
break;
}
}
+ bool WasDefinition = Record[Idx++];
+ if (WasDefinition)
+ ReadCXXRecordDefinition(D);
+ else
+ // Propagate DefinitionData pointer from the canonical declaration.
+ D->DefinitionData = D->getCanonicalDecl()->DefinitionData;
+
// Lazily load the key function to avoid deserializing every method so we can
// compute it.
if (WasDefinition) {
@@ -1352,6 +1483,7 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
if (auto *CD = ReadDeclAs<CXXConstructorDecl>(Record, Idx))
D->setInheritedConstructor(CD);
D->IsExplicitSpecified = Record[Idx++];
+ // FIXME: We should defer loading this until we need the constructor's body.
std::tie(D->CtorInitializers, D->NumCtorInitializers) =
Reader.ReadCXXCtorInitializers(F, Record, Idx);
}
@@ -1409,16 +1541,19 @@ void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
D->FriendLoc = ReadSourceLocation(Record, Idx);
}
-void ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
+DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
VisitNamedDecl(D);
- NamedDecl *TemplatedDecl = ReadDeclAs<NamedDecl>(Record, Idx);
+ DeclID PatternID = ReadDeclID(Record, Idx);
+ NamedDecl *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID));
TemplateParameterList* TemplateParams
= Reader.ReadTemplateParameterList(F, Record, Idx);
D->init(TemplatedDecl, TemplateParams);
// FIXME: If this is a redeclaration of a template from another module, handle
// inheritance of default template arguments.
+
+ return PatternID;
}
ASTDeclReader::RedeclarableResult
@@ -1447,10 +1582,10 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
}
}
- VisitTemplateDecl(D);
+ DeclID PatternID = VisitTemplateDecl(D);
D->IdentifierNamespace = Record[Idx++];
- mergeRedeclarable(D, Redecl);
+ mergeRedeclarable(D, Redecl, PatternID);
// If we merged the template with a prior declaration chain, merge the common
// pointer.
@@ -1494,6 +1629,14 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
CommonPtr->InjectedClassNameType = Reader.readType(F, Record, Idx);
}
+
+ if (D->getTemplatedDecl()->TemplateOrInstantiation) {
+ // We were loaded before our templated declaration was. We've not set up
+ // its corresponding type yet (see VisitCXXRecordDeclImpl), so reconstruct
+ // it now.
+ Reader.Context.getInjectedClassNameType(
+ D->getTemplatedDecl(), D->getCommonPtr()->InjectedClassNameType);
+ }
}
/// TODO: Unify with ClassTemplateDecl version?
@@ -1589,7 +1732,7 @@ ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
if (!CanonSpec->DefinitionData) {
CanonSpec->DefinitionData = D->DefinitionData;
} else {
- // FIXME: Check DefinitionData for consistency with prior definition
+ MergeDefinitionData(CanonSpec, *D->DefinitionData);
Reader.PendingDefinitions.erase(D);
Reader.MergedDeclContexts.insert(
std::make_pair(D, CanonSpec->DefinitionData->Definition));
@@ -1844,23 +1987,54 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
/// of the same entity.
template<typename T>
void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
- RedeclarableResult &Redecl) {
+ RedeclarableResult &Redecl,
+ DeclID TemplatePatternID) {
// If modules are not available, there is no reason to perform this merge.
if (!Reader.getContext().getLangOpts().Modules)
return;
if (FindExistingResult ExistingRes = findExisting(static_cast<T*>(D)))
if (T *Existing = ExistingRes)
- mergeRedeclarable(D, Existing, Redecl);
+ mergeRedeclarable(D, Existing, Redecl, TemplatePatternID);
+}
+
+/// \brief "Cast" to type T, asserting if we don't have an implicit conversion.
+/// We use this to put code in a template that will only be valid for certain
+/// instantiations.
+template<typename T> static T assert_cast(T t) { return t; }
+template<typename T> static T assert_cast(...) {
+ llvm_unreachable("bad assert_cast");
+}
+
+/// \brief Merge together the pattern declarations from two template
+/// declarations.
+void ASTDeclReader::mergeTemplatePattern(RedeclarableTemplateDecl *D,
+ RedeclarableTemplateDecl *Existing,
+ DeclID DsID) {
+ auto *DPattern = D->getTemplatedDecl();
+ auto *ExistingPattern = Existing->getTemplatedDecl();
+ RedeclarableResult Result(Reader, DsID, DPattern->getKind());
+ if (auto *DClass = dyn_cast<CXXRecordDecl>(DPattern))
+ // FIXME: Merge definitions here, if both declarations had definitions.
+ return mergeRedeclarable(DClass, cast<TagDecl>(ExistingPattern),
+ Result);
+ if (auto *DFunction = dyn_cast<FunctionDecl>(DPattern))
+ return mergeRedeclarable(DFunction, cast<FunctionDecl>(ExistingPattern),
+ Result);
+ if (auto *DVar = dyn_cast<VarDecl>(DPattern))
+ return mergeRedeclarable(DVar, cast<VarDecl>(ExistingPattern), Result);
+ llvm_unreachable("merged an unknown kind of redeclarable template");
}
/// \brief Attempts to merge the given declaration (D) with another declaration
/// of the same entity.
template<typename T>
-void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D, T *Existing,
- RedeclarableResult &Redecl) {
+void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase, T *Existing,
+ RedeclarableResult &Redecl,
+ DeclID TemplatePatternID) {
+ T *D = static_cast<T*>(DBase);
T *ExistingCanon = Existing->getCanonicalDecl();
- T *DCanon = static_cast<T*>(D)->getCanonicalDecl();
+ T *DCanon = D->getCanonicalDecl();
if (ExistingCanon != DCanon) {
// Have our redeclaration link point back at the canonical declaration
// of the existing declaration, so that this declaration has the
@@ -1868,11 +2042,15 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D, T *Existing,
D->RedeclLink = Redeclarable<T>::PreviousDeclLink(ExistingCanon);
// When we merge a namespace, update its pointer to the first namespace.
- if (NamespaceDecl *Namespace
- = dyn_cast<NamespaceDecl>(static_cast<T*>(D))) {
+ if (auto *Namespace = dyn_cast<NamespaceDecl>(D))
Namespace->AnonOrFirstNamespaceAndInline.setPointer(
- static_cast<NamespaceDecl *>(static_cast<void*>(ExistingCanon)));
- }
+ assert_cast<NamespaceDecl*>(ExistingCanon));
+
+ // When we merge a template, merge its pattern.
+ if (auto *DTemplate = dyn_cast<RedeclarableTemplateDecl>(D))
+ mergeTemplatePattern(
+ DTemplate, assert_cast<RedeclarableTemplateDecl*>(ExistingCanon),
+ TemplatePatternID);
// Don't introduce DCanon into the set of pending declaration chains.
Redecl.suppress();
@@ -1889,7 +2067,7 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D, T *Existing,
// If this declaration was the canonical declaration, make a note of
// that. We accept the linear algorithm here because the number of
// unique canonical declarations of an entity should always be tiny.
- if (DCanon == static_cast<T*>(D)) {
+ if (DCanon == D) {
SmallVectorImpl<DeclID> &Merged = Reader.MergedDecls[ExistingCanon];
if (std::find(Merged.begin(), Merged.end(), Redecl.getFirstID())
== Merged.end())
@@ -2149,9 +2327,7 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
// Fields with the same name and the same type match.
if (FieldDecl *FDX = dyn_cast<FieldDecl>(X)) {
FieldDecl *FDY = cast<FieldDecl>(Y);
- // FIXME: Diagnose if the types don't match. More generally, diagnose if we
- // get a declaration in a class definition that isn't in the canonical class
- // definition.
+ // FIXME: Diagnose if the types don't match.
// FIXME: Also check the bitwidth is odr-equivalent, if any.
return X->getASTContext().hasSameType(FDX->getType(), FDY->getType());
}
@@ -2258,6 +2434,9 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
// If this declaration is from a merged context, make a note that we need to
// check that the canonical definition of that context contains the decl.
+ //
+ // FIXME: We should do something similar if we merge two definitions of the
+ // same template specialization into the same CXXRecordDecl.
if (Reader.MergedDeclContexts.count(D->getLexicalDeclContext()))
Reader.PendingOdrMergeChecks.push_back(D);
@@ -2922,12 +3101,14 @@ void ASTReader::loadObjCCategories(serialization::GlobalDeclID ID,
void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
const RecordData &Record) {
- unsigned Idx = 0;
while (Idx < Record.size()) {
switch ((DeclUpdateKind)Record[Idx++]) {
- case UPD_CXX_ADDED_IMPLICIT_MEMBER:
- cast<CXXRecordDecl>(D)->addedMember(Reader.ReadDecl(ModuleFile, Record, Idx));
+ case UPD_CXX_ADDED_IMPLICIT_MEMBER: {
+ Decl *MD = Reader.ReadDecl(ModuleFile, Record, Idx);
+ assert(MD && "couldn't read decl from update record");
+ cast<CXXRecordDecl>(D)->addedMember(MD);
break;
+ }
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
// It will be added to the template's specializations set when loaded.
@@ -2957,9 +3138,11 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
case UPD_CXX_INSTANTIATED_FUNCTION_DEFINITION: {
FunctionDecl *FD = cast<FunctionDecl>(D);
- if (Reader.PendingBodies[FD])
+ if (Reader.PendingBodies[FD]) {
// FIXME: Maybe check for ODR violations.
- break;
+ // It's safe to stop now because this update record is always last.
+ return;
+ }
if (Record[Idx++])
FD->setImplicitlyInline();
@@ -2974,6 +3157,45 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
break;
}
+ case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: {
+ auto *RD = cast<CXXRecordDecl>(D);
+ bool HadDefinition = RD->getDefinition();
+ ReadCXXRecordDefinition(RD);
+ // Visible update is handled separately.
+ uint64_t LexicalOffset = Record[Idx++];
+ if (!HadDefinition && LexicalOffset) {
+ RD->setHasExternalLexicalStorage(true);
+ Reader.ReadDeclContextStorage(ModuleFile, ModuleFile.DeclsCursor,
+ std::make_pair(LexicalOffset, 0),
+ ModuleFile.DeclContextInfos[RD]);
+ }
+
+ auto TSK = (TemplateSpecializationKind)Record[Idx++];
+ SourceLocation POI = Reader.ReadSourceLocation(ModuleFile, Record, Idx);
+ if (MemberSpecializationInfo *MSInfo =
+ RD->getMemberSpecializationInfo()) {
+ MSInfo->setTemplateSpecializationKind(TSK);
+ MSInfo->setPointOfInstantiation(POI);
+ } else {
+ ClassTemplateSpecializationDecl *Spec =
+ cast<ClassTemplateSpecializationDecl>(RD);
+ Spec->setTemplateSpecializationKind(TSK);
+ Spec->setPointOfInstantiation(POI);
+ }
+
+ RD->setTagKind((TagTypeKind)Record[Idx++]);
+ RD->setLocation(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
+ RD->setLocStart(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
+ RD->setRBraceLoc(Reader.ReadSourceLocation(ModuleFile, Record, Idx));
+
+ if (Record[Idx++]) {
+ AttrVec Attrs;
+ Reader.ReadAttributes(F, Attrs, Record, Idx);
+ D->setAttrsImpl(Attrs, Reader.getContext());
+ }
+ break;
+ }
+
case UPD_CXX_RESOLVED_EXCEPTION_SPEC: {
auto *FD = cast<FunctionDecl>(D);
auto *FPT = FD->getType()->castAs<FunctionProtoType>();
diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h
index 9149b18480..fdcecca4aa 100644
--- a/lib/Serialization/ASTReaderInternals.h
+++ b/lib/Serialization/ASTReaderInternals.h
@@ -14,9 +14,9 @@
#define LLVM_CLANG_SERIALIZATION_ASTREADER_INTERNALS_H
#include "clang/AST/DeclarationName.h"
-#include "clang/Basic/OnDiskHashTable.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/OnDiskHashTable.h"
#include <sys/stat.h>
#include <utility>
@@ -46,6 +46,8 @@ public:
/// particular lookup t
typedef llvm::support::ulittle32_t LE32DeclID;
typedef std::pair<LE32DeclID *, LE32DeclID *> data_type;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
/// \brief Special internal key for declaration names.
/// The hash table creates keys for comparison; we do not create
@@ -67,7 +69,7 @@ public:
return a.Kind == b.Kind && a.Data == b.Data;
}
- unsigned ComputeHash(const DeclNameKey &Key) const;
+ hash_value_type ComputeHash(const DeclNameKey &Key) const;
internal_key_type GetInternalKey(const external_key_type& Name) const;
static std::pair<unsigned, unsigned>
@@ -92,13 +94,14 @@ class ASTIdentifierLookupTraitBase {
public:
typedef StringRef external_key_type;
typedef StringRef internal_key_type;
-
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
static bool EqualKey(const internal_key_type& a, const internal_key_type& b) {
return a == b;
}
- static unsigned ComputeHash(const internal_key_type& a);
+ static hash_value_type ComputeHash(const internal_key_type& a);
static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char*& d);
@@ -140,7 +143,7 @@ public:
/// \brief The on-disk hash table used to contain information about
/// all of the identifiers in the program.
-typedef OnDiskChainedHashTable<ASTIdentifierLookupTrait>
+typedef llvm::OnDiskIterableChainedHashTable<ASTIdentifierLookupTrait>
ASTIdentifierLookupTable;
/// \brief Class that performs lookup for a selector's entries in the global
@@ -160,6 +163,8 @@ public:
typedef Selector external_key_type;
typedef external_key_type internal_key_type;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
ASTSelectorLookupTrait(ASTReader &Reader, ModuleFile &F)
: Reader(Reader), F(F) { }
@@ -169,7 +174,7 @@ public:
return a == b;
}
- static unsigned ComputeHash(Selector Sel);
+ static hash_value_type ComputeHash(Selector Sel);
static const internal_key_type&
GetInternalKey(const external_key_type& x) { return x; }
@@ -182,7 +187,7 @@ public:
};
/// \brief The on-disk hash table used for the global method pool.
-typedef OnDiskChainedHashTable<ASTSelectorLookupTrait>
+typedef llvm::OnDiskChainedHashTable<ASTSelectorLookupTrait>
ASTSelectorLookupTable;
/// \brief Trait class used to search the on-disk hash table containing all of
@@ -211,12 +216,14 @@ public:
typedef const internal_key_type &internal_key_ref;
typedef HeaderFileInfo data_type;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
HeaderFileInfoTrait(ASTReader &Reader, ModuleFile &M, HeaderSearch *HS,
const char *FrameworkStrings)
: Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings) { }
- static unsigned ComputeHash(internal_key_ref ikey);
+ static hash_value_type ComputeHash(internal_key_ref ikey);
static internal_key_type GetInternalKey(const FileEntry *FE);
bool EqualKey(internal_key_ref a, internal_key_ref b);
@@ -229,7 +236,7 @@ public:
};
/// \brief The on-disk hash table used for known header files.
-typedef OnDiskChainedHashTable<HeaderFileInfoTrait>
+typedef llvm::OnDiskChainedHashTable<HeaderFileInfoTrait>
HeaderFileInfoLookupTable;
} // end namespace clang::serialization::reader
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 9a201d0f69..da652ff8e3 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -1692,6 +1692,9 @@ OMPClause *OMPClauseReader::readClause() {
case OMPC_shared:
C = OMPSharedClause::CreateEmpty(Context, Record[Idx++]);
break;
+ case OMPC_linear:
+ C = OMPLinearClause::CreateEmpty(Context, Record[Idx++]);
+ break;
case OMPC_copyin:
C = OMPCopyinClause::CreateEmpty(Context, Record[Idx++]);
break;
@@ -1755,6 +1758,18 @@ void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) {
C->setVarRefs(Vars);
}
+void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) {
+ C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+ C->setColonLoc(Reader->ReadSourceLocation(Record, Idx));
+ unsigned NumVars = C->varlist_size();
+ SmallVector<Expr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Vars);
+ C->setStep(Reader->Reader.ReadSubExpr());
+}
+
void OMPClauseReader::VisitOMPCopyinClause(OMPCopyinClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index e4b5cdb968..7402961ae8 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -25,7 +25,6 @@
#include "clang/AST/TypeLocVisitor.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
-#include "clang/Basic/OnDiskHashTable.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/TargetInfo.h"
@@ -49,6 +48,7 @@
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/Path.h"
#include <algorithm>
#include <cstdio>
@@ -798,6 +798,8 @@ void ASTWriter::WriteBlockInfoBlock() {
// Control Block.
BLOCK(CONTROL_BLOCK);
RECORD(METADATA);
+ RECORD(MODULE_NAME);
+ RECORD(MODULE_MAP_FILE);
RECORD(IMPORTS);
RECORD(LANGUAGE_OPTIONS);
RECORD(TARGET_OPTIONS);
@@ -1050,6 +1052,32 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record,
getClangFullRepositoryVersion());
+ // Module name
+ if (WritingModule) {
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(MODULE_NAME));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
+ RecordData Record;
+ Record.push_back(MODULE_NAME);
+ Stream.EmitRecordWithBlob(AbbrevCode, Record, WritingModule->Name);
+ }
+
+ // Module map file
+ if (WritingModule) {
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(MODULE_MAP_FILE));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Filename
+ unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev);
+
+ assert(WritingModule->ModuleMap && "missing module map");
+ SmallString<128> ModuleMap(WritingModule->ModuleMap->getName());
+ llvm::sys::fs::make_absolute(ModuleMap);
+ RecordData Record;
+ Record.push_back(MODULE_MAP_FILE);
+ Stream.EmitRecordWithBlob(AbbrevCode, Record, ModuleMap.str());
+ }
+
// Imports
if (Chain) {
serialization::ModuleManager &Mgr = Chain->getModuleManager();
@@ -1065,7 +1093,6 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
AddSourceLocation((*M)->ImportLoc, Record);
Record.push_back((*M)->File->getSize());
Record.push_back((*M)->File->getModificationTime());
- // FIXME: This writes the absolute path for AST files we depend on.
const std::string &FileName = (*M)->FileName;
Record.push_back(FileName.size());
Record.append(FileName.begin(), FileName.end());
@@ -1455,8 +1482,10 @@ namespace {
typedef HeaderFileInfo data_type;
typedef const data_type &data_type_ref;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
- static unsigned ComputeHash(key_type_ref key) {
+ static hash_value_type ComputeHash(key_type_ref key) {
// The hash is based only on size/time of the file, so that the reader can
// match even when symlinking or excess path elements ("foo/../", "../")
// change the form of the name. However, complete path is still the key.
@@ -1548,7 +1577,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
FilesByUID.resize(HS.header_file_size());
HeaderFileInfoTrait GeneratorTrait(*this, HS);
- OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
+ llvm::OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
SmallVector<const char *, 4> SavedStrings;
unsigned NumHeaderSearchEntries = 0;
for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) {
@@ -1828,8 +1857,10 @@ public:
typedef Data data_type;
typedef const data_type &data_type_ref;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
- static unsigned ComputeHash(IdentID IdID) {
+ static hash_value_type ComputeHash(IdentID IdID) {
return llvm::hash_value(IdID);
}
@@ -1921,7 +1952,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
llvm::array_pod_sort(MacroDirectives.begin(), MacroDirectives.end(),
&compareMacroDirectives);
- OnDiskChainedHashTableGenerator<ASTMacroTableTrait> Generator;
+ llvm::OnDiskChainedHashTableGenerator<ASTMacroTableTrait> Generator;
// Emit the macro directives as a list and associate the offset with the
// identifier they belong to.
@@ -2003,6 +2034,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
AddSourceLocation(MI->getDefinitionLoc(), Record);
AddSourceLocation(MI->getDefinitionEndLoc(), Record);
Record.push_back(MI->isUsed());
+ Record.push_back(MI->isUsedForHeaderGuard());
unsigned Code;
if (MI->isObjectLike()) {
Code = PP_MACRO_OBJECT_LIKE;
@@ -2710,9 +2742,12 @@ public:
};
typedef const data_type& data_type_ref;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
explicit ASTMethodPoolTrait(ASTWriter &Writer) : Writer(Writer) { }
- static unsigned ComputeHash(Selector Sel) {
+ static hash_value_type ComputeHash(Selector Sel) {
return serialization::ComputeHash(Sel);
}
@@ -2806,7 +2841,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) {
unsigned NumTableEntries = 0;
// Create and write out the blob that contains selectors and the method pool.
{
- OnDiskChainedHashTableGenerator<ASTMethodPoolTrait> Generator;
+ llvm::OnDiskChainedHashTableGenerator<ASTMethodPoolTrait> Generator;
ASTMethodPoolTrait Trait(*this);
// Create the on-disk hash table representation. We walk through every
@@ -3062,11 +3097,14 @@ public:
typedef IdentID data_type;
typedef data_type data_type_ref;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
ASTIdentifierTableTrait(ASTWriter &Writer, Preprocessor &PP,
IdentifierResolver &IdResolver, bool IsModule)
: Writer(Writer), PP(PP), IdResolver(IdResolver), IsModule(IsModule) { }
- static unsigned ComputeHash(const IdentifierInfo* II) {
+ static hash_value_type ComputeHash(const IdentifierInfo* II) {
return llvm::HashString(II->getName());
}
@@ -3232,7 +3270,7 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
// Create and write out the blob that contains the identifier
// strings.
{
- OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator;
+ llvm::OnDiskChainedHashTableGenerator<ASTIdentifierTableTrait> Generator;
ASTIdentifierTableTrait Trait(*this, PP, IdResolver, IsModule);
// Look for any identifiers that were named while processing the
@@ -3321,9 +3359,12 @@ public:
typedef DeclContext::lookup_result data_type;
typedef const data_type& data_type_ref;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
+
explicit ASTDeclContextNameLookupTrait(ASTWriter &Writer) : Writer(Writer) { }
- unsigned ComputeHash(DeclarationName Name) {
+ hash_value_type ComputeHash(DeclarationName Name) {
llvm::FoldingSetNodeID ID;
ID.AddInteger(Name.getNameKind());
@@ -3430,13 +3471,57 @@ public:
};
} // end anonymous namespace
+template<typename Visitor>
+static void visitLocalLookupResults(const DeclContext *ConstDC,
+ bool NeedToReconcileExternalVisibleStorage,
+ Visitor AddLookupResult) {
+ // FIXME: We need to build the lookups table, which is logically const.
+ DeclContext *DC = const_cast<DeclContext*>(ConstDC);
+ assert(DC == DC->getPrimaryContext() && "only primary DC has lookup table");
+
+ SmallVector<DeclarationName, 16> ExternalNames;
+ for (auto &Lookup : *DC->buildLookup()) {
+ if (Lookup.second.hasExternalDecls() ||
+ NeedToReconcileExternalVisibleStorage) {
+ // We don't know for sure what declarations are found by this name,
+ // because the external source might have a different set from the set
+ // that are in the lookup map, and we can't update it now without
+ // risking invalidating our lookup iterator. So add it to a queue to
+ // deal with later.
+ ExternalNames.push_back(Lookup.first);
+ continue;
+ }
+
+ AddLookupResult(Lookup.first, Lookup.second.getLookupResult());
+ }
+
+ // Add the names we needed to defer. Note, this shouldn't add any new decls
+ // to the list we need to serialize: any new declarations we find here should
+ // be imported from an external source.
+ // FIXME: What if the external source isn't an ASTReader?
+ for (const auto &Name : ExternalNames)
+ AddLookupResult(Name, DC->lookup(Name));
+}
+
+void ASTWriter::AddUpdatedDeclContext(const DeclContext *DC) {
+ if (UpdatedDeclContexts.insert(DC) && WritingAST) {
+ // Ensure we emit all the visible declarations.
+ visitLocalLookupResults(DC, DC->NeedToReconcileExternalVisibleStorage,
+ [&](DeclarationName Name,
+ DeclContext::lookup_const_result Result) {
+ for (auto *Decl : Result)
+ GetDeclRef(Decl);
+ });
+ }
+}
+
uint32_t
ASTWriter::GenerateNameLookupTable(const DeclContext *DC,
llvm::SmallVectorImpl<char> &LookupTable) {
assert(!DC->LookupPtr.getInt() && "must call buildLookups first");
- assert(DC == DC->getPrimaryContext() && "only primary DC has lookup table");
- OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait> Generator;
+ llvm::OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait>
+ Generator;
ASTDeclContextNameLookupTrait Trait(*this);
// Create the on-disk hash table representation.
@@ -3445,8 +3530,9 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *DC,
SmallVector<NamedDecl *, 8> ConstructorDecls;
SmallVector<NamedDecl *, 4> ConversionDecls;
- auto AddLookupResult = [&](DeclarationName Name,
- DeclContext::lookup_result Result) {
+ visitLocalLookupResults(DC, DC->NeedToReconcileExternalVisibleStorage,
+ [&](DeclarationName Name,
+ DeclContext::lookup_result Result) {
if (Result.empty())
return;
@@ -3462,41 +3548,19 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *DC,
ConstructorName = Name;
ConstructorDecls.append(Result.begin(), Result.end());
return;
+
case DeclarationName::CXXConversionFunctionName:
if (!ConversionName)
ConversionName = Name;
ConversionDecls.append(Result.begin(), Result.end());
return;
+
default:
break;
}
Generator.insert(Name, Result, Trait);
- };
-
- SmallVector<DeclarationName, 16> ExternalNames;
- for (auto &Lookup : *DC->getLookupPtr()) {
- if (Lookup.second.hasExternalDecls() ||
- DC->NeedToReconcileExternalVisibleStorage) {
- // We don't know for sure what declarations are found by this name,
- // because the external source might have a different set from the set
- // that are in the lookup map, and we can't update it now without
- // risking invalidating our lookup iterator. So add it to a queue to
- // deal with later.
- ExternalNames.push_back(Lookup.first);
- continue;
- }
-
- AddLookupResult(Lookup.first, Lookup.second.getLookupResult());
- }
-
- // Add the names we needed to defer. Note, this shouldn't add any new decls
- // to the list we need to serialize: any new declarations we find here should
- // be imported from an external source.
- // FIXME: What if the external source isn't an ASTReader?
- for (const auto &Name : ExternalNames)
- // FIXME: const_cast since OnDiskHashTable wants a non-const lookup result.
- AddLookupResult(Name, const_cast<DeclContext*>(DC)->lookup(Name));
+ });
// Add the constructors.
if (!ConstructorDecls.empty()) {
@@ -3505,6 +3569,7 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *DC,
ConstructorDecls.end()),
Trait);
}
+
// Add the conversion functions.
if (!ConversionDecls.empty()) {
Generator.insert(ConversionName,
@@ -3750,7 +3815,7 @@ void ASTWriter::WriteMergedDecls() {
IEnd = Chain->MergedDecls.end();
I != IEnd; ++I) {
DeclID CanonID = I->first->isFromASTFile()? I->first->getGlobalID()
- : getDeclID(I->first);
+ : GetDeclRef(I->first);
assert(CanonID && "Merged declaration not known?");
Record.push_back(CanonID);
@@ -3987,6 +4052,15 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
}
}
+ // If we saw any DeclContext updates before we started writing the AST file,
+ // make sure all visible decls in those DeclContexts are written out.
+ if (!UpdatedDeclContexts.empty()) {
+ auto OldUpdatedDeclContexts = std::move(UpdatedDeclContexts);
+ UpdatedDeclContexts.clear();
+ for (auto *DC : OldUpdatedDeclContexts)
+ AddUpdatedDeclContext(DC);
+ }
+
// Build a record containing all of the tentative definitions in this file, in
// TentativeDefinitions order. Generally, this record will be empty for
// headers.
@@ -4346,11 +4420,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Stream.EmitRecord(UNDEFINED_BUT_USED, UndefinedButUsed);
// Write the visible updates to DeclContexts.
- for (llvm::SmallPtrSet<const DeclContext *, 16>::iterator
- I = UpdatedDeclContexts.begin(),
- E = UpdatedDeclContexts.end();
- I != E; ++I)
- WriteDeclContextVisibleUpdate(*I);
+ for (auto *DC : UpdatedDeclContexts)
+ WriteDeclContextVisibleUpdate(DC);
if (!WritingModule) {
// Write the submodules that were imported, if any.
@@ -4417,9 +4488,6 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
if (isRewritten(D))
continue; // The decl will be written completely,no need to store updates.
- OffsetsRecord.push_back(GetDeclRef(D));
- OffsetsRecord.push_back(Stream.GetCurrentBitNo());
-
bool HasUpdatedBody = false;
RecordData Record;
for (auto &Update : DeclUpdate.second) {
@@ -4430,6 +4498,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
case UPD_CXX_ADDED_IMPLICIT_MEMBER:
case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION:
case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE:
+ assert(Update.getDecl() && "no decl to add?");
Record.push_back(GetDeclRef(Update.getDecl()));
break;
@@ -4444,6 +4513,39 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
HasUpdatedBody = true;
break;
+ case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: {
+ auto *RD = cast<CXXRecordDecl>(D);
+ AddUpdatedDeclContext(RD->getPrimaryContext());
+ AddCXXDefinitionData(RD, Record);
+ Record.push_back(WriteDeclContextLexicalBlock(
+ *Context, const_cast<CXXRecordDecl *>(RD)));
+
+ // This state is sometimes updated by template instantiation, when we
+ // switch from the specialization referring to the template declaration
+ // to it referring to the template definition.
+ if (auto *MSInfo = RD->getMemberSpecializationInfo()) {
+ Record.push_back(MSInfo->getTemplateSpecializationKind());
+ AddSourceLocation(MSInfo->getPointOfInstantiation(), Record);
+ } else {
+ auto *Spec = cast<ClassTemplateSpecializationDecl>(RD);
+ Record.push_back(Spec->getTemplateSpecializationKind());
+ AddSourceLocation(Spec->getPointOfInstantiation(), Record);
+ }
+ Record.push_back(RD->getTagKind());
+ AddSourceLocation(RD->getLocation(), Record);
+ AddSourceLocation(RD->getLocStart(), Record);
+ AddSourceLocation(RD->getRBraceLoc(), Record);
+
+ // Instantiation may change attributes; write them all out afresh.
+ Record.push_back(D->hasAttrs());
+ if (Record.back())
+ WriteAttributes(ArrayRef<const Attr*>(D->getAttrs().begin(),
+ D->getAttrs().size()), Record);
+
+ // FIXME: Ensure we don't get here for explicit instantiations.
+ break;
+ }
+
case UPD_CXX_RESOLVED_EXCEPTION_SPEC:
addExceptionSpec(
*this,
@@ -4473,10 +4575,16 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
AddFunctionDefinition(Def, Record);
}
+ OffsetsRecord.push_back(GetDeclRef(D));
+ OffsetsRecord.push_back(Stream.GetCurrentBitNo());
+
Stream.EmitRecord(DECL_UPDATES, Record);
// Flush any statements that were written as part of this update record.
FlushStmts();
+
+ // Flush C++ base specifiers, if there are any.
+ FlushCXXBaseSpecifiers();
}
}
@@ -5220,6 +5328,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.DefaultedMoveAssignmentIsDeleted);
Record.push_back(Data.DefaultedDestructorIsDeleted);
Record.push_back(Data.HasTrivialSpecialMembers);
+ Record.push_back(Data.DeclaredNonTrivialSpecialMembers);
Record.push_back(Data.HasIrrelevantDestructor);
Record.push_back(Data.HasConstexprNonCopyMoveConstructor);
Record.push_back(Data.DefaultedDefaultConstructorIsConstexpr);
@@ -5362,7 +5471,10 @@ void ASTWriter::CompletedTagDefinition(const TagDecl *D) {
// A forward reference was mutated into a definition. Rewrite it.
// FIXME: This happens during template instantiation, should we
// have created a new definition decl instead ?
- RewriteDecl(RD);
+ assert(isTemplateInstantiation(RD->getTemplateSpecializationKind()) &&
+ "completed a tag from another module but not by instantiation?");
+ DeclUpdates[RD].push_back(
+ DeclUpdate(UPD_CXX_INSTANTIATED_CLASS_DEFINITION));
}
}
}
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 14304ab6e1..6841a9224a 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -984,9 +984,6 @@ void ASTDeclWriter::VisitUnresolvedUsingTypenameDecl(
void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
VisitRecordDecl(D);
- Record.push_back(D->isThisDeclarationADefinition());
- if (D->isThisDeclarationADefinition())
- Writer.AddCXXDefinitionData(D, Record);
enum {
CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization
@@ -1004,6 +1001,10 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
Record.push_back(CXXRecNotTemplate);
}
+ Record.push_back(D->isThisDeclarationADefinition());
+ if (D->isThisDeclarationADefinition())
+ Writer.AddCXXDefinitionData(D, Record);
+
// Store (what we currently believe to be) the key function to avoid
// deserializing every method so we can compute it.
if (D->IsCompleteDefinition)
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index dd44a695a2..958620636e 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -1698,29 +1698,38 @@ void OMPClauseWriter::VisitOMPDefaultClause(OMPDefaultClause *C) {
void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
- for (auto *I : C->varlists())
- Writer->Writer.AddStmt(I);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
}
void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
- for (auto *I : C->varlists())
- Writer->Writer.AddStmt(I);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
}
void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
- for (auto *I : C->varlists())
- Writer->Writer.AddStmt(I);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+}
+
+void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) {
+ Record.push_back(C->varlist_size());
+ Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
+ Writer->Writer.AddSourceLocation(C->getColonLoc(), Record);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
+ Writer->Writer.AddStmt(C->getStep());
}
void OMPClauseWriter::VisitOMPCopyinClause(OMPCopyinClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
- for (auto *I : C->varlists())
- Writer->Writer.AddStmt(I);
+ for (auto *VE : C->varlists())
+ Writer->Writer.AddStmt(VE);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Serialization/GlobalModuleIndex.cpp b/lib/Serialization/GlobalModuleIndex.cpp
index 14b149f078..04e4fb2c02 100644
--- a/lib/Serialization/GlobalModuleIndex.cpp
+++ b/lib/Serialization/GlobalModuleIndex.cpp
@@ -13,7 +13,7 @@
#include "ASTReaderInternals.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Lex/HeaderSearch.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/Module.h"
@@ -26,6 +26,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/LockFileManager.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/Path.h"
#include <cstdio>
using namespace clang;
@@ -71,12 +72,14 @@ public:
typedef StringRef external_key_type;
typedef StringRef internal_key_type;
typedef SmallVector<unsigned, 2> data_type;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
static bool EqualKey(const internal_key_type& a, const internal_key_type& b) {
return a == b;
}
- static unsigned ComputeHash(const internal_key_type& a) {
+ static hash_value_type ComputeHash(const internal_key_type& a) {
return llvm::HashString(a);
}
@@ -114,7 +117,8 @@ public:
}
};
-typedef OnDiskChainedHashTable<IdentifierIndexReaderTrait> IdentifierIndexTable;
+typedef llvm::OnDiskIterableChainedHashTable<IdentifierIndexReaderTrait>
+ IdentifierIndexTable;
}
@@ -202,7 +206,12 @@ GlobalModuleIndex::GlobalModuleIndex(llvm::MemoryBuffer *Buffer,
assert(Idx == Record.size() && "More module info?");
// Record this module as an unresolved module.
- UnresolvedModules[llvm::sys::path::stem(Modules[ID].FileName)] = ID;
+ // FIXME: this doesn't work correctly for module names containing path
+ // separators.
+ StringRef ModuleName = llvm::sys::path::stem(Modules[ID].FileName);
+ // Remove the -<hash of ModuleMapPath>
+ ModuleName = ModuleName.rsplit('-').first;
+ UnresolvedModules[ModuleName] = ID;
break;
}
@@ -210,16 +219,18 @@ GlobalModuleIndex::GlobalModuleIndex(llvm::MemoryBuffer *Buffer,
// Wire up the identifier index.
if (Record[0]) {
IdentifierIndex = IdentifierIndexTable::Create(
- (const unsigned char *)Blob.data() + Record[0],
- (const unsigned char *)Blob.data(),
- IdentifierIndexReaderTrait());
+ (const unsigned char *)Blob.data() + Record[0],
+ (const unsigned char *)Blob.data() + sizeof(uint32_t),
+ (const unsigned char *)Blob.data(), IdentifierIndexReaderTrait());
}
break;
}
}
}
-GlobalModuleIndex::~GlobalModuleIndex() { }
+GlobalModuleIndex::~GlobalModuleIndex() {
+ delete static_cast<IdentifierIndexTable *>(IdentifierIndex);
+}
std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode>
GlobalModuleIndex::readIndex(StringRef Path) {
@@ -307,7 +318,7 @@ bool GlobalModuleIndex::lookupIdentifier(StringRef Name, HitSet &Hits) {
bool GlobalModuleIndex::loadedModuleFile(ModuleFile *File) {
// Look for the module in the global module index based on the module name.
- StringRef Name = llvm::sys::path::stem(File->FileName);
+ StringRef Name = File->ModuleName;
llvm::StringMap<unsigned>::iterator Known = UnresolvedModules.find(Name);
if (Known == UnresolvedModules.end()) {
return true;
@@ -342,6 +353,19 @@ void GlobalModuleIndex::printStats() {
std::fprintf(stderr, "\n");
}
+void GlobalModuleIndex::dump() {
+ llvm::errs() << "*** Global Module Index Dump:\n";
+ llvm::errs() << "Module files:\n";
+ for (auto &MI : Modules) {
+ llvm::errs() << "** " << MI.FileName << "\n";
+ if (MI.File)
+ MI.File->dump();
+ else
+ llvm::errs() << "\n";
+ }
+ llvm::errs() << "\n";
+}
+
//----------------------------------------------------------------------------//
// Global module index writer.
//----------------------------------------------------------------------------//
@@ -591,11 +615,12 @@ bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
// Handle the identifier table
if (State == ASTBlock && Code == IDENTIFIER_TABLE && Record[0] > 0) {
- typedef OnDiskChainedHashTable<InterestingASTIdentifierLookupTrait>
- InterestingIdentifierTable;
+ typedef llvm::OnDiskIterableChainedHashTable<
+ InterestingASTIdentifierLookupTrait> InterestingIdentifierTable;
std::unique_ptr<InterestingIdentifierTable> Table(
InterestingIdentifierTable::Create(
(const unsigned char *)Blob.data() + Record[0],
+ (const unsigned char *)Blob.data() + sizeof(uint32_t),
(const unsigned char *)Blob.data()));
for (InterestingIdentifierTable::data_iterator D = Table->data_begin(),
DEnd = Table->data_end();
@@ -624,8 +649,10 @@ public:
typedef StringRef key_type_ref;
typedef SmallVector<unsigned, 2> data_type;
typedef const SmallVector<unsigned, 2> &data_type_ref;
+ typedef unsigned hash_value_type;
+ typedef unsigned offset_type;
- static unsigned ComputeHash(key_type_ref Key) {
+ static hash_value_type ComputeHash(key_type_ref Key) {
return llvm::HashString(Key);
}
@@ -696,7 +723,7 @@ void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
// Write the identifier -> module file mapping.
{
- OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator;
+ llvm::OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator;
IdentifierIndexWriterTrait Trait;
// Populate the hash table.
diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp
index 3513eba860..c36d902deb 100644
--- a/lib/Serialization/ModuleManager.cpp
+++ b/lib/Serialization/ModuleManager.cpp
@@ -11,6 +11,7 @@
// modules for the ASTReader.
//
//===----------------------------------------------------------------------===//
+#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/ModuleMap.h"
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/ModuleManager.h"
@@ -155,7 +156,7 @@ void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last,
FileMgr.invalidateCache((*victim)->File);
if (modMap) {
- StringRef ModuleName = llvm::sys::path::stem((*victim)->FileName);
+ StringRef ModuleName = (*victim)->ModuleName;
if (Module *mod = modMap->findModule(ModuleName)) {
mod->setASTFile(0);
}
@@ -429,7 +430,7 @@ namespace llvm {
}
std::string getNodeLabel(ModuleFile *M, const ModuleManager&) {
- return llvm::sys::path::stem(M->FileName);
+ return M->ModuleName;
}
};
}
diff --git a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
index 3becdca97d..97887dcd53 100644
--- a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
@@ -8,8 +8,6 @@
//===----------------------------------------------------------------------===//
// This file reports various statistics about analyzer visitation.
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "StatsChecker"
-
#include "ClangSACheckers.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/SourceManager.h"
@@ -26,6 +24,8 @@
using namespace clang;
using namespace ento;
+#define DEBUG_TYPE "StatsChecker"
+
STATISTIC(NumBlocks,
"The # of blocks in top level functions");
STATISTIC(NumBlocksUnreachable,
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 4b2ccd43aa..44aa43f998 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "SelectorExtras.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
@@ -97,6 +98,18 @@ namespace {
check::PostStmt<ObjCArrayLiteral> > {
mutable std::unique_ptr<APIMisuse> BT;
+ mutable llvm::SmallDenseMap<Selector, unsigned, 16> StringSelectors;
+ mutable Selector ArrayWithObjectSel;
+ mutable Selector AddObjectSel;
+ mutable Selector InsertObjectAtIndexSel;
+ mutable Selector ReplaceObjectAtIndexWithObjectSel;
+ mutable Selector SetObjectAtIndexedSubscriptSel;
+ mutable Selector ArrayByAddingObjectSel;
+ mutable Selector DictionaryWithObjectForKeySel;
+ mutable Selector SetObjectForKeySel;
+ mutable Selector SetObjectForKeyedSubscriptSel;
+ mutable Selector RemoveObjectForKeySel;
+
void warnIfNilExpr(const Expr *E,
const char *Msg,
CheckerContext &C) const;
@@ -214,50 +227,62 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (Class == FC_NSString) {
Selector S = msg.getSelector();
-
+
if (S.isUnarySelector())
return;
-
- // FIXME: This is going to be really slow doing these checks with
- // lexical comparisons.
-
- std::string NameStr = S.getAsString();
- StringRef Name(NameStr);
- assert(!Name.empty());
-
- // FIXME: Checking for initWithFormat: will not work in most cases
- // yet because [NSString alloc] returns id, not NSString*. We will
- // need support for tracking expected-type information in the analyzer
- // to find these errors.
- if (Name == "caseInsensitiveCompare:" ||
- Name == "compare:" ||
- Name == "compare:options:" ||
- Name == "compare:options:range:" ||
- Name == "compare:options:range:locale:" ||
- Name == "componentsSeparatedByCharactersInSet:" ||
- Name == "initWithFormat:") {
- Arg = 0;
+
+ if (StringSelectors.empty()) {
+ ASTContext &Ctx = C.getASTContext();
+ Selector Sels[] = {
+ getKeywordSelector(Ctx, "caseInsensitiveCompare", nullptr),
+ getKeywordSelector(Ctx, "compare", nullptr),
+ getKeywordSelector(Ctx, "compare", "options", nullptr),
+ getKeywordSelector(Ctx, "compare", "options", "range", nullptr),
+ getKeywordSelector(Ctx, "compare", "options", "range", "locale",
+ nullptr),
+ getKeywordSelector(Ctx, "componentsSeparatedByCharactersInSet",
+ nullptr),
+ getKeywordSelector(Ctx, "initWithFormat",
+ nullptr),
+ getKeywordSelector(Ctx, "localizedCaseInsensitiveCompare", nullptr),
+ getKeywordSelector(Ctx, "localizedCompare", nullptr),
+ getKeywordSelector(Ctx, "localizedStandardCompare", nullptr),
+ };
+ for (Selector KnownSel : Sels)
+ StringSelectors[KnownSel] = 0;
}
+ auto I = StringSelectors.find(S);
+ if (I == StringSelectors.end())
+ return;
+ Arg = I->second;
} else if (Class == FC_NSArray) {
Selector S = msg.getSelector();
if (S.isUnarySelector())
return;
- if (S.getNameForSlot(0).equals("addObject")) {
- Arg = 0;
- } else if (S.getNameForSlot(0).equals("insertObject") &&
- S.getNameForSlot(1).equals("atIndex")) {
+ if (ArrayWithObjectSel.isNull()) {
+ ASTContext &Ctx = C.getASTContext();
+ ArrayWithObjectSel = getKeywordSelector(Ctx, "arrayWithObject", nullptr);
+ AddObjectSel = getKeywordSelector(Ctx, "addObject", nullptr);
+ InsertObjectAtIndexSel =
+ getKeywordSelector(Ctx, "insertObject", "atIndex", nullptr);
+ ReplaceObjectAtIndexWithObjectSel =
+ getKeywordSelector(Ctx, "replaceObjectAtIndex", "withObject", nullptr);
+ SetObjectAtIndexedSubscriptSel =
+ getKeywordSelector(Ctx, "setObject", "atIndexedSubscript", nullptr);
+ ArrayByAddingObjectSel =
+ getKeywordSelector(Ctx, "arrayByAddingObject", nullptr);
+ }
+
+ if (S == ArrayWithObjectSel || S == AddObjectSel ||
+ S == InsertObjectAtIndexSel || S == ArrayByAddingObjectSel) {
Arg = 0;
- } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") &&
- S.getNameForSlot(1).equals("withObject")) {
- Arg = 1;
- } else if (S.getNameForSlot(0).equals("setObject") &&
- S.getNameForSlot(1).equals("atIndexedSubscript")) {
+ } else if (S == SetObjectAtIndexedSubscriptSel) {
Arg = 0;
CanBeSubscript = true;
- } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
- Arg = 0;
+ } else if (S == ReplaceObjectAtIndexWithObjectSel) {
+ Arg = 1;
}
} else if (Class == FC_NSDictionary) {
Selector S = msg.getSelector();
@@ -265,20 +290,26 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (S.isUnarySelector())
return;
- if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
- S.getNameForSlot(1).equals("forKey")) {
- Arg = 0;
- warnIfNilArg(C, msg, /* Arg */1, Class);
- } else if (S.getNameForSlot(0).equals("setObject") &&
- S.getNameForSlot(1).equals("forKey")) {
+ if (DictionaryWithObjectForKeySel.isNull()) {
+ ASTContext &Ctx = C.getASTContext();
+ DictionaryWithObjectForKeySel =
+ getKeywordSelector(Ctx, "dictionaryWithObject", "forKey", nullptr);
+ SetObjectForKeySel =
+ getKeywordSelector(Ctx, "setObject", "forKey", nullptr);
+ SetObjectForKeyedSubscriptSel =
+ getKeywordSelector(Ctx, "setObject", "forKeyedSubscript", nullptr);
+ RemoveObjectForKeySel =
+ getKeywordSelector(Ctx, "removeObjectForKey", nullptr);
+ }
+
+ if (S == DictionaryWithObjectForKeySel || S == SetObjectForKeySel) {
Arg = 0;
warnIfNilArg(C, msg, /* Arg */1, Class);
- } else if (S.getNameForSlot(0).equals("setObject") &&
- S.getNameForSlot(1).equals("forKeyedSubscript")) {
+ } else if (S == SetObjectForKeyedSubscriptSel) {
CanBeSubscript = true;
Arg = 0;
warnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
- } else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
+ } else if (S == RemoveObjectForKeySel) {
Arg = 0;
}
}
@@ -286,7 +317,6 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
// If argument is '0', report a warning.
if ((Arg != InvalidArgIndex))
warnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
-
}
void NilArgChecker::checkPostStmt(const ObjCArrayLiteral *AL,
diff --git a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index 0e9cbba350..ba82d1d1d4 100644
--- a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "SelectorExtras.h"
#include "clang/AST/Attr.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
@@ -28,6 +29,8 @@ namespace {
class NoReturnFunctionChecker : public Checker< check::PostCall,
check::PostObjCMessage > {
+ mutable Selector HandleFailureInFunctionSel;
+ mutable Selector HandleFailureInMethodSel;
public:
void checkPostCall(const CallEvent &CE, CheckerContext &C) const;
void checkPostObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
@@ -81,24 +84,6 @@ void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE,
C.generateSink();
}
-static bool END_WITH_NULL isMultiArgSelector(const Selector *Sel, ...) {
- va_list argp;
- va_start(argp, Sel);
-
- unsigned Slot = 0;
- const char *Arg;
- while ((Arg = va_arg(argp, const char *))) {
- if (!Sel->getNameForSlot(Slot).equals(Arg))
- break; // still need to va_end!
- ++Slot;
- }
-
- va_end(argp);
-
- // We only succeeded if we made it to the end of the argument list.
- return (Arg == NULL);
-}
-
void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
CheckerContext &C) const {
// Check if the method is annotated with analyzer_noreturn.
@@ -135,13 +120,17 @@ void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
default:
return;
case 4:
- if (!isMultiArgSelector(&Sel, "handleFailureInFunction", "file",
- "lineNumber", "description", NULL))
+ lazyInitKeywordSelector(HandleFailureInFunctionSel, C.getASTContext(),
+ "handleFailureInFunction", "file", "lineNumber",
+ "description", nullptr);
+ if (Sel != HandleFailureInFunctionSel)
return;
break;
case 5:
- if (!isMultiArgSelector(&Sel, "handleFailureInMethod", "object", "file",
- "lineNumber", "description", NULL))
+ lazyInitKeywordSelector(HandleFailureInMethodSel, C.getASTContext(),
+ "handleFailureInMethod", "object", "file",
+ "lineNumber", "description", nullptr);
+ if (Sel != HandleFailureInMethodSel)
return;
break;
}
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 9ac993160a..d312b0199a 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -14,6 +14,7 @@
#include "ClangSACheckers.h"
#include "AllocationDiagnostics.h"
+#include "SelectorExtras.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -675,18 +676,9 @@ private:
ObjCMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
- Selector generateSelector(va_list argp) {
- SmallVector<IdentifierInfo*, 10> II;
-
- while (const char* s = va_arg(argp, const char*))
- II.push_back(&Ctx.Idents.get(s));
-
- return Ctx.Selectors.getSelector(II.size(), &II[0]);
- }
-
- void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy& Summaries,
- const RetainSummary * Summ, va_list argp) {
- Selector S = generateSelector(argp);
+ void addMethodSummary(IdentifierInfo *ClsII, ObjCMethodSummariesTy &Summaries,
+ const RetainSummary *Summ, va_list argp) {
+ Selector S = getKeywordSelector(Ctx, argp);
Summaries[ObjCSummaryKey(ClsII, S)] = Summ;
}
diff --git a/lib/StaticAnalyzer/Checkers/SelectorExtras.h b/lib/StaticAnalyzer/Checkers/SelectorExtras.h
new file mode 100644
index 0000000000..48d96eb422
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/SelectorExtras.h
@@ -0,0 +1,68 @@
+//=== SelectorExtras.h - Helpers for checkers using selectors -----*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SA_CHECKERS_SELECTOREXTRAS
+#define LLVM_CLANG_SA_CHECKERS_SELECTOREXTRAS
+
+#include "clang/AST/ASTContext.h"
+#include <cstdarg>
+
+namespace clang {
+namespace ento {
+
+static inline Selector getKeywordSelectorImpl(ASTContext &Ctx,
+ const char *First,
+ va_list argp) {
+ SmallVector<IdentifierInfo*, 10> II;
+ II.push_back(&Ctx.Idents.get(First));
+
+ while (const char *s = va_arg(argp, const char *))
+ II.push_back(&Ctx.Idents.get(s));
+
+ return Ctx.Selectors.getSelector(II.size(), &II[0]);
+}
+
+static inline Selector getKeywordSelector(ASTContext &Ctx, va_list argp) {
+ const char *First = va_arg(argp, const char *);
+ assert(First && "keyword selectors must have at least one argument");
+ return getKeywordSelectorImpl(Ctx, First, argp);
+}
+
+END_WITH_NULL
+static inline Selector getKeywordSelector(ASTContext &Ctx,
+ const char *First, ...) {
+ va_list argp;
+ va_start(argp, First);
+ Selector result = getKeywordSelectorImpl(Ctx, First, argp);
+ va_end(argp);
+ return result;
+}
+
+END_WITH_NULL
+static inline void lazyInitKeywordSelector(Selector &Sel, ASTContext &Ctx,
+ const char *First, ...) {
+ if (!Sel.isNull())
+ return;
+ va_list argp;
+ va_start(argp, First);
+ Sel = getKeywordSelectorImpl(Ctx, First, argp);
+ va_end(argp);
+}
+
+static inline void lazyInitNullarySelector(Selector &Sel, ASTContext &Ctx,
+ const char *Name) {
+ if (!Sel.isNull())
+ return;
+ Sel = GetNullarySelector(Name, Ctx);
+}
+
+} // end namespace ento
+} // end namespace clang
+
+#endif
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index a08a2269c9..6569141b51 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -12,8 +12,6 @@
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "BugReporter"
-
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
@@ -40,6 +38,8 @@
using namespace clang;
using namespace ento;
+#define DEBUG_TYPE "BugReporter"
+
STATISTIC(MaxBugClassSize,
"The maximum number of bug reports in the same equivalence class");
STATISTIC(MaxValidBugClassSize,
@@ -3149,21 +3149,21 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD,
// Generate the very last diagnostic piece - the piece is visible before
// the trace is expanded.
- PathDiagnosticPiece *LastPiece = 0;
+ std::unique_ptr<PathDiagnosticPiece> LastPiece;
for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end();
I != E; ++I) {
if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) {
assert (!LastPiece &&
"There can only be one final piece in a diagnostic.");
- LastPiece = Piece;
+ LastPiece.reset(Piece);
}
}
if (ActiveScheme != PathDiagnosticConsumer::None) {
if (!LastPiece)
- LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R);
+ LastPiece.reset(BugReporterVisitor::getDefaultEndPath(PDB, N, *R));
assert(LastPiece);
- PD.setEndOfPath(LastPiece);
+ PD.setEndOfPath(LastPiece.release());
}
// Make sure we get a clean location context map so we don't
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 897164b608..edba501e6e 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -12,8 +12,6 @@
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "CoreEngine"
-
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
#include "clang/AST/Expr.h"
#include "clang/AST/StmtCXX.h"
@@ -26,6 +24,8 @@
using namespace clang;
using namespace ento;
+#define DEBUG_TYPE "CoreEngine"
+
STATISTIC(NumSteps,
"The # of steps executed.");
STATISTIC(NumReachedMaxSteps,
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index e7f49b279c..fd77e710b8 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -13,8 +13,6 @@
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "ExprEngine"
-
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "PrettyStackTraceLocationContext.h"
#include "clang/AST/CharUnits.h"
@@ -40,6 +38,8 @@ using namespace clang;
using namespace ento;
using llvm::APSInt;
+#define DEBUG_TYPE "ExprEngine"
+
STATISTIC(NumRemoveDeadBindings,
"The # of times RemoveDeadBindings is called");
STATISTIC(NumMaxBlockCountReached,
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 52fe156e35..e1eb728147 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -113,8 +113,16 @@ static const MemRegion *getRegionForConstructedObject(
// See if we're constructing an existing region by looking at the next
// element in the CFG.
const CFGBlock *B = CurrBldrCtx.getBlock();
- if (CurrStmtIdx + 1 < B->size()) {
- CFGElement Next = (*B)[CurrStmtIdx+1];
+ unsigned int NextStmtIdx = CurrStmtIdx + 1;
+ if (NextStmtIdx < B->size()) {
+ CFGElement Next = (*B)[NextStmtIdx];
+
+ // Is this a destructor? If so, we might be in the middle of an assignment
+ // to a local or member: look ahead one more element to see what we find.
+ while (Next.getAs<CFGImplicitDtor>() && NextStmtIdx + 1 < B->size()) {
+ ++NextStmtIdx;
+ Next = (*B)[NextStmtIdx];
+ }
// Is this a constructor for a local variable?
if (Optional<CFGStmt> StmtElem = Next.getAs<CFGStmt>()) {
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 72af75dba7..bffae0037c 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -11,8 +11,6 @@
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "ExprEngine"
-
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "PrettyStackTraceLocationContext.h"
#include "clang/AST/CXXInheritance.h"
@@ -28,6 +26,8 @@
using namespace clang;
using namespace ento;
+#define DEBUG_TYPE "ExprEngine"
+
STATISTIC(NumOfDynamicDispatchPathSplits,
"The # of times we split the path due to imprecise dynamic dispatch info");
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 563924d46e..fcea997b83 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -11,8 +11,6 @@
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "AnalysisConsumer"
-
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DataRecursiveASTVisitor.h"
@@ -51,6 +49,8 @@ using namespace clang;
using namespace ento;
using llvm::SmallPtrSet;
+#define DEBUG_TYPE "AnalysisConsumer"
+
static ExplodedNode::Auditor* CreateUbiViz();
STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");
@@ -307,7 +307,7 @@ public:
/// analyzed. This allows to redefine the default inlining policies when
/// analyzing a given function.
ExprEngine::InliningModes
- getInliningModeForFunction(const Decl *D, SetOfConstDecls Visited);
+ getInliningModeForFunction(const Decl *D, const SetOfConstDecls &Visited);
/// \brief Build the call graph for all the top level decls of this TU and
/// use it to define the order in which the functions should be visited.
@@ -414,8 +414,8 @@ void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {
}
static bool shouldSkipFunction(const Decl *D,
- SetOfConstDecls Visited,
- SetOfConstDecls VisitedAsTopLevel) {
+ const SetOfConstDecls &Visited,
+ const SetOfConstDecls &VisitedAsTopLevel) {
if (VisitedAsTopLevel.count(D))
return true;
@@ -435,7 +435,7 @@ static bool shouldSkipFunction(const Decl *D,
ExprEngine::InliningModes
AnalysisConsumer::getInliningModeForFunction(const Decl *D,
- SetOfConstDecls Visited) {
+ const SetOfConstDecls &Visited) {
// We want to reanalyze all ObjC methods as top level to report Retain
// Count naming convention errors more aggressively. But we should tune down
// inlining when reanalyzing an already inlined function.
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index 7425e3b4e8..5f4c46d6ef 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -38,6 +38,8 @@
# include <unistd.h>
#endif
+#define DEBUG_TYPE "clang-tooling"
+
namespace clang {
namespace tooling {
@@ -369,44 +371,46 @@ int ClangTool::run(ToolAction *Action) {
namespace {
class ASTBuilderAction : public ToolAction {
- std::vector<ASTUnit *> &ASTs;
+ std::vector<std::unique_ptr<ASTUnit>> &ASTs;
public:
- ASTBuilderAction(std::vector<ASTUnit *> &ASTs) : ASTs(ASTs) {}
+ ASTBuilderAction(std::vector<std::unique_ptr<ASTUnit>> &ASTs) : ASTs(ASTs) {}
bool runInvocation(CompilerInvocation *Invocation, FileManager *Files,
DiagnosticConsumer *DiagConsumer) override {
// FIXME: This should use the provided FileManager.
- ASTUnit *AST = ASTUnit::LoadFromCompilerInvocation(
+ std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation(
Invocation, CompilerInstance::createDiagnostics(
&Invocation->getDiagnosticOpts(), DiagConsumer,
/*ShouldOwnClient=*/false));
if (!AST)
return false;
- ASTs.push_back(AST);
+ ASTs.push_back(std::move(AST));
return true;
}
};
}
-int ClangTool::buildASTs(std::vector<ASTUnit *> &ASTs) {
+int ClangTool::buildASTs(std::vector<std::unique_ptr<ASTUnit>> &ASTs) {
ASTBuilderAction Action(ASTs);
return run(&Action);
}
-ASTUnit *buildASTFromCode(const Twine &Code, const Twine &FileName) {
+std::unique_ptr<ASTUnit> buildASTFromCode(const Twine &Code,
+ const Twine &FileName) {
return buildASTFromCodeWithArgs(Code, std::vector<std::string>(), FileName);
}
-ASTUnit *buildASTFromCodeWithArgs(const Twine &Code,
- const std::vector<std::string> &Args,
- const Twine &FileName) {
+std::unique_ptr<ASTUnit>
+buildASTFromCodeWithArgs(const Twine &Code,
+ const std::vector<std::string> &Args,
+ const Twine &FileName) {
SmallString<16> FileNameStorage;
StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage);
- std::vector<ASTUnit *> ASTs;
+ std::vector<std::unique_ptr<ASTUnit>> ASTs;
ASTBuilderAction Action(ASTs);
ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), &Action, 0);
@@ -417,7 +421,7 @@ ASTUnit *buildASTFromCodeWithArgs(const Twine &Code,
return 0;
assert(ASTs.size() == 1);
- return ASTs[0];
+ return std::move(ASTs[0]);
}
} // end namespace tooling
diff --git a/test/Analysis/NSContainers.m b/test/Analysis/NSContainers.m
index 3d3603acb3..4b34926456 100644
--- a/test/Analysis/NSContainers.m
+++ b/test/Analysis/NSContainers.m
@@ -284,3 +284,11 @@ void testLiteralsNonNil() {
clang_analyzer_eval(!!@{}); // expected-warning{{TRUE}}
}
+@interface NSMutableArray (MySafeAdd)
+- (void)addObject:(id)obj safe:(BOOL)safe;
+@end
+
+void testArrayCategory(NSMutableArray *arr) {
+ [arr addObject:0 safe:1]; // no-warning
+}
+
diff --git a/test/Analysis/dtor.cpp b/test/Analysis/dtor.cpp
index dbb950eda0..8d6e30a6c2 100644
--- a/test/Analysis/dtor.cpp
+++ b/test/Analysis/dtor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors,cfg-temporary-dtors=true -Wno-null-dereference -verify %s
void clang_analyzer_eval(bool);
void clang_analyzer_checkInlined(bool);
@@ -432,6 +432,12 @@ namespace LifetimeExtension {
return false;
}
+ bool testMultipleTemporariesCustomDestructor() {
+ if (CheckCustomDestructor c = (CheckCustomDestructor(), CheckCustomDestructor()))
+ return true;
+ return false;
+ }
+
class VirtualDtorBase {
public:
int value;
@@ -477,8 +483,7 @@ namespace NoReturn {
void g2(int *x) {
if (! x) NR();
- // FIXME: this shouldn't cause a warning.
- *x = 47; // expected-warning{{Dereference of null pointer}}
+ *x = 47; // no warning
}
}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 209154003a..970c7b96b3 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -39,7 +39,7 @@ set(CLANG_TEST_PARAMS
if( NOT CLANG_BUILT_STANDALONE )
list(APPEND CLANG_TEST_DEPS
llvm-config
- llc opt FileCheck count not llvm-symbolizer
+ llc opt FileCheck count not llvm-symbolizer llvm-profdata
)
endif()
diff --git a/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp
index 41ff3e2823..1d04d7d2a7 100644
--- a/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/p1-0x.cpp
@@ -65,8 +65,8 @@ namespace inline_namespaces {
template<> void ft<int>() {}
template void ft<char>(); // expected-error {{undefined}}
- template<typename T> int mt<T*>; // expected-warning {{extension}}
- template<> int mt<int>; // expected-warning {{extension}}
+ template<typename T> int mt<T*>;
+ template<> int mt<int>;
template int mt<int*>;
template int mt<char>; // expected-error {{undefined}}
@@ -92,8 +92,8 @@ namespace inline_namespaces {
template<> void N::gt<int>() {}
template void N::gt<char>(); // expected-error {{undefined}}
- template<typename T> int N::nt<T*>; // expected-warning {{extension}}
- template<> int N::nt<int>; // expected-warning {{extension}}
+ template<typename T> int N::nt<T*>;
+ template<> int N::nt<int>;
template int N::nt<int*>;
template int N::nt<char>; // expected-error {{undefined}}
diff --git a/test/CXX/drs/dr2xx.cpp b/test/CXX/drs/dr2xx.cpp
index 19cb122aa6..692ed1d1af 100644
--- a/test/CXX/drs/dr2xx.cpp
+++ b/test/CXX/drs/dr2xx.cpp
@@ -686,6 +686,8 @@ namespace dr259 { // dr259: yes c++11
#endif
}
+// FIXME: When dr260 is resolved, also add tests for DR507.
+
namespace dr261 { // dr261: no
#pragma clang diagnostic push
#pragma clang diagnostic warning "-Wused-but-marked-unused"
diff --git a/test/CXX/drs/dr5xx.cpp b/test/CXX/drs/dr5xx.cpp
index fa8d568237..09b28690fd 100644
--- a/test/CXX/drs/dr5xx.cpp
+++ b/test/CXX/drs/dr5xx.cpp
@@ -14,4 +14,183 @@ namespace dr500 { // dr500: dup 372
class D : public A::B {};
}
-// expected-no-diagnostics
+namespace dr501 { // dr501: yes
+ struct A {
+ friend void f() {}
+ void g() {
+ void (*p)() = &f; // expected-error {{undeclared identifier}}
+ }
+ };
+}
+
+namespace dr502 { // dr502: yes
+ struct Q {};
+ template<typename T> struct A {
+ enum E { e = 1 };
+ void q1() { f(e); }
+ void q2() { Q arr[sizeof(E)]; f(arr); }
+ void q3() { Q arr[e]; f(arr); }
+ void sanity() { Q arr[1]; f(arr); } // expected-error {{undeclared identifier 'f'}}
+ };
+ int f(A<int>::E);
+ template<int N> int f(Q (&)[N]);
+ template struct A<int>;
+}
+
+namespace dr505 { // dr505: yes
+ const char *exts = "\e\(\{\[\%"; // expected-error 5{{use of non-standard escape}}
+ const char *unknown = "\Q"; // expected-error {{unknown escape sequence}}
+}
+
+namespace dr506 { // dr506: yes
+ struct NonPod { ~NonPod(); };
+ void f(...);
+ void g(NonPod np) { f(np); } // expected-error {{cannot pass}}
+}
+
+// FIXME: Add tests here once DR260 is resolved.
+// dr507: dup 260
+
+// dr508: na
+// dr509: na
+// dr510: na
+
+namespace dr512 { // dr512: yes
+ struct A {
+ A(int);
+ };
+ union U { A a; };
+#if __cplusplus < 201103L
+ // expected-error@-2 {{has a non-trivial constructor}}
+ // expected-note@-6 {{no default constructor}}
+ // expected-note@-6 {{suppressed by user-declared constructor}}
+#endif
+}
+
+// dr513: na
+
+namespace dr514 { // dr514: yes
+ namespace A { extern int x, y; }
+ int A::x = y;
+}
+
+namespace dr515 { // dr515: sup 1017
+ // FIXME: dr1017 reverses the wording of dr515, but the current draft has
+ // dr515's wording, with a different fix for dr1017.
+
+ struct X { int n; };
+ template<typename T> struct Y : T {
+ int f() { return X::n; }
+ };
+ int k = Y<X>().f();
+
+ struct A { int a; };
+ struct B { void f() { int k = sizeof(A::a); } };
+#if __cplusplus < 201103L
+ // expected-error@-2 {{invalid use of non-static data member}}
+#endif
+}
+
+// dr516: na
+
+namespace dr517 { // dr517: no
+ // This is NDR, but we should diagnose it anyway.
+ template<typename T> struct S {};
+ template<typename T> int v = 0; // expected-error 0-1{{extension}}
+
+ template struct S<int*>;
+ template int v<int*>;
+
+ S<char&> s;
+ int k = v<char&>;
+
+ // FIXME: These are both ill-formed.
+ template<typename T> struct S<T*> {};
+ template<typename T> int v<T*> = 0; // expected-error 0-1{{extension}}
+
+ // FIXME: These are both ill-formed.
+ template<typename T> struct S<T&> {};
+ template<typename T> int v<T&> = 0; // expected-error 0-1{{extension}}
+}
+
+namespace dr518 { // dr518: yes c++11
+ enum E { e, };
+#if __cplusplus < 201103L
+ // expected-error@-2 {{C++11 extension}}
+#endif
+}
+
+namespace dr519 { // dr519: yes
+// FIXME: Add a codegen test.
+#if __cplusplus >= 201103L
+#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
+ int test[fold((int*)(void*)0) ? -1 : 1];
+#undef fold
+#endif
+}
+
+// dr520: na
+
+// dr521: no
+// FIXME: The wording here is broken. It's not reasonable to expect a
+// diagnostic here. Once the relevant DR gets a number, mark this as a dup.
+
+namespace dr522 { // dr522: yes
+ struct S {};
+ template<typename T> void b1(volatile T &);
+ template<typename T> void b2(volatile T * const *);
+ template<typename T> void b2(volatile T * const S::*);
+ template<typename T> void b2(volatile T * const S::* const *);
+ // FIXME: This diagnostic isn't very good. The problem is not substitution failure.
+ template<typename T> void b2a(volatile T *S::* const *); // expected-note {{substitution failure}}
+
+ template<typename T> struct Base {};
+ struct Derived : Base<int> {};
+ template<typename T> void b3(Base<T>);
+ template<typename T> void b3(Base<T> *);
+
+ void test(int n, const int cn, int **p, int *S::*pm) {
+ int *a[3], *S::*am[3];
+ const Derived cd = Derived();
+ Derived d[3];
+
+ b1(n);
+ b1(cn);
+ b2(p);
+ b2(pm);
+ b2(a);
+ b2(am);
+ b2a(am); // expected-error {{no matching function}}
+ b3(d);
+ b3(cd);
+ }
+}
+
+namespace dr524 { // dr524: yes
+ template<typename T> void f(T a, T b) { operator+(a, b); } // expected-error {{call}}
+
+ struct S {};
+ void operator+(S, S);
+ template void f(S, S);
+
+ namespace N { struct S {}; }
+ void operator+(N::S, N::S); // expected-note {{should be declared}}
+ template void f(N::S, N::S); // expected-note {{instantiation}}
+}
+
+namespace dr525 { // dr525: yes
+ namespace before {
+ // Note, the example was correct prior to the change; instantiation is
+ // required for cases like this:
+ template <class T> struct D { operator T*(); };
+ void g(D<double> ppp) {
+ delete ppp;
+ }
+ }
+ namespace after {
+ template <class T> struct D { typename T::error e; }; // expected-error {{prior to '::'}}
+ void g(D<double> *ppp) {
+ delete ppp; // expected-note {{instantiation of}}
+ }
+ }
+}
diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp
index 84688278f0..bcf45a0c05 100644
--- a/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/test/CXX/expr/expr.const/p2-0x.cpp
@@ -202,7 +202,9 @@ namespace UndefinedBehavior {
static_assert((A*)nb == 0, "");
static_assert((B*)na == 0, "");
constexpr const int &nf = nb->n; // expected-error {{constant expression}} expected-note {{cannot access field of null pointer}}
- constexpr const int &np = (*(int(*)[4])nullptr)[2]; // expected-error {{constant expression}} expected-note {{cannot access array element of null pointer}}
+ constexpr const int *np1 = (int*)nullptr + 0; // ok
+ constexpr const int *np2 = &(*(int(*)[4])nullptr)[0]; // ok
+ constexpr const int *np3 = &(*(int(*)[4])nullptr)[2]; // expected-error {{constant expression}} expected-note {{cannot perform pointer arithmetic on null pointer}}
struct C {
constexpr int f() const { return 0; }
diff --git a/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp b/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp
index 35f8808fff..d88d5beb4e 100644
--- a/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp
+++ b/test/CXX/over/over.match/over.match.funcs/over.match.oper/p3.cpp
@@ -1,5 +1,27 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-// expected-no-diagnostics
+
+namespace bullet2 {
+
+// For non-member candidates, if no operand has a class type, only those
+// non-member functions that have a matching enumeration parameter are
+// candidates.
+
+struct B { template<typename T> B(T); };
+int operator~(B);
+template<typename T> int operator%(B, T);
+enum class E { e };
+
+template<typename T> int f(T t) { return ~t; } // expected-error {{invalid argument type}}
+template<typename T, typename U> int f(T t, U u) { return t % u; } // expected-error {{invalid operands to}}
+
+int b1 = ~E::e; // expected-error {{invalid argument type}}
+int b2 = f(E::e); // expected-note {{in instantiation of}}
+int b3 = f(0, E::e);
+int b4 = f(E::e, 0); // expected-note {{in instantiation of}}
+
+}
+
+namespace bullet3 {
// This is specifically testing the bullet:
// "do not have the same parameter-type-list as any non-template
@@ -26,4 +48,6 @@ extern bool test2;
extern decltype(a <= a) test2;
extern A test3;
-extern decltype(a <= b) test3; \ No newline at end of file
+extern decltype(a <= b) test3;
+
+}
diff --git a/test/CodeGen/aarch64-inline-asm.c b/test/CodeGen/aarch64-inline-asm.c
index ca39c6e7ff..8dd2e34f59 100644
--- a/test/CodeGen/aarch64-inline-asm.c
+++ b/test/CodeGen/aarch64-inline-asm.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
// The only part clang really deals with is the lvalue/rvalue
// distinction on constraints. It's sufficient to emit llvm and make
diff --git a/test/CodeGen/aarch64-neon-2velem.c b/test/CodeGen/aarch64-neon-2velem.c
index 19c9b16adc..c00c8bb40f 100644
--- a/test/CodeGen/aarch64-neon-2velem.c
+++ b/test/CodeGen/aarch64-neon-2velem.c
@@ -4,7 +4,7 @@
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -S -O3 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu -S -O3 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -S -O3 -o - %s | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-3v.c b/test/CodeGen/aarch64-neon-3v.c
index 5251690c18..5c51c09605 100644
--- a/test/CodeGen/aarch64-neon-3v.c
+++ b/test/CodeGen/aarch64-neon-3v.c
@@ -2,7 +2,7 @@
// REQUIRES: arm64-registered-target
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -S -O3 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu -S -O3 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -S -O3 -o - %s | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-across.c b/test/CodeGen/aarch64-neon-across.c
index 17ac3efb85..330869ec89 100644
--- a/test/CodeGen/aarch64-neon-across.c
+++ b/test/CodeGen/aarch64-neon-across.c
@@ -2,7 +2,7 @@
// REQUIRES: arm64-registered-target
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu \
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-extract.c b/test/CodeGen/aarch64-neon-extract.c
index 77d574cf0e..b8da2b842e 100644
--- a/test/CodeGen/aarch64-neon-extract.c
+++ b/test/CodeGen/aarch64-neon-extract.c
@@ -2,7 +2,7 @@
// REQUIRES: arm64-registered-target
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu \
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-fcvt-intrinsics.c b/test/CodeGen/aarch64-neon-fcvt-intrinsics.c
index 77022f58fe..c63ce8557d 100644
--- a/test/CodeGen/aarch64-neon-fcvt-intrinsics.c
+++ b/test/CodeGen/aarch64-neon-fcvt-intrinsics.c
@@ -2,7 +2,7 @@
// REQUIRES: arm64-registered-target
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu \
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-fma.c b/test/CodeGen/aarch64-neon-fma.c
index 85603c5257..68f2fbc52a 100644
--- a/test/CodeGen/aarch64-neon-fma.c
+++ b/test/CodeGen/aarch64-neon-fma.c
@@ -4,7 +4,7 @@
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck -check-prefix=CHECK-FMA %s
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -S -O3 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu -S -O3 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -S -O3 -o - %s | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-intrinsics.c b/test/CodeGen/aarch64-neon-intrinsics.c
index 4e8c40528e..e7fa048881 100644
--- a/test/CodeGen/aarch64-neon-intrinsics.c
+++ b/test/CodeGen/aarch64-neon-intrinsics.c
@@ -2,7 +2,7 @@
// REQUIRES: arm64-registered-target
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-AARCH64
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu \
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ARM64
// Test new aarch64 intrinsics and types
@@ -5824,157 +5824,157 @@ float64_t test_vrsqrted_f64(float64_t a) {
uint8x16_t test_vld1q_u8(uint8_t const *a) {
// CHECK-LABEL: test_vld1q_u8
return vld1q_u8(a);
- // CHECK: {{ld1 {v[0-9]+.16b}|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.16b }|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
}
uint16x8_t test_vld1q_u16(uint16_t const *a) {
// CHECK-LABEL: test_vld1q_u16
return vld1q_u16(a);
- // CHECK: {{ld1 {v[0-9]+.8h}|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.8h }|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
}
uint32x4_t test_vld1q_u32(uint32_t const *a) {
// CHECK-LABEL: test_vld1q_u32
return vld1q_u32(a);
- // CHECK: {{ld1 {v[0-9]+.4s}|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.4s }|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
}
uint64x2_t test_vld1q_u64(uint64_t const *a) {
// CHECK-LABEL: test_vld1q_u64
return vld1q_u64(a);
- // CHECK: {{ld1 {v[0-9]+.2d}|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.2d }|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
}
int8x16_t test_vld1q_s8(int8_t const *a) {
// CHECK-LABEL: test_vld1q_s8
return vld1q_s8(a);
- // CHECK: {{ld1 {v[0-9]+.16b}|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.16b }|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
}
int16x8_t test_vld1q_s16(int16_t const *a) {
// CHECK-LABEL: test_vld1q_s16
return vld1q_s16(a);
- // CHECK: {{ld1 {v[0-9]+.8h}|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.8h }|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
}
int32x4_t test_vld1q_s32(int32_t const *a) {
// CHECK-LABEL: test_vld1q_s32
return vld1q_s32(a);
- // CHECK: {{ld1 {v[0-9]+.4s}|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.4s }|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
}
int64x2_t test_vld1q_s64(int64_t const *a) {
// CHECK-LABEL: test_vld1q_s64
return vld1q_s64(a);
- // CHECK: {{ld1 {v[0-9]+.2d}|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.2d }|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
}
float16x8_t test_vld1q_f16(float16_t const *a) {
// CHECK-LABEL: test_vld1q_f16
return vld1q_f16(a);
- // CHECK: {{ld1 {v[0-9]+.8h}|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.8h }|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
}
float32x4_t test_vld1q_f32(float32_t const *a) {
// CHECK-LABEL: test_vld1q_f32
return vld1q_f32(a);
- // CHECK: {{ld1 {v[0-9]+.4s}|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.4s }|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
}
float64x2_t test_vld1q_f64(float64_t const *a) {
// CHECK-LABEL: test_vld1q_f64
return vld1q_f64(a);
- // CHECK: {{ld1 {v[0-9]+.2d}|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.2d }|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
}
poly8x16_t test_vld1q_p8(poly8_t const *a) {
// CHECK-LABEL: test_vld1q_p8
return vld1q_p8(a);
- // CHECK: {{ld1 {v[0-9]+.16b}|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.16b }|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
}
poly16x8_t test_vld1q_p16(poly16_t const *a) {
// CHECK-LABEL: test_vld1q_p16
return vld1q_p16(a);
- // CHECK: {{ld1 {v[0-9]+.8h}|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.8h }|ldr q[0-9]+}}, [{{x[0-9]+|sp}}]
}
uint8x8_t test_vld1_u8(uint8_t const *a) {
// CHECK-LABEL: test_vld1_u8
return vld1_u8(a);
- // CHECK: {{ld1 {v[0-9]+.8b}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.8b }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
uint16x4_t test_vld1_u16(uint16_t const *a) {
// CHECK-LABEL: test_vld1_u16
return vld1_u16(a);
- // CHECK: {{ld1 {v[0-9]+.4h}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.4h }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
uint32x2_t test_vld1_u32(uint32_t const *a) {
// CHECK-LABEL: test_vld1_u32
return vld1_u32(a);
- // CHECK: {{ld1 {v[0-9]+.2s}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.2s }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
uint64x1_t test_vld1_u64(uint64_t const *a) {
// CHECK-LABEL: test_vld1_u64
return vld1_u64(a);
- // CHECK: {{ld1 {v[0-9]+.1d}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.1d }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
int8x8_t test_vld1_s8(int8_t const *a) {
// CHECK-LABEL: test_vld1_s8
return vld1_s8(a);
- // CHECK: {{ld1 {v[0-9]+.8b}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.8b }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
int16x4_t test_vld1_s16(int16_t const *a) {
// CHECK-LABEL: test_vld1_s16
return vld1_s16(a);
- // CHECK: {{ld1 {v[0-9]+.4h}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.4h }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
int32x2_t test_vld1_s32(int32_t const *a) {
// CHECK-LABEL: test_vld1_s32
return vld1_s32(a);
- // CHECK: {{ld1 {v[0-9]+.2s}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.2s }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
int64x1_t test_vld1_s64(int64_t const *a) {
// CHECK-LABEL: test_vld1_s64
return vld1_s64(a);
- // CHECK: {{ld1 {v[0-9]+.1d}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.1d }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
float16x4_t test_vld1_f16(float16_t const *a) {
// CHECK-LABEL: test_vld1_f16
return vld1_f16(a);
- // CHECK: {{ld1 {v[0-9]+.4h}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.4h }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
float32x2_t test_vld1_f32(float32_t const *a) {
// CHECK-LABEL: test_vld1_f32
return vld1_f32(a);
- // CHECK: {{ld1 {v[0-9]+.2s}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.2s }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
float64x1_t test_vld1_f64(float64_t const *a) {
// CHECK-LABEL: test_vld1_f64
return vld1_f64(a);
- // CHECK: {{ld1 {v[0-9]+.1d}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.1d }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
poly8x8_t test_vld1_p8(poly8_t const *a) {
// CHECK-LABEL: test_vld1_p8
return vld1_p8(a);
- // CHECK: {{ld1 {v[0-9]+.8b}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.8b }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
poly16x4_t test_vld1_p16(poly16_t const *a) {
// CHECK-LABEL: test_vld1_p16
return vld1_p16(a);
- // CHECK: {{ld1 {v[0-9]+.4h}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1 { v[0-9]+.4h }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
uint8x16x2_t test_vld2q_u8(uint8_t const *a) {
@@ -6448,157 +6448,157 @@ poly16x4x4_t test_vld4_p16(poly16_t const *a) {
void test_vst1q_u8(uint8_t *a, uint8x16_t b) {
// CHECK-LABEL: test_vst1q_u8
vst1q_u8(a, b);
- // CHECK: {{st1 {v[0-9]+.16b}|str q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.16b }|str q[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1q_u16(uint16_t *a, uint16x8_t b) {
// CHECK-LABEL: test_vst1q_u16
vst1q_u16(a, b);
- // CHECK: {{st1 {v[0-9]+.8h}|str q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.8h }|str q[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1q_u32(uint32_t *a, uint32x4_t b) {
// CHECK-LABEL: test_vst1q_u32
vst1q_u32(a, b);
- // CHECK: {{st1 {v[0-9]+.4s}|str q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.4s }|str q[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1q_u64(uint64_t *a, uint64x2_t b) {
// CHECK-LABEL: test_vst1q_u64
vst1q_u64(a, b);
- // CHECK: {{st1 {v[0-9]+.2d}|str q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.2d }|str q[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1q_s8(int8_t *a, int8x16_t b) {
// CHECK-LABEL: test_vst1q_s8
vst1q_s8(a, b);
- // CHECK: {{st1 {v[0-9]+.16b}|str q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.16b }|str q[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1q_s16(int16_t *a, int16x8_t b) {
// CHECK-LABEL: test_vst1q_s16
vst1q_s16(a, b);
- // CHECK: {{st1 {v[0-9]+.8h}|str q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.8h }|str q[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1q_s32(int32_t *a, int32x4_t b) {
// CHECK-LABEL: test_vst1q_s32
vst1q_s32(a, b);
- // CHECK: {{st1 {v[0-9]+.4s}|str q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.4s }|str q[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1q_s64(int64_t *a, int64x2_t b) {
// CHECK-LABEL: test_vst1q_s64
vst1q_s64(a, b);
- // CHECK: {{st1 {v[0-9]+.2d}|str q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.2d }|str q[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1q_f16(float16_t *a, float16x8_t b) {
// CHECK-LABEL: test_vst1q_f16
vst1q_f16(a, b);
- // CHECK: {{st1 {v[0-9]+.8h}|str q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.8h }|str q[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1q_f32(float32_t *a, float32x4_t b) {
// CHECK-LABEL: test_vst1q_f32
vst1q_f32(a, b);
- // CHECK: {{st1 {v[0-9]+.4s}|str q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.4s }|str q[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1q_f64(float64_t *a, float64x2_t b) {
// CHECK-LABEL: test_vst1q_f64
vst1q_f64(a, b);
- // CHECK: {{st1 {v[0-9]+.2d}|str q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.2d }|str q[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1q_p8(poly8_t *a, poly8x16_t b) {
// CHECK-LABEL: test_vst1q_p8
vst1q_p8(a, b);
- // CHECK: {{st1 {v[0-9]+.16b}|str q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.16b }|str q[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1q_p16(poly16_t *a, poly16x8_t b) {
// CHECK-LABEL: test_vst1q_p16
vst1q_p16(a, b);
- // CHECK: {{st1 {v[0-9]+.8h}|str q[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.8h }|str q[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1_u8(uint8_t *a, uint8x8_t b) {
// CHECK-LABEL: test_vst1_u8
vst1_u8(a, b);
- // CHECK: {{st1 {v[0-9]+.8b}|str d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.8b }|str d[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1_u16(uint16_t *a, uint16x4_t b) {
// CHECK-LABEL: test_vst1_u16
vst1_u16(a, b);
- // CHECK: {{st1 {v[0-9]+.4h}|str d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.4h }|str d[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1_u32(uint32_t *a, uint32x2_t b) {
// CHECK-LABEL: test_vst1_u32
vst1_u32(a, b);
- // CHECK: {{st1 {v[0-9]+.2s}|str d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.2s }|str d[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1_u64(uint64_t *a, uint64x1_t b) {
// CHECK-LABEL: test_vst1_u64
vst1_u64(a, b);
- // CHECK: {{st1 {v[0-9]+.1d}|str d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.1d }|str d[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1_s8(int8_t *a, int8x8_t b) {
// CHECK-LABEL: test_vst1_s8
vst1_s8(a, b);
- // CHECK: {{st1 {v[0-9]+.8b}|str d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.8b }|str d[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1_s16(int16_t *a, int16x4_t b) {
// CHECK-LABEL: test_vst1_s16
vst1_s16(a, b);
- // CHECK: {{st1 {v[0-9]+.4h}|str d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.4h }|str d[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1_s32(int32_t *a, int32x2_t b) {
// CHECK-LABEL: test_vst1_s32
vst1_s32(a, b);
- // CHECK: {{st1 {v[0-9]+.2s}|str d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.2s }|str d[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1_s64(int64_t *a, int64x1_t b) {
// CHECK-LABEL: test_vst1_s64
vst1_s64(a, b);
- // CHECK: {{st1 {v[0-9]+.1d}|str d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.1d }|str d[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1_f16(float16_t *a, float16x4_t b) {
// CHECK-LABEL: test_vst1_f16
vst1_f16(a, b);
- // CHECK: {{st1 {v[0-9]+.4h}|str d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.4h }|str d[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1_f32(float32_t *a, float32x2_t b) {
// CHECK-LABEL: test_vst1_f32
vst1_f32(a, b);
- // CHECK: {{st1 {v[0-9]+.2s}|str d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.2s }|str d[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1_f64(float64_t *a, float64x1_t b) {
// CHECK-LABEL: test_vst1_f64
vst1_f64(a, b);
- // CHECK: {{st1 {v[0-9]+.1d}|str d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.1d }|str d[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1_p8(poly8_t *a, poly8x8_t b) {
// CHECK-LABEL: test_vst1_p8
vst1_p8(a, b);
- // CHECK: {{st1 {v[0-9]+.8b}|str d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.8b }|str d[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1_p16(poly16_t *a, poly16x4_t b) {
// CHECK-LABEL: test_vst1_p16
vst1_p16(a, b);
- // CHECK: {{st1 {v[0-9]+.4h}|str d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.4h }|str d[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst2q_u8(uint8_t *a, uint8x16x2_t b) {
@@ -8175,13 +8175,13 @@ int64_t test_vcltzd_s64(int64_t a) {
int64_t test_vtstd_s64(int64_t a, int64_t b) {
// CHECK-LABEL: test_vtstd_s64
-// CHECK: {{cmtst d[0-9]+, d[0-9]+, d[0-9]+|and x[0-9]+, x1, x0}}
+// CHECK: {{cmtst d[0-9]+, d[0-9]+, d[0-9]+|tst x1, x0}}
return (int64_t)vtstd_s64(a, b);
}
uint64_t test_vtstd_u64(uint64_t a, uint64_t b) {
// CHECK-LABEL: test_vtstd_u64
-// CHECK: {{cmtst d[0-9]+, d[0-9]+, d[0-9]+|and x[0-9]+, x1, x0}}
+// CHECK: {{cmtst d[0-9]+, d[0-9]+, d[0-9]+|tst x1, x0}}
return (uint64_t)vtstd_u64(a, b);
}
diff --git a/test/CodeGen/aarch64-neon-ld-sideeffect.c b/test/CodeGen/aarch64-neon-ld-sideeffect.c
index 1160133a77..1436dcd9ba 100644
--- a/test/CodeGen/aarch64-neon-ld-sideeffect.c
+++ b/test/CodeGen/aarch64-neon-ld-sideeffect.c
@@ -10,5 +10,5 @@ float32x2_t bar(void) {
return vld1_f32(foo());
// CHECK: call i8* @foo
// CHECK-NOT: call i8* @foo
- // CHECK: call <2 x float> @llvm.arm.neon.vld1
+ // CHECK: call <2 x float> @llvm.{{arm|arm64}}.neon.vld1
}
diff --git a/test/CodeGen/aarch64-neon-ldst-one.c b/test/CodeGen/aarch64-neon-ldst-one.c
index 2d63628e9b..1f26f67dd0 100644
--- a/test/CodeGen/aarch64-neon-ldst-one.c
+++ b/test/CodeGen/aarch64-neon-ldst-one.c
@@ -2,7 +2,7 @@
// REQUIRES: arm64-registered-target
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu \
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
#include <arm_neon.h>
@@ -112,7 +112,7 @@ uint32x2_t test_vld1_dup_u32(uint32_t *a) {
uint64x1_t test_vld1_dup_u64(uint64_t *a) {
// CHECK-LABEL: test_vld1_dup_u64
return vld1_dup_u64(a);
- // CHECK: {{ld1r {v[0-9]+.1d}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1r { v[0-9]+.1d }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
int8x8_t test_vld1_dup_s8(int8_t *a) {
@@ -136,7 +136,7 @@ int32x2_t test_vld1_dup_s32(int32_t *a) {
int64x1_t test_vld1_dup_s64(int64_t *a) {
// CHECK-LABEL: test_vld1_dup_s64
return vld1_dup_s64(a);
- // CHECK: {{ld1r {v[0-9]+.1d}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1r { v[0-9]+.1d }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
float16x4_t test_vld1_dup_f16(float16_t *a) {
@@ -154,7 +154,7 @@ float32x2_t test_vld1_dup_f32(float32_t *a) {
float64x1_t test_vld1_dup_f64(float64_t *a) {
// CHECK-LABEL: test_vld1_dup_f64
return vld1_dup_f64(a);
- // CHECK: {{ld1r {v[0-9]+.1d}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1r { v[0-9]+.1d }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
poly8x8_t test_vld1_dup_p8(poly8_t *a) {
@@ -172,7 +172,7 @@ poly16x4_t test_vld1_dup_p16(poly16_t *a) {
poly64x1_t test_vld1_dup_p64(poly64_t *a) {
// CHECK-LABEL: test_vld1_dup_p64
return vld1_dup_p64(a);
- // CHECK: {{ld1r {v[0-9]+.1d}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1r { v[0-9]+.1d }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
uint8x16x2_t test_vld2q_dup_u8(uint8_t *a) {
@@ -812,7 +812,7 @@ uint32x2_t test_vld1_lane_u32(uint32_t *a, uint32x2_t b) {
uint64x1_t test_vld1_lane_u64(uint64_t *a, uint64x1_t b) {
// CHECK-LABEL: test_vld1_lane_u64
return vld1_lane_u64(a, b, 0);
- // CHECK: {{ld1r {v[0-9]+.1d}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1r { v[0-9]+.1d }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
int8x8_t test_vld1_lane_s8(int8_t *a, int8x8_t b) {
@@ -836,7 +836,7 @@ int32x2_t test_vld1_lane_s32(int32_t *a, int32x2_t b) {
int64x1_t test_vld1_lane_s64(int64_t *a, int64x1_t b) {
// CHECK-LABEL: test_vld1_lane_s64
return vld1_lane_s64(a, b, 0);
- // CHECK: {{ld1r {v[0-9]+.1d}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1r { v[0-9]+.1d }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
float16x4_t test_vld1_lane_f16(float16_t *a, float16x4_t b) {
@@ -854,7 +854,7 @@ float32x2_t test_vld1_lane_f32(float32_t *a, float32x2_t b) {
float64x1_t test_vld1_lane_f64(float64_t *a, float64x1_t b) {
// CHECK-LABEL: test_vld1_lane_f64
return vld1_lane_f64(a, b, 0);
- // CHECK: {{ld1r {v[0-9]+.1d}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1r { v[0-9]+.1d }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
poly8x8_t test_vld1_lane_p8(poly8_t *a, poly8x8_t b) {
@@ -872,7 +872,7 @@ poly16x4_t test_vld1_lane_p16(poly16_t *a, poly16x4_t b) {
poly64x1_t test_vld1_lane_p64(poly64_t *a, poly64x1_t b) {
// CHECK-LABEL: test_vld1_lane_p64
return vld1_lane_p64(a, b, 0);
- // CHECK: {{ld1r {v[0-9]+.1d}|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{ld1r { v[0-9]+.1d }|ldr d[0-9]+}}, [{{x[0-9]+|sp}}]
}
int8x16x2_t test_vld2q_lane_s8(int8_t const * ptr, int8x16x2_t src) {
@@ -1526,7 +1526,7 @@ void test_vst1_lane_f32(float32_t *a, float32x2_t b) {
void test_vst1_lane_f64(float64_t *a, float64x1_t b) {
// CHECK-LABEL: test_vst1_lane_f64
vst1_lane_f64(a, b, 0);
- // CHECK: {{st1 {v[0-9]+.d}\[0]|str d[0-9]+}}, [{{x[0-9]+|sp}}]
+ // CHECK: {{st1 { v[0-9]+.d }\[0]|str d[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1_lane_p8(poly8_t *a, poly8x8_t b) {
diff --git a/test/CodeGen/aarch64-neon-misc.c b/test/CodeGen/aarch64-neon-misc.c
index dce00f3454..9a5569b63d 100644
--- a/test/CodeGen/aarch64-neon-misc.c
+++ b/test/CodeGen/aarch64-neon-misc.c
@@ -2,7 +2,7 @@
// REQUIRES: arm64-registered-target
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu \
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-perm.c b/test/CodeGen/aarch64-neon-perm.c
index c9a3d600dc..bcff83de36 100644
--- a/test/CodeGen/aarch64-neon-perm.c
+++ b/test/CodeGen/aarch64-neon-perm.c
@@ -2,7 +2,7 @@
// REQUIRES: arm64-registered-target
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu \
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-scalar-copy.c b/test/CodeGen/aarch64-neon-scalar-copy.c
index 227c6e04e1..806b626bff 100644
--- a/test/CodeGen/aarch64-neon-scalar-copy.c
+++ b/test/CodeGen/aarch64-neon-scalar-copy.c
@@ -2,7 +2,7 @@
// REQUIRES: arm64-registered-target
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu \
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
diff --git a/test/CodeGen/aarch64-neon-scalar-x-indexed-elem.c b/test/CodeGen/aarch64-neon-scalar-x-indexed-elem.c
index 0293e983c2..ac7a7520ee 100644
--- a/test/CodeGen/aarch64-neon-scalar-x-indexed-elem.c
+++ b/test/CodeGen/aarch64-neon-scalar-x-indexed-elem.c
@@ -2,7 +2,7 @@
// REQUIRES: arm64-registered-target
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu \
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -target-cpu cyclone \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-shifts.c b/test/CodeGen/aarch64-neon-shifts.c
index 99adff1f04..a6cb9be7c2 100644
--- a/test/CodeGen/aarch64-neon-shifts.c
+++ b/test/CodeGen/aarch64-neon-shifts.c
@@ -2,7 +2,7 @@
// REQUIRES: arm64-registered-target
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -emit-llvm -O1 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu \
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -emit-llvm -O1 -o - %s | FileCheck %s
#include <arm_neon.h>
diff --git a/test/CodeGen/aarch64-neon-tbl.c b/test/CodeGen/aarch64-neon-tbl.c
index 93cba1d7e1..682fade592 100644
--- a/test/CodeGen/aarch64-neon-tbl.c
+++ b/test/CodeGen/aarch64-neon-tbl.c
@@ -2,7 +2,7 @@
// REQUIRES: arm64-registered-target
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu \
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-vcombine.c b/test/CodeGen/aarch64-neon-vcombine.c
index 381b052849..78f422ec25 100644
--- a/test/CodeGen/aarch64-neon-vcombine.c
+++ b/test/CodeGen/aarch64-neon-vcombine.c
@@ -2,7 +2,7 @@
// REQUIRES: arm64-registered-target
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -S -O3 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu -S -O3 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -S -O3 -o - %s | FileCheck %s
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-neon-vget-hilo.c b/test/CodeGen/aarch64-neon-vget-hilo.c
index 4d80d414d3..96317ffd32 100644
--- a/test/CodeGen/aarch64-neon-vget-hilo.c
+++ b/test/CodeGen/aarch64-neon-vget-hilo.c
@@ -2,7 +2,7 @@
// REQUIRES: arm64-registered-target
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s --check-prefix CHECK-COMMON --check-prefix CHECK-AARCH64
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu \
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s --check-prefix CHECK-COMMON --check-prefix CHECK-ARM64
// Test new aarch64 intrinsics and types
diff --git a/test/CodeGen/aarch64-poly128.c b/test/CodeGen/aarch64-poly128.c
index 609e5962ce..3a4d363a53 100644
--- a/test/CodeGen/aarch64-poly128.c
+++ b/test/CodeGen/aarch64-poly128.c
@@ -3,7 +3,7 @@
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s --check-prefix=CHECK \
// RUN: --check-prefix=CHECK-AARCH64
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu \
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s --check-prefix=CHECK \
// RUN: --check-prefix=CHECK-ARM64
diff --git a/test/CodeGen/aarch64-poly64.c b/test/CodeGen/aarch64-poly64.c
index c071147af2..82740f8095 100644
--- a/test/CodeGen/aarch64-poly64.c
+++ b/test/CodeGen/aarch64-poly64.c
@@ -3,7 +3,7 @@
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s --check-prefix=CHECK \
// RUN: --check-prefix=CHECK-AARCH64
-// RUN: %clang_cc1 -triple arm64-none-linux-gnu \
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
// RUN: -ffp-contract=fast -S -O3 -o - %s | FileCheck %s --check-prefix=CHECK \
// RUN: --check-prefix=CHECK-ARM64
@@ -135,28 +135,28 @@ poly64x2_t test_vcombine_p64(poly64x1_t low, poly64x1_t high) {
poly64x1_t test_vld1_p64(poly64_t const * ptr) {
// CHECK-LABEL: test_vld1_p64
return vld1_p64(ptr);
- // CHECK-AARCH64: ld1 {{{v[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+ // CHECK-AARCH64: ld1 { {{v[0-9]+}}.1d }, [{{x[0-9]+|sp}}]
// CHECK-ARM64: ldr {{d[0-9]+}}, [{{x[0-9]+|sp}}]
}
poly64x2_t test_vld1q_p64(poly64_t const * ptr) {
// CHECK-LABEL: test_vld1q_p64
return vld1q_p64(ptr);
- // CHECK-AARCH64: ld1 {{{v[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+ // CHECK-AARCH64: ld1 { {{v[0-9]+}}.2d }, [{{x[0-9]+|sp}}]
// CHECK-ARM64: ldr {{q[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1_p64(poly64_t * ptr, poly64x1_t val) {
// CHECK-LABEL: test_vst1_p64
return vst1_p64(ptr, val);
- // CHECK-AARCH64: st1 {{{v[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+ // CHECK-AARCH64: st1 { {{v[0-9]+}}.1d }, [{{x[0-9]+|sp}}]
// CHECK-ARM64: str {{d[0-9]+}}, [{{x[0-9]+|sp}}]
}
void test_vst1q_p64(poly64_t * ptr, poly64x2_t val) {
// CHECK-LABEL: test_vst1q_p64
return vst1q_p64(ptr, val);
- // CHECK-AARCH64: st1 {{{v[0-9]+}}.2d}, [{{x[0-9]+|sp}}]
+ // CHECK-AARCH64: st1 { {{v[0-9]+}}.2d }, [{{x[0-9]+|sp}}]
// CHECK-ARM64: str {{q[0-9]+}}, [{{x[0-9]+|sp}}]
}
diff --git a/test/CodeGen/aarch64-type-sizes.c b/test/CodeGen/aarch64-type-sizes.c
index f9e55f7e1f..3b3789f4cb 100644
--- a/test/CodeGen/aarch64-type-sizes.c
+++ b/test/CodeGen/aarch64-type-sizes.c
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -w -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-LE %s
// RUN: %clang_cc1 -triple aarch64_be-none-linux-gnu -emit-llvm -w -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-BE %s
+// RUN: %clang_cc1 -triple arm64_be-none-linux-gnu -emit-llvm -w -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-BE %s
// char by definition has size 1
// CHECK-LE: target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
diff --git a/test/CodeGen/aarch64-varargs.c b/test/CodeGen/aarch64-varargs.c
index 053982bb25..5f0ea6e295 100644
--- a/test/CodeGen/aarch64-varargs.c
+++ b/test/CodeGen/aarch64-varargs.c
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple aarch64 -emit-llvm -o - %s | FileCheck -check-prefix=CHECK --check-prefix=CHECK-LE %s
// RUN: %clang_cc1 -triple aarch64_be -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-BE %s
// RUN: %clang_cc1 -triple arm64-linux-gnu -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-LE %s
+// RUN: %clang_cc1 -triple arm64_be-linux-gnu -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=CHECK-BE %s
#include <stdarg.h>
diff --git a/test/CodeGen/arm-aapcs-vfp.c b/test/CodeGen/arm-aapcs-vfp.c
index cd9aaa4735..9972158bb9 100644
--- a/test/CodeGen/arm-aapcs-vfp.c
+++ b/test/CodeGen/arm-aapcs-vfp.c
@@ -12,7 +12,7 @@
// RUN: -ffreestanding \
// RUN: -emit-llvm -w -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-apple-darwin9 \
+// RUN: %clang_cc1 -triple arm64-apple-darwin9 -target-feature +neon \
// RUN: -ffreestanding \
// RUN: -emit-llvm -w -o - %s | FileCheck -check-prefix=CHECK64 %s
diff --git a/test/CodeGen/arm-homogenous.c b/test/CodeGen/arm-homogenous.c
index ad21444aab..854ccaf15e 100644
--- a/test/CodeGen/arm-homogenous.c
+++ b/test/CodeGen/arm-homogenous.c
@@ -178,7 +178,7 @@ void test_struct_of_four_doubles(void) {
// CHECK64: test_struct_of_four_doubles
// CHECK64: call void @takes_struct_of_four_doubles(double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, [3 x float] undef, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}})
// CHECK64-AAPCS: test_struct_of_four_doubles
-// CHECK64-AAPCS: call void @takes_struct_of_four_doubles(double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, [3 x float] undef, [4 x double] {{.*}}, double {{.*}})
+// CHECK64-AAPCS: call void @takes_struct_of_four_doubles(double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}}, [3 x float] undef, double {{.*}}, double {{.*}}, double {{.*}}, double {{.*}})
takes_struct_of_four_doubles(3.0, g_s4d, g_s4d, 4.0);
}
@@ -214,7 +214,7 @@ void test_struct_of_vecs(void) {
// CHECK64: test_struct_of_vecs
// CHECK64: call void @takes_struct_of_vecs(double {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, [3 x float] undef, <8 x i8> {{.*}}, <4 x i16> {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, double {{.*}})
// CHECK64-AAPCS: test_struct_of_vecs
-// CHECK64-AAPCS: call void @takes_struct_of_vecs(double {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, [3 x float] undef, [4 x double] {{.*}})
+// CHECK64-AAPCS: call void @takes_struct_of_vecs(double {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, [3 x float] undef, <8 x i8> {{.*}}, <4 x i16> {{.*}}, <8 x i8> {{.*}}, <4 x i16> {{.*}}, double {{.*}})
takes_struct_of_vecs(3.0, g_vec, g_vec, 4.0);
}
diff --git a/test/CodeGen/arm64-aapcs-arguments.c b/test/CodeGen/arm64-aapcs-arguments.c
new file mode 100644
index 0000000000..b430630b07
--- /dev/null
+++ b/test/CodeGen/arm64-aapcs-arguments.c
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -triple arm64-linux-gnu -target-feature +neon -target-abi aapcs -ffreestanding -emit-llvm -w -o - %s | FileCheck %s
+
+// AAPCS clause C.8 says: If the argument has an alignment of 16 then the NGRN
+// is rounded up to the next even number.
+
+// CHECK: void @test1(i32 %x0, i128 %x2_x3, i128 %x4_x5, i128 %x6_x7, i128 %sp.coerce)
+typedef union { __int128 a; } Small;
+void test1(int x0, __int128 x2_x3, __int128 x4_x5, __int128 x6_x7, Small sp) {
+}
+
+
+// CHECK: void @test2(i32 %x0, i128 %x2_x3.coerce, i32 %x4, i128 %x6_x7.coerce, i32 %sp, i128 %sp16.coerce)
+void test2(int x0, Small x2_x3, int x4, Small x6_x7, int sp, Small sp16) {
+}
+
+// We coerce HFAs into a contiguous [N x double] type if they're going on the
+// stack in order to avoid holes. Make sure we get all of them, and not just the
+// first:
+
+// CHECK: void @test3(float %s0_s3.0, float %s0_s3.1, float %s0_s3.2, float %s0_s3.3, float %s4, [3 x float], [2 x double] %sp.coerce, [2 x double] %sp16.coerce)
+typedef struct { float arr[4]; } HFA;
+void test3(HFA s0_s3, float s4, HFA sp, HFA sp16) {
+}
+
+
+// However, we shouldn't perform the [N x double] coercion on types which have
+// sufficient alignment to avoid holes on their own. We could coerce to [N x
+// fp128] or something, but leaving them as-is retains more information for
+// users to debug.
+
+// CHECK: void @test4(<16 x i8> %v0_v2.0, <16 x i8> %v0_v2.1, <16 x i8> %v0_v2.2, <16 x i8> %v3_v5.0, <16 x i8> %v3_v5.1, <16 x i8> %v3_v5.2, [2 x float], <16 x i8> %sp.0, <16 x i8> %sp.1, <16 x i8> %sp.2, double %sp48, <16 x i8> %sp64.0, <16 x i8> %sp64.1, <16 x i8> %sp64.2)
+typedef __attribute__((neon_vector_type(16))) signed char int8x16_t;
+typedef struct { int8x16_t arr[3]; } BigHFA;
+void test4(BigHFA v0_v2, BigHFA v3_v5, BigHFA sp, double sp48, BigHFA sp64) {
+}
+
+// It's the job of the argument *consumer* to perform the required sign & zero
+// extensions under AAPCS. There shouldn't be
+
+// CHECK: define i8 @test5(i8 %a, i16 %b)
+unsigned char test5(unsigned char a, signed short b) {
+}
diff --git a/test/CodeGen/arm64-arguments.c b/test/CodeGen/arm64-arguments.c
index edfb62832a..b2de08dbe6 100644
--- a/test/CodeGen/arm64-arguments.c
+++ b/test/CodeGen/arm64-arguments.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios7 -target-abi darwinpcs -ffreestanding -emit-llvm -w -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios7 -target-feature +neon -target-abi darwinpcs -ffreestanding -emit-llvm -w -o - %s | FileCheck %s
// CHECK: define signext i8 @f0()
char f0(void) {
@@ -640,6 +640,12 @@ float test_hfa(int n, ...) {
return h.d;
}
+float test_hfa_call(struct HFA *a) {
+// CHECK-LABEL: define float @test_hfa_call(%struct.HFA* %a)
+// CHECK: call float (i32, ...)* @test_hfa(i32 1, [2 x double] {{.*}})
+ test_hfa(1, *a);
+}
+
struct TooBigHFA {
float a, b, c, d, e;
};
diff --git a/test/CodeGen/arm64-lanes.c b/test/CodeGen/arm64-lanes.c
index 63d7d0c831..b0d4694677 100644
--- a/test/CodeGen/arm64-lanes.c
+++ b/test/CodeGen/arm64-lanes.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O3 -triple arm64-apple-ios7 -ffreestanding -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -O3 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -emit-llvm -o - %s | FileCheck %s
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64-scalar-test.c b/test/CodeGen/arm64-scalar-test.c
index 1e1087d40b..a956c845f9 100644
--- a/test/CodeGen/arm64-scalar-test.c
+++ b/test/CodeGen/arm64-scalar-test.c
@@ -1,5 +1,5 @@
// REQUIRES: arm64-registered-target
-// RUN: %clang_cc1 -triple arm64-apple-ios7.0 \
+// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-feature +neon \
// RUN: -S -O1 -o - -ffreestanding %s | FileCheck %s
// We're explicitly using arm_neon.h here: some types probably don't match
@@ -114,6 +114,12 @@ int64_t test_vqshld_s64(int64_t a, int64_t b) {
// CHECK: sqshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
}
+// CHECK: test_vqshld_s64_i
+int64_t test_vqshld_s64_i(int64_t a) {
+ return vqshld_s64(a, 36);
+// CHECK: sqshl {{d[0-9]+}}, {{d[0-9]+}}, #36
+}
+
// CHECK: test_vqshlb_u8
uint8_t test_vqshlb_u8(uint8_t a, uint8_t b) {
return vqshlb_u8(a, b);
@@ -138,6 +144,12 @@ uint64_t test_vqshld_u64(uint64_t a, uint64_t b) {
// CHECK: uqshl {{d[0-9]+}}, {{d[0-9]+}}, {{d[0-9]+}}
}
+// CHECK: test_vqshld_u64_i
+uint64_t test_vqshld_u64_i(uint64_t a) {
+ return vqshld_u64(a, 36);
+// CHECK: uqshl {{d[0-9]+}}, {{d[0-9]+}}, #36
+}
+
// CHECK: test_vshld_u64
uint64_t test_vshld_u64(uint64_t a, uint64_t b) {
return vshld_u64(a, b);
diff --git a/test/CodeGen/arm64-vrnd.c b/test/CodeGen/arm64-vrnd.c
index 4de2ec73ac..de72013629 100644
--- a/test/CodeGen/arm64-vrnd.c
+++ b/test/CodeGen/arm64-vrnd.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios7 -ffreestanding -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -emit-llvm -o - %s | FileCheck %s
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64-vrsqrt.c b/test/CodeGen/arm64-vrsqrt.c
index 45a536ca28..90e012a994 100644
--- a/test/CodeGen/arm64-vrsqrt.c
+++ b/test/CodeGen/arm64-vrsqrt.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -ffreestanding -emit-llvm -O1 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-feature +neon -ffreestanding -emit-llvm -O1 -o - %s | FileCheck %s
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64_crypto.c b/test/CodeGen/arm64_crypto.c
index 7150c56c8a..c672d2d0ed 100644
--- a/test/CodeGen/arm64_crypto.c
+++ b/test/CodeGen/arm64_crypto.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -ffreestanding -Os -S -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-feature +neon -target-feature +crypto -ffreestanding -Os -S -o - %s | FileCheck %s
// REQUIRES: arm64-registered-target
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64_neon_high_half.c b/test/CodeGen/arm64_neon_high_half.c
index 920dded8d3..0cda5e19ea 100644
--- a/test/CodeGen/arm64_neon_high_half.c
+++ b/test/CodeGen/arm64_neon_high_half.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -ffreestanding -Os -S -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-feature +neon -ffreestanding -Os -S -o - %s | FileCheck %s
// REQUIRES: arm64-registered-target
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64_vCMP.c b/test/CodeGen/arm64_vCMP.c
index 5fb1d7933a..7356d3c531 100644
--- a/test/CodeGen/arm64_vCMP.c
+++ b/test/CodeGen/arm64_vCMP.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
// Test ARM64 SIMD fused multiply add intrinsics
diff --git a/test/CodeGen/arm64_vLdStNum_lane.c b/test/CodeGen/arm64_vLdStNum_lane.c
index e36cd823b3..d9b85b2c2b 100644
--- a/test/CodeGen/arm64_vLdStNum_lane.c
+++ b/test/CodeGen/arm64_vLdStNum_lane.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
// Test ARM64 SIMD load and stores of an N-element structure intrinsics
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64_vMaxMin.c b/test/CodeGen/arm64_vMaxMin.c
index d53c0bb63d..631df08a31 100644
--- a/test/CodeGen/arm64_vMaxMin.c
+++ b/test/CodeGen/arm64_vMaxMin.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - %s | FileCheck -check-prefix=CHECK-CODEGEN %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - %s | FileCheck -check-prefix=CHECK-CODEGEN %s
// REQUIRES: arm64-registered-target
// Test ARM64 SIMD max/min intrinsics
diff --git a/test/CodeGen/arm64_vadd.c b/test/CodeGen/arm64_vadd.c
index 83fb3e7e79..94d248efd6 100644
--- a/test/CodeGen/arm64_vadd.c
+++ b/test/CodeGen/arm64_vadd.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
// Test ARM64 SIMD add intrinsics
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64_vca.c b/test/CodeGen/arm64_vca.c
index 0acbe45066..bfe07e817e 100644
--- a/test/CodeGen/arm64_vca.c
+++ b/test/CodeGen/arm64_vca.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
// Test ARM64 vector compare absolute intrinsics
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64_vcopy.c b/test/CodeGen/arm64_vcopy.c
index 7283909f49..990d4f658c 100644
--- a/test/CodeGen/arm64_vcopy.c
+++ b/test/CodeGen/arm64_vcopy.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
// Test ARM64 SIMD copy vector element to vector element: vcopyq_lane*
diff --git a/test/CodeGen/arm64_vcreate.c b/test/CodeGen/arm64_vcreate.c
index ae1e431c6b..b124eaffeb 100644
--- a/test/CodeGen/arm64_vcreate.c
+++ b/test/CodeGen/arm64_vcreate.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
// Test ARM64 SIMD vcreate intrinsics
/*#include <arm_neon.h>*/
diff --git a/test/CodeGen/arm64_vcvtfp.c b/test/CodeGen/arm64_vcvtfp.c
index a98a175a82..539c7d826c 100644
--- a/test/CodeGen/arm64_vcvtfp.c
+++ b/test/CodeGen/arm64_vcvtfp.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64_vdup.c b/test/CodeGen/arm64_vdup.c
index 8476af2538..8419828b38 100644
--- a/test/CodeGen/arm64_vdup.c
+++ b/test/CodeGen/arm64_vdup.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
// Test ARM64 SIMD duplicate lane and n intrinsics
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64_vdupq_n_f64.c b/test/CodeGen/arm64_vdupq_n_f64.c
index 5e8834f6c4..73e1cc4bf9 100644
--- a/test/CodeGen/arm64_vdupq_n_f64.c
+++ b/test/CodeGen/arm64_vdupq_n_f64.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -O3 -triple arm64-apple-ios7 -ffreestanding -S -o - %s | FileCheck %s
-// RUN: %clang_cc1 -O3 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | \
+// RUN: %clang_cc1 -O3 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - %s | FileCheck %s
+// RUN: %clang_cc1 -O3 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | \
// RUN: FileCheck -check-prefix=CHECK-IR %s
// REQUIRES: arm64-registered-target
diff --git a/test/CodeGen/arm64_vecCmpBr.c b/test/CodeGen/arm64_vecCmpBr.c
index ba67496e3e..08fa6f7e7b 100644
--- a/test/CodeGen/arm64_vecCmpBr.c
+++ b/test/CodeGen/arm64_vecCmpBr.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O3 -triple arm64-apple-ios7 -S -ffreestanding %s -o - | FileCheck %s
+// RUN: %clang_cc1 -O3 -triple arm64-apple-ios7 -target-feature +neon -S -ffreestanding %s -o - -target-cpu cyclone | FileCheck %s
// REQUIRES: arm64-registered-target
// test code generation for <rdar://problem/11487757>
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64_vext.c b/test/CodeGen/arm64_vext.c
index 50ff48c3a1..6c3fe73399 100644
--- a/test/CodeGen/arm64_vext.c
+++ b/test/CodeGen/arm64_vext.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
// Test ARM64 extract intrinsics
// can use as back end test by adding a run line with
diff --git a/test/CodeGen/arm64_vfma.c b/test/CodeGen/arm64_vfma.c
index e57161b894..bfa5687796 100644
--- a/test/CodeGen/arm64_vfma.c
+++ b/test/CodeGen/arm64_vfma.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
// Test ARM64 SIMD fused multiply add intrinsics
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64_vget.c b/test/CodeGen/arm64_vget.c
index 44c7da504c..62b68ef343 100644
--- a/test/CodeGen/arm64_vget.c
+++ b/test/CodeGen/arm64_vget.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
// Test ARM64 SIMD vget intrinsics
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64_vneg.c b/test/CodeGen/arm64_vneg.c
index 96b9e1f539..74ea0eb02b 100644
--- a/test/CodeGen/arm64_vneg.c
+++ b/test/CodeGen/arm64_vneg.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
// Test ARM64 SIMD negate and saturating negate intrinsics
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64_vqmov.c b/test/CodeGen/arm64_vqmov.c
index e8c0605a75..38acc0c3b3 100644
--- a/test/CodeGen/arm64_vqmov.c
+++ b/test/CodeGen/arm64_vqmov.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O3 -triple arm64-apple-ios7 -ffreestanding -S -o - %s | FileCheck %s
+// RUN: %clang_cc1 -O3 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - %s | FileCheck %s
// REQUIRES: arm64-registered-target
/// Test vqmov[u]n_high_<su>{16,32,64) ARM64 intrinsics
diff --git a/test/CodeGen/arm64_vrecps.c b/test/CodeGen/arm64_vrecps.c
index 66f06ceb53..1febaa1852 100644
--- a/test/CodeGen/arm64_vrecps.c
+++ b/test/CodeGen/arm64_vrecps.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O3 -triple arm64-apple-ios7 -ffreestanding -S -o - %s | FileCheck %s
+// RUN: %clang_cc1 -O3 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - %s | FileCheck %s
// REQUIRES: arm64-registered-target
/// Test vrecpss_f32, vrecpsd_f64 ARM64 intrinsics
diff --git a/test/CodeGen/arm64_vset_lane.c b/test/CodeGen/arm64_vset_lane.c
index 6997eb87cf..49f21514e8 100644
--- a/test/CodeGen/arm64_vset_lane.c
+++ b/test/CodeGen/arm64_vset_lane.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
// Test ARM64 SIMD set lane intrinsics INCOMPLETE
#include <arm_neon.h>
diff --git a/test/CodeGen/arm64_vshift.c b/test/CodeGen/arm64_vshift.c
index cac4d12bd9..48255c27a6 100644
--- a/test/CodeGen/arm64_vshift.c
+++ b/test/CodeGen/arm64_vshift.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -ffreestanding -emit-llvm -o - -O1 %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-feature +neon -ffreestanding -emit-llvm -o - -O1 %s | FileCheck %s
#include <arm_neon.h>
int8x8_t test_vqshl_n_s8(int8x8_t in) {
diff --git a/test/CodeGen/arm64_vsli.c b/test/CodeGen/arm64_vsli.c
index bce14461d0..02432577d3 100644
--- a/test/CodeGen/arm64_vsli.c
+++ b/test/CodeGen/arm64_vsli.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - %s | \
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - %s | \
// RUN: FileCheck -check-prefix=CHECK_CODEGEN %s
// REQUIRES: arm64-registered-target
// Test
diff --git a/test/CodeGen/arm64_vsri.c b/test/CodeGen/arm64_vsri.c
index f5613398b3..2547df5c9a 100644
--- a/test/CodeGen/arm64_vsri.c
+++ b/test/CodeGen/arm64_vsri.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - %s | \
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - %s | \
// RUN: FileCheck -check-prefix=CHECK_CODEGEN %s
// REQUIRES: arm64-registered-target
diff --git a/test/CodeGen/arm64_vtst.c b/test/CodeGen/arm64_vtst.c
index c30b3947c2..f40c62c4a3 100644
--- a/test/CodeGen/arm64_vtst.c
+++ b/test/CodeGen/arm64_vtst.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -O1 -triple arm64-apple-ios7 -target-feature +neon -ffreestanding -S -o - -emit-llvm %s | FileCheck %s
// Test ARM64 SIMD comparison test intrinsics
#include <arm_neon.h>
diff --git a/test/CodeGen/avx2-builtins.c b/test/CodeGen/avx2-builtins.c
index 5024d94e71..948483db8d 100644
--- a/test/CodeGen/avx2-builtins.c
+++ b/test/CodeGen/avx2-builtins.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -O3 -triple=x86_64-apple-darwin -target-feature +avx2 -emit-llvm -o - -Werror | FileCheck %s
+// RUN: %clang_cc1 %s -O0 -triple=x86_64-apple-darwin -target-feature +avx2 -emit-llvm -o - -Werror | FileCheck %s
// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
@@ -427,17 +427,17 @@ __m256i test_mm256_shuffle_epi8(__m256i a, __m256i b) {
}
__m256i test_mm256_shuffle_epi32(__m256i a) {
- // CHECK: shufflevector <8 x i32> %{{.*}}, <8 x i32> undef, <8 x i32> <i32 3, i32 3, i32 0, i32 0, i32 7, i32 7, i32 4, i32 4>
+ // CHECK: shufflevector <8 x i32> %{{.*}}, <8 x i32> %{{.*}}, <8 x i32> <i32 3, i32 3, i32 0, i32 0, i32 7, i32 7, i32 4, i32 4>
return _mm256_shuffle_epi32(a, 15);
}
__m256i test_mm256_shufflehi_epi16(__m256i a) {
- // CHECK: shufflevector <16 x i16> %{{.*}}, <16 x i16> undef, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 7, i32 6, i32 6, i32 5, i32 8, i32 9, i32 10, i32 11, i32 15, i32 14, i32 14, i32 13>
+ // CHECK: shufflevector <16 x i16> %{{.*}}, <16 x i16> %{{.*}}, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 7, i32 6, i32 6, i32 5, i32 8, i32 9, i32 10, i32 11, i32 15, i32 14, i32 14, i32 13>
return _mm256_shufflehi_epi16(a, 107);
}
__m256i test_mm256_shufflelo_epi16(__m256i a) {
- // CHECK: shufflevector <16 x i16> %{{.*}}, <16 x i16> undef, <16 x i32> <i32 3, i32 0, i32 1, i32 1, i32 4, i32 5, i32 6, i32 7, i32 11, i32 8, i32 9, i32 9, i32 12, i32 13, i32 14, i32 15>
+ // CHECK: shufflevector <16 x i16> %{{.*}}, <16 x i16> %{{.*}}, <16 x i32> <i32 3, i32 0, i32 1, i32 1, i32 4, i32 5, i32 6, i32 7, i32 11, i32 8, i32 9, i32 9, i32 12, i32 13, i32 14, i32 15>
return _mm256_shufflelo_epi16(a, 83);
}
diff --git a/test/CodeGen/builtins-arm-microsoft.c b/test/CodeGen/builtins-arm-microsoft.c
new file mode 100644
index 0000000000..682ec916a8
--- /dev/null
+++ b/test/CodeGen/builtins-arm-microsoft.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple thumbv7-windows -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple armv7-eabi -emit-llvm -o - %s | FileCheck %s
+// REQUIRES: arm-registered-target
+
+void test_yield_intrinsic() {
+ __yield();
+}
+
+// CHECK: call void @llvm.arm.hint(i32 1)
+
diff --git a/test/CodeGen/builtins-arm.c b/test/CodeGen/builtins-arm.c
index 937e1d9625..880d2d1798 100644
--- a/test/CodeGen/builtins-arm.c
+++ b/test/CodeGen/builtins-arm.c
@@ -22,7 +22,7 @@ void test_eh_return_data_regno()
void sevl() {
__builtin_arm_sevl();
}
-// CHECK: call {{.*}} @llvm.arm.sevl
+// CHECK: call {{.*}} @llvm.arm.hint(i32 5)
void test_barrier() {
__builtin_arm_dmb(1); //CHECK: call {{.*}} @llvm.arm.dmb(i32 1)
diff --git a/test/CodeGen/builtins-x86.c b/test/CodeGen/builtins-x86.c
index 261bf2f5d8..6df005d860 100644
--- a/test/CodeGen/builtins-x86.c
+++ b/test/CodeGen/builtins-x86.c
@@ -263,6 +263,9 @@ void f0() {
tmp_V4f = __builtin_ia32_cvtpi2ps(tmp_V4f, tmp_V2i);
tmp_V2i = __builtin_ia32_cvtps2pi(tmp_V4f);
tmp_i = __builtin_ia32_cvtss2si(tmp_V4f);
+
+ tmp_i = __builtin_ia32_rdtsc();
+ tmp_i = __builtin_ia32_rdtscp(&tmp_Ui);
#ifdef USE_64
tmp_LLi = __builtin_ia32_cvtss2si64(tmp_V4f);
#endif
diff --git a/test/CodeGen/disable-tail-calls.c b/test/CodeGen/disable-tail-calls.c
new file mode 100644
index 0000000000..b066100226
--- /dev/null
+++ b/test/CodeGen/disable-tail-calls.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9.0 -emit-llvm -O1 -mdisable-tail-calls -o - < %s | FileCheck %s
+
+typedef struct List {
+ struct List *next;
+ int data;
+} List;
+
+// CHECK-LABEL: define %struct.List* @find
+List *find(List *head, int data) {
+ if (!head)
+ return 0;
+ if (head->data == data)
+ return head;
+ // CHECK: call %struct.List* @find
+ return find(head->next, data);
+}
diff --git a/test/CodeGen/function-attributes.c b/test/CodeGen/function-attributes.c
index 47a0568355..177ad848f7 100644
--- a/test/CodeGen/function-attributes.c
+++ b/test/CodeGen/function-attributes.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -Os -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -Os -std=c99 -o - %s | FileCheck %s
// CHECK: define signext i8 @f0(i32 %x) [[NUW:#[0-9]+]]
// CHECK: define zeroext i8 @f1(i32 %x) [[NUW]]
// CHECK: define void @f2(i8 signext %x) [[NUW]]
@@ -117,6 +118,16 @@ void f19(void) {
setjmp(0);
}
+// CHECK-LABEL: define void @f20()
+// CHECK: {
+// CHECK: call i32 @_setjmp(i32* null)
+// CHECK: [[RT_CALL]]
+// CHECK: ret void
+int _setjmp(jmp_buf);
+void f20(void) {
+ _setjmp(0);
+}
+
// CHECK: attributes [[NUW]] = { nounwind optsize readnone{{.*}} }
// CHECK: attributes [[AI]] = { alwaysinline nounwind optsize readnone{{.*}} }
// CHECK: attributes [[ALIGN]] = { nounwind optsize readnone alignstack=16{{.*}} }
diff --git a/test/CodeGen/function-sections.c b/test/CodeGen/function-sections.c
new file mode 100644
index 0000000000..7994acf4dc
--- /dev/null
+++ b/test/CodeGen/function-sections.c
@@ -0,0 +1,28 @@
+// REQUIRES: x86-registered-target
+
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -o - < %s | FileCheck %s --check-prefix=PLAIN
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -ffunction-sections -fno-function-sections -o - < %s | FileCheck %s --check-prefix=PLAIN
+
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -ffunction-sections -o - < %s | FileCheck %s --check-prefix=FUNC_SECT
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fno-function-sections -ffunction-sections -o - < %s | FileCheck %s --check-prefix=FUNC_SECT
+
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fdata-sections -o - < %s | FileCheck %s --check-prefix=DATA_SECT
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fno-data-sections -fdata-sections -o - < %s | FileCheck %s --check-prefix=DATA_SECT
+
+const int hello = 123;
+void world() {}
+
+// PLAIN-NOT: section
+// PLAIN: world:
+// PLAIN: section .rodata,
+// PLAIN: hello:
+
+// FUNC_SECT: section .text.world,
+// FUNC_SECT: world:
+// FUNC_SECT: section .rodata,
+// FUNC_SECT: hello:
+
+// DATA_SECT-NOT: section
+// DATA_SECT: world:
+// DATA_SECT: .section .rodata.hello,
+// DATA_SECT: hello:
diff --git a/test/CodeGen/mips-type-sizes-int128.c b/test/CodeGen/mips-type-sizes-int128.c
new file mode 100644
index 0000000000..85ad73df9b
--- /dev/null
+++ b/test/CodeGen/mips-type-sizes-int128.c
@@ -0,0 +1,13 @@
+// RUN: not %clang_cc1 -triple mips-none-linux-gnu -emit-llvm -w -o - %s 2> %t1
+// RUN: FileCheck --check-prefix=O32 %s < %t1
+
+// RUN: %clang_cc1 -triple mips64-none-linux-gnu -emit-llvm -w -target-abi n32 -o - %s | FileCheck --check-prefix=NEW %s
+// RUN: %clang_cc1 -triple mips64-none-linux-gnu -emit-llvm -w -o - %s | FileCheck --check-prefix=NEW %s
+
+// O32 does not support __int128 so it must be tested separately
+// N32/N64 behave the same way so their tests have been combined into NEW
+
+int check_int128() {
+ return sizeof(__int128); // O32: :[[@LINE]]:17: error: __int128 is not supported on this target
+// NEW: ret i32 16
+}
diff --git a/test/CodeGen/mips-type-sizes.c b/test/CodeGen/mips-type-sizes.c
new file mode 100644
index 0000000000..963b282c01
--- /dev/null
+++ b/test/CodeGen/mips-type-sizes.c
@@ -0,0 +1,92 @@
+// RUN: %clang_cc1 -triple mips-none-linux-gnu -emit-llvm -w -o - %s | FileCheck --check-prefix=ALL --check-prefix=O32 %s
+// RUN: %clang_cc1 -triple mips64-none-linux-gnu -emit-llvm -w -target-abi n32 -o - %s | FileCheck --check-prefix=ALL --check-prefix=N32 %s
+// RUN: %clang_cc1 -triple mips64-none-linux-gnu -emit-llvm -w -o - %s | FileCheck --check-prefix=ALL --check-prefix=N64 %s
+
+int check_char() {
+ return sizeof(char);
+// ALL: ret i32 1
+}
+
+int check_short() {
+ return sizeof(short);
+// ALL: ret i32 2
+}
+
+int check_int() {
+ return sizeof(int);
+// ALL: ret i32 4
+}
+
+int check_long() {
+ return sizeof(long);
+// O32: ret i32 4
+// N32: ret i32 4
+// N64: ret i32 8
+}
+
+int check_longlong() {
+ return sizeof(long long);
+// ALL: ret i32 8
+}
+
+int check_fp16() {
+ return sizeof(__fp16);
+// ALL: ret i32 2
+}
+
+int check_float() {
+ return sizeof(float);
+// ALL: ret i32 4
+}
+
+int check_double() {
+ return sizeof(double);
+// ALL: ret i32 8
+}
+
+int check_longdouble() {
+ return sizeof(long double);
+// O32: ret i32 8
+// N32: ret i32 16
+// N64: ret i32 16
+}
+
+int check_floatComplex() {
+ return sizeof(float _Complex);
+// ALL: ret i32 8
+}
+
+int check_doubleComplex() {
+ return sizeof(double _Complex);
+// ALL: ret i32 16
+}
+
+int check_longdoubleComplex() {
+ return sizeof(long double _Complex);
+// O32: ret i32 16
+// N32: ret i32 32
+// N64: ret i32 32
+}
+
+int check_bool() {
+ return sizeof(_Bool);
+// ALL: ret i32 1
+}
+
+int check_wchar() {
+ return sizeof(__WCHAR_TYPE__);
+// ALL: ret i32 4
+}
+
+int check_wchar_is_unsigned() {
+ return (__WCHAR_TYPE__)-1 > (__WCHAR_TYPE__)0;
+// ALL: ret i32 0
+}
+
+int check_ptr() {
+ return sizeof(void *);
+// O32: ret i32 4
+// N32: ret i32 4
+// N64: ret i32 8
+}
+
diff --git a/test/CodeGen/mmx-inline-asm-error.c b/test/CodeGen/mmx-inline-asm-error.c
index a6393682ce..876c664e3b 100644
--- a/test/CodeGen/mmx-inline-asm-error.c
+++ b/test/CodeGen/mmx-inline-asm-error.c
@@ -4,9 +4,9 @@ typedef int vec256 __attribute__((ext_vector_type(8)));
vec256 foo(vec256 in) {
vec256 out;
- asm("something %0" : : "y"(in)); // expected-error {{invalid type 'vec256' in asm input for constraint 'y'}}
- asm("something %0" : "=y"(out)); // expected-error {{invalid type 'vec256' in asm input for constraint 'y'}}
- asm("something %0, %0" : "+y"(out)); // expected-error {{invalid type 'vec256' in asm input for constraint 'y'}}
+ asm("something %0" : : "y"(in)); // expected-error {{invalid type 'vec256' (vector of 8 'int' values) in asm input for constraint 'y'}}
+ asm("something %0" : "=y"(out)); // expected-error {{invalid type 'vec256' (vector of 8 'int' values) in asm input for constraint 'y'}}
+ asm("something %0, %0" : "+y"(out)); // expected-error {{invalid type 'vec256' (vector of 8 'int' values) in asm input for constraint 'y'}}
return out;
}
diff --git a/test/CodeGen/neon-crypto.c b/test/CodeGen/neon-crypto.c
index 5dcef4b579..551bafce7e 100644
--- a/test/CodeGen/neon-crypto.c
+++ b/test/CodeGen/neon-crypto.c
@@ -5,6 +5,11 @@
// RUN: not %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +neon \
// RUN: -S -O3 -o - %s 2>&1 | FileCheck --check-prefix=CHECK-NO-CRYPTO %s
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
+// RUN: -target-feature +crypto -emit-llvm -O1 -o - %s | FileCheck %s
+// RUN: not %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon \
+// RUN: -S -O3 -o - %s 2>&1 | FileCheck --check-prefix=CHECK-NO-CRYPTO %s
+
// Test new aarch64 intrinsics and types
#include <arm_neon.h>
@@ -13,83 +18,83 @@ uint8x16_t test_vaeseq_u8(uint8x16_t data, uint8x16_t key) {
// CHECK-LABEL: @test_vaeseq_u8
// CHECK-NO-CRYPTO: warning: implicit declaration of function 'vaeseq_u8' is invalid in C99
return vaeseq_u8(data, key);
- // CHECK: call <16 x i8> @llvm.arm.neon.aese(<16 x i8> %data, <16 x i8> %key)
+ // CHECK: call <16 x i8> @llvm.{{arm.neon|arm64.crypto}}.aese(<16 x i8> %data, <16 x i8> %key)
}
uint8x16_t test_vaesdq_u8(uint8x16_t data, uint8x16_t key) {
// CHECK-LABEL: @test_vaesdq_u8
return vaesdq_u8(data, key);
- // CHECK: call <16 x i8> @llvm.arm.neon.aesd(<16 x i8> %data, <16 x i8> %key)
+ // CHECK: call <16 x i8> @llvm.{{arm.neon|arm64.crypto}}.aesd(<16 x i8> %data, <16 x i8> %key)
}
uint8x16_t test_vaesmcq_u8(uint8x16_t data) {
// CHECK-LABEL: @test_vaesmcq_u8
return vaesmcq_u8(data);
- // CHECK: call <16 x i8> @llvm.arm.neon.aesmc(<16 x i8> %data)
+ // CHECK: call <16 x i8> @llvm.{{arm.neon|arm64.crypto}}.aesmc(<16 x i8> %data)
}
uint8x16_t test_vaesimcq_u8(uint8x16_t data) {
// CHECK-LABEL: @test_vaesimcq_u8
return vaesimcq_u8(data);
- // CHECK: call <16 x i8> @llvm.arm.neon.aesimc(<16 x i8> %data)
+ // CHECK: call <16 x i8> @llvm.{{arm.neon|arm64.crypto}}.aesimc(<16 x i8> %data)
}
uint32_t test_vsha1h_u32(uint32_t hash_e) {
// CHECK-LABEL: @test_vsha1h_u32
return vsha1h_u32(hash_e);
- // CHECK: call i32 @llvm.arm.neon.sha1h(i32 %hash_e)
+ // CHECK: call i32 @llvm.{{arm.neon|arm64.crypto}}.sha1h(i32 %hash_e)
}
uint32x4_t test_vsha1su1q_u32(uint32x4_t w0_3, uint32x4_t w12_15) {
// CHECK-LABEL: @test_vsha1su1q_u32
return vsha1su1q_u32(w0_3, w12_15);
- // CHECK: call <4 x i32> @llvm.arm.neon.sha1su1(<4 x i32> %w0_3, <4 x i32> %w12_15)
+ // CHECK: call <4 x i32> @llvm.{{arm.neon|arm64.crypto}}.sha1su1(<4 x i32> %w0_3, <4 x i32> %w12_15)
}
uint32x4_t test_vsha256su0q_u32(uint32x4_t w0_3, uint32x4_t w4_7) {
// CHECK-LABEL: @test_vsha256su0q_u32
return vsha256su0q_u32(w0_3, w4_7);
- // CHECK: call <4 x i32> @llvm.arm.neon.sha256su0(<4 x i32> %w0_3, <4 x i32> %w4_7)
+ // CHECK: call <4 x i32> @llvm.{{arm.neon|arm64.crypto}}.sha256su0(<4 x i32> %w0_3, <4 x i32> %w4_7)
}
uint32x4_t test_vsha1cq_u32(uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk) {
// CHECK-LABEL: @test_vsha1cq_u32
return vsha1cq_u32(hash_abcd, hash_e, wk);
- // CHECK: call <4 x i32> @llvm.arm.neon.sha1c(<4 x i32> %hash_abcd, i32 %hash_e, <4 x i32> %wk)
+ // CHECK: call <4 x i32> @llvm.{{arm.neon|arm64.crypto}}.sha1c(<4 x i32> %hash_abcd, i32 %hash_e, <4 x i32> %wk)
}
uint32x4_t test_vsha1pq_u32(uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk) {
// CHECK-LABEL: @test_vsha1pq_u32
return vsha1pq_u32(hash_abcd, hash_e, wk);
- // CHECK: call <4 x i32> @llvm.arm.neon.sha1p(<4 x i32> %hash_abcd, i32 %hash_e, <4 x i32> %wk)
+ // CHECK: call <4 x i32> @llvm.{{arm.neon|arm64.crypto}}.sha1p(<4 x i32> %hash_abcd, i32 %hash_e, <4 x i32> %wk)
}
uint32x4_t test_vsha1mq_u32(uint32x4_t hash_abcd, uint32_t hash_e, uint32x4_t wk) {
// CHECK-LABEL: @test_vsha1mq_u32
return vsha1mq_u32(hash_abcd, hash_e, wk);
- // CHECK: call <4 x i32> @llvm.arm.neon.sha1m(<4 x i32> %hash_abcd, i32 %hash_e, <4 x i32> %wk)
+ // CHECK: call <4 x i32> @llvm.{{arm.neon|arm64.crypto}}.sha1m(<4 x i32> %hash_abcd, i32 %hash_e, <4 x i32> %wk)
}
uint32x4_t test_vsha1su0q_u32(uint32x4_t w0_3, uint32x4_t w4_7, uint32x4_t w8_11) {
// CHECK-LABEL: @test_vsha1su0q_u32
return vsha1su0q_u32(w0_3, w4_7, w8_11);
- // CHECK: call <4 x i32> @llvm.arm.neon.sha1su0(<4 x i32> %w0_3, <4 x i32> %w4_7, <4 x i32> %w8_11)
+ // CHECK: call <4 x i32> @llvm.{{arm.neon|arm64.crypto}}.sha1su0(<4 x i32> %w0_3, <4 x i32> %w4_7, <4 x i32> %w8_11)
}
uint32x4_t test_vsha256hq_u32(uint32x4_t hash_abcd, uint32x4_t hash_efgh, uint32x4_t wk) {
// CHECK-LABEL: @test_vsha256hq_u32
return vsha256hq_u32(hash_abcd, hash_efgh, wk);
- // CHECK: call <4 x i32> @llvm.arm.neon.sha256h(<4 x i32> %hash_abcd, <4 x i32> %hash_efgh, <4 x i32> %wk)
+ // CHECK: call <4 x i32> @llvm.{{arm.neon|arm64.crypto}}.sha256h(<4 x i32> %hash_abcd, <4 x i32> %hash_efgh, <4 x i32> %wk)
}
uint32x4_t test_vsha256h2q_u32(uint32x4_t hash_efgh, uint32x4_t hash_abcd, uint32x4_t wk) {
// CHECK-LABEL: @test_vsha256h2q_u32
return vsha256h2q_u32(hash_efgh, hash_abcd, wk);
- // CHECK: call <4 x i32> @llvm.arm.neon.sha256h2(<4 x i32> %hash_efgh, <4 x i32> %hash_abcd, <4 x i32> %wk)
+ // CHECK: call <4 x i32> @llvm.{{arm.neon|arm64.crypto}}.sha256h2(<4 x i32> %hash_efgh, <4 x i32> %hash_abcd, <4 x i32> %wk)
}
uint32x4_t test_vsha256su1q_u32(uint32x4_t w0_3, uint32x4_t w8_11, uint32x4_t w12_15) {
// CHECK-LABEL: @test_vsha256su1q_u32
return vsha256su1q_u32(w0_3, w8_11, w12_15);
- // CHECK: call <4 x i32> @llvm.arm.neon.sha256su1(<4 x i32> %w0_3, <4 x i32> %w8_11, <4 x i32> %w12_15)
+ // CHECK: call <4 x i32> @llvm.{{arm.neon|arm64.crypto}}.sha256su1(<4 x i32> %w0_3, <4 x i32> %w8_11, <4 x i32> %w12_15)
}
diff --git a/test/CodeGen/predefined-expr.c b/test/CodeGen/predefined-expr.c
index 3471dcdaa2..6c94152b73 100644
--- a/test/CodeGen/predefined-expr.c
+++ b/test/CodeGen/predefined-expr.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -fms-extensions %s -emit-llvm -o - | FileCheck %s
// CHECK: @__func__.plainFunction = private unnamed_addr constant [14 x i8] c"plainFunction\00"
// CHECK: @__PRETTY_FUNCTION__.plainFunction = private unnamed_addr constant [21 x i8] c"void plainFunction()\00"
diff --git a/test/CodeGen/sections.c b/test/CodeGen/sections.c
index 7994acf4dc..8d93fed480 100644
--- a/test/CodeGen/sections.c
+++ b/test/CodeGen/sections.c
@@ -1,28 +1,51 @@
-// REQUIRES: x86-registered-target
+// RUN: %clang_cc1 -emit-llvm -fms-extensions -xc++ -o - < %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -o - < %s | FileCheck %s --check-prefix=PLAIN
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -ffunction-sections -fno-function-sections -o - < %s | FileCheck %s --check-prefix=PLAIN
+#ifdef __cplusplus
+extern "C" {
+#endif
+#pragma const_seg(".my_const")
+#pragma bss_seg(".my_bss")
+int D = 1;
+#pragma data_seg(".data")
+int a = 1;
+#pragma data_seg(push, label, ".data2")
+extern const int b;
+const int b = 1;
+const char* s = "my string!";
+#pragma data_seg(push, ".my_seg")
+int c = 1;
+#pragma data_seg(pop, label)
+int d = 1;
+int e;
+#pragma bss_seg(".c")
+int f;
+void g(void){}
+#pragma code_seg(".my_code")
+void h(void){}
+#pragma bss_seg()
+int i;
+#pragma bss_seg(".bss1")
+#pragma bss_seg(push, test, ".bss2")
+#pragma bss_seg()
+#pragma bss_seg()
+int TEST1;
+#pragma bss_seg(pop)
+int TEST2;
+#ifdef __cplusplus
+}
+#endif
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -ffunction-sections -o - < %s | FileCheck %s --check-prefix=FUNC_SECT
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fno-function-sections -ffunction-sections -o - < %s | FileCheck %s --check-prefix=FUNC_SECT
-
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fdata-sections -o - < %s | FileCheck %s --check-prefix=DATA_SECT
-// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fno-data-sections -fdata-sections -o - < %s | FileCheck %s --check-prefix=DATA_SECT
-
-const int hello = 123;
-void world() {}
-
-// PLAIN-NOT: section
-// PLAIN: world:
-// PLAIN: section .rodata,
-// PLAIN: hello:
-
-// FUNC_SECT: section .text.world,
-// FUNC_SECT: world:
-// FUNC_SECT: section .rodata,
-// FUNC_SECT: hello:
-
-// DATA_SECT-NOT: section
-// DATA_SECT: world:
-// DATA_SECT: .section .rodata.hello,
-// DATA_SECT: hello:
+//CHECK: @D = global i32 1
+//CHECK: @a = global i32 1, section ".data"
+//CHECK: @b = constant i32 1, section ".my_const"
+//CHECK: @[[MYSTR:.*]] = {{.*}} unnamed_addr constant [11 x i8] c"my string!\00"
+//CHECK: @s = global i8* getelementptr inbounds ([11 x i8]* @[[MYSTR]], i32 0, i32 0), section ".data2"
+//CHECK: @c = global i32 1, section ".my_seg"
+//CHECK: @d = global i32 1, section ".data"
+//CHECK: @e = global i32 0, section ".my_bss"
+//CHECK: @f = global i32 0, section ".c"
+//CHECK: @i = global i32 0
+//CHECK: @TEST1 = global i32 0
+//CHECK: @TEST2 = global i32 0, section ".bss1"
+//CHECK: define void @g()
+//CHECK: define void @h() {{.*}} section ".my_code"
diff --git a/test/CodeGen/split-stacks.c b/test/CodeGen/split-stacks.c
new file mode 100644
index 0000000000..98112467a5
--- /dev/null
+++ b/test/CodeGen/split-stacks.c
@@ -0,0 +1,18 @@
+// RUN: %clang -target x86_64-linux-gnu -fsplit-stack -S %s -emit-llvm -o - | FileCheck -check-prefix=CHECK-SEGSTK %s
+// RUN: %clang -target x86_64-linux-gnu -S %s -emit-llvm -o - | FileCheck -check-prefix=CHECK-NOSEGSTK %s
+
+int foo() {
+ return 0;
+}
+
+int main() {
+ return foo();
+}
+
+// CHECK-SEGSTK: define i32 @foo() #0 {
+// CHECK-SEGSTK: define i32 @main() #0 {
+// CHECK-SEGSTK: #0 = { {{.*}} "split-stack" {{.*}} }
+
+// CHECK-NOSEGSTK: define i32 @foo() #0 {
+// CHECK-NOSEGSTK: define i32 @main() #0 {
+// CHECK-NOSEGSTK-NOT: #0 = { {{.*}} "split-stack" {{.*}} }
diff --git a/test/CodeGen/varargs.c b/test/CodeGen/varargs.c
index b6973d8337..3e2cce0793 100644
--- a/test/CodeGen/varargs.c
+++ b/test/CodeGen/varargs.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
-
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s
// PR6433 - Don't crash on va_arg(typedef).
typedef double gdouble;
@@ -15,3 +14,10 @@ void function_as_vararg() {
// CHECK-NOT: llvm.trap
vararg(0, focus_changed_cb);
}
+
+void vla(int n, ...)
+{
+ __builtin_va_list ap;
+ void *p;
+ p = __builtin_va_arg(ap, typeof (int (*)[++n])); // CHECK: add nsw i32 {{.*}}, 1
+}
diff --git a/test/CodeGenCUDA/launch-bounds.cu b/test/CodeGenCUDA/launch-bounds.cu
new file mode 100644
index 0000000000..3f88aeb7e7
--- /dev/null
+++ b/test/CodeGenCUDA/launch-bounds.cu
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 %s -triple nvptx-unknown-unknown -fcuda-is-device -emit-llvm -o - | FileCheck %s
+
+#include "../SemaCUDA/cuda.h"
+
+#define MAX_THREADS_PER_BLOCK 256
+#define MIN_BLOCKS_PER_MP 2
+
+// Test both max threads per block and Min cta per sm.
+extern "C" {
+__global__ void
+__launch_bounds__( MAX_THREADS_PER_BLOCK, MIN_BLOCKS_PER_MP )
+Kernel1()
+{
+}
+}
+
+// CHECK: !{{[0-9]+}} = metadata !{void ()* @Kernel1, metadata !"maxntidx", i32 256}
+// CHECK: !{{[0-9]+}} = metadata !{void ()* @Kernel1, metadata !"minctasm", i32 2}
+
+// Test only max threads per block. Min cta per sm defaults to 0, and
+// CodeGen doesn't output a zero value for minctasm.
+extern "C" {
+__global__ void
+__launch_bounds__( MAX_THREADS_PER_BLOCK )
+Kernel2()
+{
+}
+}
+
+// CHECK: !{{[0-9]+}} = metadata !{void ()* @Kernel2, metadata !"maxntidx", i32 256}
diff --git a/test/CodeGenCXX/aarch64-cxxabi.cpp b/test/CodeGenCXX/aarch64-cxxabi.cpp
index 04d9493ae6..c7d910d5f0 100644
--- a/test/CodeGenCXX/aarch64-cxxabi.cpp
+++ b/test/CodeGenCXX/aarch64-cxxabi.cpp
@@ -40,8 +40,8 @@ public:
void guard_variables(int a) {
static Guarded mine(a);
-// CHECK: [[GUARDBIT:%[0-9]+]] = and i64 {{%[0-9]+}}, 1
-// CHECK: icmp eq i64 [[GUARDBIT]], 0
+// CHECK: [[GUARDBIT:%[0-9]+]] = and i8 {{%[0-9]+}}, 1
+// CHECK: icmp eq i8 [[GUARDBIT]], 0
// As guards are 64-bit, these helpers should take 64-bit pointers.
// CHECK: call i32 @__cxa_guard_acquire(i64*
diff --git a/test/CodeGenCXX/aarch64-neon.cpp b/test/CodeGenCXX/aarch64-neon.cpp
index 5d2a00bebe..5f7c63a614 100644
--- a/test/CodeGenCXX/aarch64-neon.cpp
+++ b/test/CodeGenCXX/aarch64-neon.cpp
@@ -9,5 +9,5 @@
poly64x1_t test_vld1_p64(poly64_t const * ptr) {
// CHECK: test_vld1_p64
return vld1_p64(ptr);
- // CHECK: ld1 {{{v[0-9]+}}.1d}, [{{x[0-9]+|sp}}]
+ // CHECK: ld1 { {{v[0-9]+}}.1d }, [{{x[0-9]+|sp}}]
}
diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp
index 2790199446..b8d95991e2 100644
--- a/test/CodeGenCXX/arm.cpp
+++ b/test/CodeGenCXX/arm.cpp
@@ -292,9 +292,9 @@ namespace test7 {
// CHECK-LABEL: define void @_ZN5test74testEv()
void test() {
- // CHECK: [[T0:%.*]] = load i32* @_ZGVZN5test74testEvE1x
- // CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], 1
- // CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T1]], 0
+ // CHECK: [[T0:%.*]] = load atomic i8* bitcast (i32* @_ZGVZN5test74testEvE1x to i8*) acquire, align 1
+ // CHECK-NEXT: [[T1:%.*]] = and i8 [[T0]], 1
+ // CHECK-NEXT: [[T2:%.*]] = icmp eq i8 [[T1]], 0
// CHECK-NEXT: br i1 [[T2]]
// -> fallthrough, end
// CHECK: [[T3:%.*]] = call i32 @__cxa_guard_acquire(i32* @_ZGVZN5test74testEvE1x)
@@ -327,9 +327,9 @@ namespace test8 {
// CHECK-LABEL: define void @_ZN5test84testEv()
void test() {
- // CHECK: [[T0:%.*]] = load i32* @_ZGVZN5test84testEvE1x
- // CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], 1
- // CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T1]], 0
+ // CHECK: [[T0:%.*]] = load atomic i8* bitcast (i32* @_ZGVZN5test84testEvE1x to i8*) acquire, align 1
+ // CHECK-NEXT: [[T1:%.*]] = and i8 [[T0]], 1
+ // CHECK-NEXT: [[T2:%.*]] = icmp eq i8 [[T1]], 0
// CHECK-NEXT: br i1 [[T2]]
// -> fallthrough, end
// CHECK: [[T3:%.*]] = call i32 @__cxa_guard_acquire(i32* @_ZGVZN5test84testEvE1x)
diff --git a/test/CodeGenCXX/class-layout.cpp b/test/CodeGenCXX/class-layout.cpp
index 1f6212949f..c6aaf0f046 100644
--- a/test/CodeGenCXX/class-layout.cpp
+++ b/test/CodeGenCXX/class-layout.cpp
@@ -91,3 +91,12 @@ namespace Test7 {
B* b;
#pragma pack ()
}
+
+// Shouldn't crash.
+namespace Test8 {
+ struct A {};
+ struct D { int a; };
+ struct B : virtual D, A { };
+ struct C : B, A { void f() {} };
+ C c;
+}
diff --git a/test/CodeGenCXX/debug-info-alias.cpp b/test/CodeGenCXX/debug-info-alias.cpp
new file mode 100644
index 0000000000..e354ef0a73
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-alias.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang -g -std=c++11 -S -emit-llvm %s -o - | FileCheck %s
+
+template<typename T>
+struct foo {
+};
+namespace x {
+// splitting these over multiple lines to make sure the right token is used for
+// the location
+template<typename T>
+using
+# 42
+bar
+= foo<T*>;
+}
+
+// CHECK: metadata [[BINT:![0-9]*]], i32 0, i32 1, {{.*}} ; [ DW_TAG_variable ] [bi]
+// CHECK: [[BINT]] = {{.*}} ; [ DW_TAG_typedef ] [bar<int>] [line 42
+x::bar<int> bi;
+// CHECK: metadata [[BFLOAT:![0-9]*]], i32 0, i32 1, {{.*}} ; [ DW_TAG_variable ] [bf]
+// CHECK: [[BFLOAT]] = {{.*}} ; [ DW_TAG_typedef ] [bar<float>] [line 42
+x::bar<float> bf;
+
+using
+// metadata [[NARF:![0-9]*]], i32 0, i32 1, {{.*}} ; [ DW_TAG_variable ] [n]
+narf // [[NARF]] = {{.*}} ; [ DW_TAG_typedef ] [narf] [line [[@LINE]]
+= int;
+narf n;
+
diff --git a/test/CodeGenCXX/debug-info-anon-union-vars.cpp b/test/CodeGenCXX/debug-info-anon-union-vars.cpp
new file mode 100644
index 0000000000..396b7e94a8
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-anon-union-vars.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -emit-llvm -gdwarf-4 -triple x86_64-linux-gnu %s -o - | FileCheck %s
+
+// Make sure that we emit a global variable for each of the members of the
+// anonymous union.
+
+static union {
+ int c;
+ int d;
+ union {
+ int a;
+ };
+ struct {
+ int b;
+ };
+};
+
+int test_it() {
+ c = 1;
+ d = 2;
+ a = 4;
+ return (c == 1);
+}
+
+// CHECK: [[FILE:.*]] = {{.*}}[ DW_TAG_file_type ] [{{.*}}debug-info-anon-union-vars.cpp]
+// CHECK: [[FILE]]{{.*}}[ DW_TAG_variable ] [c] [line 6] [local] [def]
+// CHECK: [[FILE]]{{.*}}[ DW_TAG_variable ] [d] [line 6] [local] [def]
+// CHECK: [[FILE]]{{.*}}[ DW_TAG_variable ] [a] [line 6] [local] [def]
+// CHECK: [[FILE]]{{.*}}[ DW_TAG_variable ] [b] [line 6] [local] [def]
diff --git a/test/CodeGenCXX/debug-info-global.cpp b/test/CodeGenCXX/debug-info-global.cpp
new file mode 100644
index 0000000000..8dc30c8923
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-global.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple x86_64-none-linux-gnu -emit-llvm -g %s -o - | FileCheck %s
+
+// Multiple references to the same constant should result in only one entry in
+// the globals list.
+
+namespace ns {
+const int cnst = 42;
+}
+int f1() {
+ return ns::cnst + ns::cnst;
+}
+
+// CHECK: metadata [[GLOBALS:![0-9]*]], metadata {{![0-9]*}}, metadata !"{{.*}}", i32 {{[0-9]*}}} ; [ DW_TAG_compile_unit ]
+
+// CHECK: [[GLOBALS]] = metadata !{metadata [[CNST:![0-9]*]]}
+
+// CHECK: [[CNST]] = {{.*}}, metadata [[NS:![0-9]*]], metadata !"cnst", {{.*}}; [ DW_TAG_variable ] [cnst]
+// CHECK: [[NS]] = {{.*}}; [ DW_TAG_namespace ] [ns]
+
diff --git a/test/CodeGenCXX/debug-info-namespace.cpp b/test/CodeGenCXX/debug-info-namespace.cpp
index 473034cad5..2eb942e04a 100644
--- a/test/CodeGenCXX/debug-info-namespace.cpp
+++ b/test/CodeGenCXX/debug-info-namespace.cpp
@@ -57,7 +57,7 @@ using B::i;
// CHECK: [[MODULES]] = metadata !{metadata [[M1:![0-9]*]], metadata [[M2:![0-9]*]], metadata [[M3:![0-9]*]], metadata [[M4:![0-9]*]], metadata [[M5:![0-9]*]], metadata [[M6:![0-9]*]], metadata [[M7:![0-9]*]], metadata [[M8:![0-9]*]], metadata [[M9:![0-9]*]], metadata [[M10:![0-9]*]], metadata [[M11:![0-9]*]], metadata [[M12:![0-9]*]], metadata [[M13:![0-9]*]]}
// CHECK: [[M1]] = metadata !{i32 {{[0-9]*}}, metadata [[CTXT]], metadata [[NS]], i32 11} ; [ DW_TAG_imported_module ]
// CHECK: [[M2]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_module ]
-// CHECK: [[M3]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 15, metadata !"E"} ; [ DW_TAG_imported_module ]
+// CHECK: [[M3]] = metadata !{i32 {{[0-9]*}}, metadata [[CU]], metadata [[CTXT]], i32 15, metadata !"E"} ; [ DW_TAG_imported_declaration ]
// CHECK: [[M4]] = metadata !{i32 {{[0-9]*}}, metadata [[LEX2:![0-9]*]], metadata [[NS]], i32 19} ; [ DW_TAG_imported_module ]
// CHECK: [[LEX2]] = metadata !{i32 {{[0-9]*}}, metadata [[FILE2]], metadata [[LEX1:![0-9]+]], i32 {{[0-9]*}}, i32 0, i32 {{.*}}} ; [ DW_TAG_lexical_block ]
// CHECK: [[LEX1]] = metadata !{i32 {{[0-9]*}}, metadata [[FILE2]], metadata [[FUNC]], i32 {{[0-9]*}}, i32 0, i32 {{.*}}} ; [ DW_TAG_lexical_block ]
@@ -68,8 +68,8 @@ using B::i;
// CHECK: [[M9]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[I]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ]
// CHECK: [[M10]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[BAZ:![0-9]*]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ]
// CHECK: [[BAZ]] = metadata !{i32 {{[0-9]*}}, metadata [[FOOCPP]], metadata [[NS]], {{.*}}, metadata !"_ZTSN1A1B3barE"} ; [ DW_TAG_typedef ] [baz] {{.*}} [from _ZTSN1A1B3barE]
-// CHECK: [[M11]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[CTXT]], i32 {{[0-9]*}}, metadata !"X"} ; [ DW_TAG_imported_module ]
-// CHECK: [[M12]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[M11]], i32 {{[0-9]*}}, metadata !"Y"} ; [ DW_TAG_imported_module ]
+// CHECK: [[M11]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[CTXT]], i32 {{[0-9]*}}, metadata !"X"} ; [ DW_TAG_imported_declaration ]
+// CHECK: [[M12]] = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], metadata [[M11]], i32 {{[0-9]*}}, metadata !"Y"} ; [ DW_TAG_imported_declaration ]
// CHECK: [[M13]] = metadata !{i32 {{[0-9]*}}, metadata [[CTXT]], metadata [[I]], i32 {{[0-9]*}}} ; [ DW_TAG_imported_declaration ]
// CHECK-GMLT: [[CU:![0-9]*]] = {{.*}}[[MODULES:![0-9]*]], metadata !"", i32 2} ; [ DW_TAG_compile_unit ]
diff --git a/test/CodeGenCXX/debug-info-template-partial-specialization.cpp b/test/CodeGenCXX/debug-info-template-partial-specialization.cpp
new file mode 100644
index 0000000000..cce84af402
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-template-partial-specialization.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -g %s -o - -fstandalone-debug | FileCheck %s
+namespace __pointer_type_imp
+{
+ template <class _Tp, class _Dp, bool > struct __pointer_type1 {};
+
+ // CHECK: metadata ![[PARAMS:[0-9]+]], metadata !"_ZTSN18__pointer_type_imp15__pointer_type1I1C14default_deleteIS1_ELb0EEE"} ; [ DW_TAG_structure_type ] [__pointer_type1<C, default_delete<C>, false>] [line [[@LINE+1]], size 8, align 8, offset 0] [def] [from ]
+ template <class _Tp, class _Dp> struct __pointer_type1<_Tp, _Dp, false>
+ {
+ typedef _Tp* type;
+ };
+}
+template <class _Tp, class _Dp>
+struct __pointer_type2
+{
+ // Test that the bool template type parameter is emitted.
+ //
+ // CHECK: ![[PARAMS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata ![[FALSE:[0-9]+]]}
+ // CHECK: ![[FALSE]] = {{.*}} i8 0, {{.*}}} ; [ DW_TAG_template_value_parameter ]
+ typedef typename __pointer_type_imp::__pointer_type1<_Tp, _Dp, false>::type type;
+};
+template <class _Tp> struct default_delete {};
+template <class _Tp, class _Dp = default_delete<_Tp> > class unique_ptr
+{
+ typedef typename __pointer_type2<_Tp, _Dp>::type pointer;
+ unique_ptr(pointer __p, _Dp __d) {}
+};
+class C {
+ unique_ptr<C> Ptr;
+};
+void foo(C &c) {
+}
diff --git a/test/CodeGenCXX/debug-info.cpp b/test/CodeGenCXX/debug-info.cpp
index 2e7226d869..7c89dfc04c 100644
--- a/test/CodeGenCXX/debug-info.cpp
+++ b/test/CodeGenCXX/debug-info.cpp
@@ -51,11 +51,6 @@ namespace VirtualBase {
}
}
-void foo() {
- const wchar_t c = L'x';
- wchar_t d = c;
-}
-
namespace b5249287 {
template <typename T> class A {
struct B;
@@ -88,6 +83,13 @@ foo func(foo f) {
// CHECK: [[FUNC:![0-9]*]] = {{.*}} metadata !"_ZN7pr147634funcENS_3fooE", i32 {{[0-9]*}}, metadata [[FUNC_TYPE:![0-9]*]], {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [def] [func]
}
+void foo() {
+ const wchar_t c = L'x';
+ wchar_t d = c;
+}
+
+// CHECK-NOT: ; [ DW_TAG_variable ] [c]
+
namespace pr9608 { // also pr9600
struct incomplete;
incomplete (*x)[3];
@@ -96,9 +98,11 @@ incomplete (*x)[3];
// CHECK: [[INCARRAY]] = {{.*}}metadata !"_ZTSN6pr960810incompleteE", metadata {{![0-9]*}}, i32 0, null, null, null} ; [ DW_TAG_array_type ] [line 0, size 0, align 0, offset 0] [from _ZTSN6pr960810incompleteE]
}
-// For some reason the argument for PR14763 ended up all the way down here
+// For some reason function arguments ended up down here
// CHECK: = metadata !{i32 {{[0-9]*}}, metadata [[FUNC]], {{.*}}, metadata !"[[FOO]]", i32 8192, i32 0} ; [ DW_TAG_arg_variable ] [f]
+// CHECK: ; [ DW_TAG_auto_variable ] [c]
+
namespace pr16214 {
struct a {
int i;
diff --git a/test/CodeGenCXX/enable_if.cpp b/test/CodeGenCXX/enable_if.cpp
new file mode 100644
index 0000000000..00c55c7749
--- /dev/null
+++ b/test/CodeGenCXX/enable_if.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-linux-gnu| FileCheck %s
+// Test itanium mangling for attribute enable_if
+
+// CHECK: _Z5test1Ua9enable_ifIXeqfL0p_Li1EEEi
+void test1(int i) __attribute__((enable_if(i == 1, ""))) {}
+
+void ext();
+// CHECK: _Z5test2Ua9enable_ifIXneadL_Z3extvELi0EEEi
+void test2(int i) __attribute__((enable_if(&ext != 0, ""))) {}
+
+// CHECK: _Z5test3Ua9enable_ifIXeqfL0p_Li1EEXeqfL0p0_Li2EEEii
+void test3(int i, int j) __attribute__((enable_if(i == 1, ""), enable_if(j == 2, ""))) {}
+
+// CHECK: _ZN5test4IdE1fEUa9enable_ifIXeqfL0p_Li1EEXeqfL0p0_Li2EEEi
+template <typename T>
+class test4 {
+ virtual void f(int i, int j) __attribute__((enable_if(i == 1, ""))) __attribute__((enable_if(j == 2, "")));
+};
+
+template class test4<double>;
diff --git a/test/CodeGenCXX/explicit-instantiation.cpp b/test/CodeGenCXX/explicit-instantiation.cpp
index 6a4fd82212..5bd06784cf 100644
--- a/test/CodeGenCXX/explicit-instantiation.cpp
+++ b/test/CodeGenCXX/explicit-instantiation.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -std=c++1y -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-OPT
+// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -std=c++1y -O3 -disable-llvm-optzns -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-OPT
// This check logically is attached to 'template int S<int>::i;' below.
// CHECK: @_ZN1SIiE1iE = weak_odr global i32
@@ -16,6 +17,79 @@ Result plus<T, U, Result>::operator()(const T& t, const U& u) const {
// CHECK-LABEL: define weak_odr i32 @_ZNK4plusIillEclERKiRKl
template struct plus<int, long, long>;
+namespace EarlyInstantiation {
+ // Check that we emit definitions if we instantiate a function definition before
+ // it gets explicitly instantiatied.
+ template<typename T> struct S {
+ constexpr int constexpr_function() { return 0; }
+ auto deduced_return_type() { return 0; }
+ };
+
+ // From an implicit instantiation.
+ constexpr int a = S<char>().constexpr_function();
+ int b = S<char>().deduced_return_type();
+
+ // From an explicit instantiation declaration.
+ extern template struct S<int>;
+ constexpr int c = S<int>().constexpr_function();
+ int d = S<int>().deduced_return_type();
+
+ // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation1SIcE18constexpr_functionEv(
+ // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation1SIcE19deduced_return_typeEv(
+ // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation1SIiE18constexpr_functionEv(
+ // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation1SIiE19deduced_return_typeEv(
+ template struct S<char>;
+ template struct S<int>;
+
+ template<typename T> constexpr int constexpr_function() { return 0; }
+ template<typename T> auto deduced_return_type() { return 0; }
+
+ // From an implicit instantiation.
+ constexpr int e = constexpr_function<char>();
+ int f = deduced_return_type<char>();
+
+ // From an explicit instantiation declaration.
+ extern template int constexpr_function<int>();
+ extern template auto deduced_return_type<int>();
+ constexpr int g = constexpr_function<int>();
+ int h = deduced_return_type<int>();
+
+ // The FIXMEs below are for PR19551.
+ // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation18constexpr_functionIcEEiv(
+ // FIXME: define weak_odr i32 @_ZN18EarlyInstantiation19deduced_return_typeIcEEiv(
+ // CHECK: define weak_odr i32 @_ZN18EarlyInstantiation18constexpr_functionIiEEiv(
+ // FIXME: define weak_odr i32 @_ZN18EarlyInstantiation19deduced_return_typeIiEEiv(
+ template int constexpr_function<char>();
+ // FIXME template auto deduced_return_type<char>();
+ template int constexpr_function<int>();
+ // FIXME template auto deduced_return_type<int>();
+}
+
+namespace LateInstantiation {
+ // Check that we downgrade the linkage to available_externally if we see an
+ // explicit instantiation declaration after the function template is
+ // instantiated.
+ template<typename T> struct S { constexpr int f() { return 0; } };
+ template<typename T> constexpr int f() { return 0; }
+
+ // Trigger eager instantiation of the function definitions.
+ int a, b = S<char>().f() + f<char>() + a;
+ int c, d = S<int>().f() + f<int>() + a;
+
+ // Don't allow some of those definitions to be emitted.
+ extern template struct S<int>;
+ extern template int f<int>();
+
+ // Check that we declare, define, or provide an available-externally
+ // definition as appropriate.
+ // CHECK: define linkonce_odr i32 @_ZN17LateInstantiation1SIcE1fEv(
+ // CHECK: define linkonce_odr i32 @_ZN17LateInstantiation1fIcEEiv(
+ // CHECK-NO-OPT: declare i32 @_ZN17LateInstantiation1SIiE1fEv(
+ // CHECK-NO-OPT: declare i32 @_ZN17LateInstantiation1fIiEEiv(
+ // CHECK-OPT: define available_externally i32 @_ZN17LateInstantiation1SIiE1fEv(
+ // CHECK-OPT: define available_externally i32 @_ZN17LateInstantiation1fIiEEiv(
+}
+
// Check that we emit definitions from explicit instantiations even when they
// occur prior to the definition itself.
template <typename T> struct S {
diff --git a/test/CodeGenCXX/extern-c.cpp b/test/CodeGenCXX/extern-c.cpp
index 63bb177b84..fefb216ea1 100644
--- a/test/CodeGenCXX/extern-c.cpp
+++ b/test/CodeGenCXX/extern-c.cpp
@@ -66,3 +66,10 @@ extern "C" {
// CHECK-NOT: @unused
// CHECK-NOT: @duplicate_internal
}
+
+namespace PR19411 {
+ struct A { void f(); };
+ extern "C" void A::f() { void g(); g(); }
+ // CHECK-LABEL: @_ZN7PR194111A1fEv(
+ // CHECK: call void @g()
+}
diff --git a/test/CodeGenCXX/funcsig.cpp b/test/CodeGenCXX/funcsig.cpp
new file mode 100644
index 0000000000..684a796c19
--- /dev/null
+++ b/test/CodeGenCXX/funcsig.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=c++11 -triple i686-pc-win32 %s -fms-extensions -fno-rtti -emit-llvm -o - | FileCheck %s
+
+// Similar to predefined-expr.cpp, but not as exhaustive, since it's basically
+// equivalent to __PRETTY_FUNCTION__.
+
+extern "C" int printf(const char *, ...);
+
+void freeFunc(int *, char) {
+ printf("__FUNCSIG__ %s\n\n", __FUNCSIG__);
+}
+// CHECK: private unnamed_addr constant [{{.*}} x i8] c"void __cdecl freeFunc(int *, char)\00"
+
+struct TopLevelClass {
+ void topLevelMethod(int *, char);
+};
+void TopLevelClass::topLevelMethod(int *, char) {
+ printf("__FUNCSIG__ %s\n\n", __FUNCSIG__);
+}
+// CHECK: private unnamed_addr constant [{{.*}} x i8] c"void __thiscall TopLevelClass::topLevelMethod(int *, char)\00"
+
+namespace NS {
+struct NamespacedClass {
+ void namespacedMethod(int *, char);
+};
+void NamespacedClass::namespacedMethod(int *, char) {
+ printf("__FUNCSIG__ %s\n\n", __FUNCSIG__);
+}
+// CHECK: private unnamed_addr constant [{{.*}} x i8] c"void __thiscall NS::NamespacedClass::namespacedMethod(int *, char)\00"
+}
diff --git a/test/CodeGenCXX/globalinit-loc.cpp b/test/CodeGenCXX/globalinit-loc.cpp
new file mode 100644
index 0000000000..c6c27e379d
--- /dev/null
+++ b/test/CodeGenCXX/globalinit-loc.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -emit-llvm -g %s -o - | FileCheck %s
+// rdar://problem/14985269.
+//
+// Verify that the global init helper function does not get associated
+// with any source location.
+//
+// CHECK: define internal void @_GLOBAL__I_a
+// CHECK: !dbg ![[DBG:.*]]
+// CHECK: "_GLOBAL__I_a", i32 0, {{.*}}, i32 0} ; [ DW_TAG_subprogram ] [line 0] [local] [def]
+// CHECK: ![[DBG]] = metadata !{i32 0, i32 0,
+# 99 "someheader.h"
+class A {
+public:
+ A();
+ int foo() { return 0; }
+};
+# 5 "main.cpp"
+A a;
+
+int f() {
+ return a.foo();
+}
+
diff --git a/test/CodeGenCXX/mangle-ms-cxx11.cpp b/test/CodeGenCXX/mangle-ms-cxx11.cpp
index 3acd7a2100..c174e48c1d 100644
--- a/test/CodeGenCXX/mangle-ms-cxx11.cpp
+++ b/test/CodeGenCXX/mangle-ms-cxx11.cpp
@@ -119,3 +119,14 @@ inline int define_lambda() {
int call_lambda() {
return define_lambda();
}
+
+namespace PR19361 {
+struct A {
+ void foo() __restrict &;
+ void foo() __restrict &&;
+};
+void A::foo() __restrict & {}
+// CHECK-DAG: @"\01?foo@A@PR19361@@QIGAEXXZ"
+void A::foo() __restrict && {}
+// CHECK-DAG: @"\01?foo@A@PR19361@@QIHAEXXZ"
+}
diff --git a/test/CodeGenCXX/mangle-ms-templates-memptrs-2.cpp b/test/CodeGenCXX/mangle-ms-templates-memptrs-2.cpp
new file mode 100644
index 0000000000..993199acfd
--- /dev/null
+++ b/test/CodeGenCXX/mangle-ms-templates-memptrs-2.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -Wno-microsoft -fms-extensions -fno-rtti -std=c++11 -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s
+
+#pragma pointers_to_members(full_generality, virtual_inheritance)
+
+struct S {
+ int a, b;
+ void f();
+ virtual void g();
+};
+
+struct GeneralBase {
+ virtual void h();
+};
+struct MostGeneral : S, virtual GeneralBase {
+ virtual void h();
+};
+template <void (MostGeneral::*MP)()>
+struct ClassTemplate {
+ ClassTemplate() {}
+};
+
+template struct ClassTemplate<&MostGeneral::h>;
+
+// Test that we mangle in the vbptr offset, which is 12 here.
+//
+// CHECK: define weak_odr x86_thiscallcc %struct.ClassTemplate* @"\01??0?$ClassTemplate@$J??_9MostGeneral@@$BA@AEA@M@3@@QAE@XZ"
diff --git a/test/CodeGenCXX/mangle-neon-vectors.cpp b/test/CodeGenCXX/mangle-neon-vectors.cpp
index a9d0b8d83c..6faf6226ef 100644
--- a/test/CodeGenCXX/mangle-neon-vectors.cpp
+++ b/test/CodeGenCXX/mangle-neon-vectors.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple armv7-apple-ios -target-feature +neon %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-apple-ios %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -triple arm64-linux-gnu %s -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-AARCH64
+// RUN: %clang_cc1 -triple arm64-apple-ios -target-feature +neon %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-linux-gnu -target-feature +neon %s -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-AARCH64
typedef float float32_t;
typedef double float64_t;
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index ffb66361fc..c55e3e0f8a 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -951,3 +951,43 @@ namespace test44 {
}
// CHECK-LABEL: define linkonce_odr void @_ZN6test443foo3barEv(%"struct.test44::foo"* %this)
}
+
+namespace test45 {
+ struct S {
+ enum e {};
+ };
+ template <typename T>
+ void f(enum T::e *) {}
+ template void f<S>(S::e *);
+ // CHECK-LABEL: define weak_odr void @_ZN6test451fINS_1SEEEvPTeNT_1eE(i32*)
+}
+
+namespace test46 {
+ struct S {
+ struct s {};
+ };
+ template <typename T>
+ void f(struct T::s *) {}
+ template void f<S>(S::s *);
+ // CHECK-LABEL: define weak_odr void @_ZN6test461fINS_1SEEEvPTsNT_1sE(%"struct.test46::S::s"*)
+}
+
+namespace test47 {
+ struct S {
+ class c {};
+ };
+ template <typename T>
+ void f(class T::c *) {}
+ template void f<S>(S::c *);
+ // CHECK-LABEL: define weak_odr void @_ZN6test471fINS_1SEEEvPTsNT_1cE(%"class.test47::S::c"*)
+}
+
+namespace test48 {
+ struct S {
+ union u {};
+ };
+ template <typename T>
+ void f(union T::u *) {}
+ template void f<S>(S::u *);
+ // CHECK-LABEL: define weak_odr void @_ZN6test481fINS_1SEEEvPTuNT_1uE(%"union.test48::S::u"*)
+}
diff --git a/test/CodeGenCXX/microsoft-abi-nontrivial-memptr-thunks.cpp b/test/CodeGenCXX/microsoft-abi-nontrivial-memptr-thunks.cpp
new file mode 100644
index 0000000000..becec2d86f
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-nontrivial-memptr-thunks.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple=i386-pc-win32 %s -verify
+
+struct A {
+ A();
+ ~A();
+ int a;
+};
+struct B {
+ virtual void f(A); // expected-error {{cannot compile this non-trivial argument copy for thunk yet}}
+};
+void (B::*mp)(A) = &B::f;
diff --git a/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp b/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
index 3d5fe9c9a1..bc937491a5 100644
--- a/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
+++ b/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp
@@ -49,7 +49,7 @@ struct Big {
// WIN32: declare void @"{{.*take_bools_and_chars.*}}"
// WIN32: (<{ i8, [3 x i8], i8, [3 x i8], %struct.SmallWithDtor,
-// WIN32: i8, [3 x i8], i8, [3 x i8], i32, i8 }>* inalloca)
+// WIN32: i8, [3 x i8], i8, [3 x i8], i32, i8, [3 x i8] }>* inalloca)
void take_bools_and_chars(char a, char b, SmallWithDtor c, char d, bool e, int f, bool g);
void call_bools_and_chars() {
take_bools_and_chars('A', 'B', SmallWithDtor(), 'D', true, 13, false);
@@ -223,7 +223,7 @@ struct X {
};
void g(X) {
}
-// WIN32: define void @"\01?g@@YAXUX@@@Z"(<{ %struct.X }>* inalloca) {{.*}} {
+// WIN32: define void @"\01?g@@YAXUX@@@Z"(<{ %struct.X, [3 x i8] }>* inalloca) {{.*}} {
// WIN32: call x86_thiscallcc void @"\01??1X@@QAE@XZ"(%struct.X* {{.*}})
// WIN32: }
void f() {
@@ -264,6 +264,20 @@ void bar() {
}
+namespace test3 {
+
+// Check that we padded the inalloca struct to a multiple of 4.
+struct NonTrivial {
+ NonTrivial();
+ NonTrivial(const NonTrivial &o);
+ ~NonTrivial();
+ int a;
+};
+void foo(NonTrivial a, bool b) { }
+// WIN32-LABEL: define void @"\01?foo@test3@@YAXUNonTrivial@1@_N@Z"(<{ %"struct.test3::NonTrivial", i8, [3 x i8] }>* inalloca)
+
+}
+
// We would crash here because the later definition of ForwardDeclare1 results
// in a different IR type for the value we want to store. However, the alloca's
// type will use the argument type selected by fn1.
diff --git a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
index 021356e8fa..0d336cf42c 100644
--- a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
+++ b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -mconstructor-aliases -triple=i386-pc-win32 | FileCheck %s
+// RUN: %clang_cc1 -fms-extensions -emit-llvm %s -o - -mconstructor-aliases -triple=i386-pc-win32 | FileCheck %s
// CHECK: @llvm.global_ctors = appending global [2 x { i32, void ()* }]
// CHECK: [{ i32, void ()* } { i32 65535, void ()* @"\01??__Efoo@?$B@H@@2VA@@A@YAXXZ"
@@ -20,6 +20,17 @@ S s;
// CHECK: call x86_thiscallcc void @"\01??1S@@QAE@XZ"
// CHECK: ret void
+// These globals should use distinct guard variables, and not different bits of
+// the same global.
+__declspec(selectany) S selectany1;
+__declspec(selectany) S selectany2;
+// CHECK: define internal void @"\01??__Eselectany1@@YAXXZ"() [[NUW:#[0-9]+]]
+// CHECK: load i32* @"\01??_Bselectany1@@3US@@A@5"
+// CHECK: ret void
+// CHECK: define internal void @"\01??__Eselectany2@@YAXXZ"() [[NUW:#[0-9]+]]
+// CHECK: load i32* @"\01??_Bselectany2@@3US@@A@5"
+// CHECK: ret void
+
void StaticLocal() {
static S TheS;
}
diff --git a/test/CodeGenCXX/microsoft-abi-vbtables.cpp b/test/CodeGenCXX/microsoft-abi-vbtables.cpp
index b950d0cbf0..8b86d6bd3c 100644
--- a/test/CodeGenCXX/microsoft-abi-vbtables.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vbtables.cpp
@@ -518,3 +518,13 @@ F x;
// CHECK-DAG: @"\01??_8F@Test28@@7BD@1@@" =
// CHECK-DAG: @"\01??_8F@Test28@@7BE@1@@" =
}
+
+namespace Test29 {
+struct A {};
+struct B : virtual A {};
+struct C : virtual B {};
+struct D : C {};
+D d;
+
+// CHECK-DAG: @"\01??_8D@Test29@@7BB@1@@" = linkonce_odr unnamed_addr constant [2 x i32] zeroinitializer
+}
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-no-thunks.cpp b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-no-thunks.cpp
new file mode 100644
index 0000000000..86314cff32
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-no-thunks.cpp
@@ -0,0 +1,302 @@
+// RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t
+// RUN: FileCheck %s < %t
+// RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
+
+namespace test1 {
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void g();
+ // Add an extra virtual method so it's easier to check for the absence of thunks.
+ virtual void h();
+};
+
+struct X : A, B {
+ // CHECK-LABEL: VFTable for 'test1::A' in 'test1::X' (1 entry)
+ // CHECK-NEXT: 0 | void test1::X::f()
+
+ // CHECK-LABEL: VFTable for 'test1::B' in 'test1::X' (2 entries)
+ // CHECK-NEXT: 0 | void test1::B::g()
+ // CHECK-NEXT: 1 | void test1::B::h()
+
+ // CHECK-LABEL: VFTable indices for 'test1::X' (1 entry)
+ // CHECK-NEXT: 0 | void test1::X::f()
+
+ // MANGLING-DAG: @"\01??_7X@test1@@6BA@1@@"
+ // MANGLING-DAG: @"\01??_7X@test1@@6BB@1@@"
+
+ // Overrides only the left child's method (A::f), needs no thunks.
+ virtual void f();
+} x;
+
+void build_vftable(X *obj) { obj->f(); }
+}
+
+namespace test2 {
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void g();
+ virtual void h();
+};
+
+struct X : A, B {
+ // CHECK-LABEL: VFTable for 'test2::A' in 'test2::X' (1 entry)
+ // CHECK-NEXT: 0 | void test2::A::f()
+
+ // CHECK-LABEL: VFTable for 'test2::B' in 'test2::X' (2 entries)
+ // CHECK-NEXT: 0 | void test2::X::g()
+ // CHECK-NEXT: 1 | void test2::B::h()
+
+ // CHECK-LABEL: VFTable indices for 'test2::X' (1 entry).
+ // CHECK-NEXT: via vfptr at offset 4
+ // CHECK-NEXT: 0 | void test2::X::g()
+
+ // Overrides only the right child's method (B::g), needs this adjustment but
+ // not thunks.
+ virtual void g();
+};
+
+void build_vftable(X *obj) { obj->g(); }
+}
+
+namespace test3 {
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void g();
+ virtual void h();
+};
+
+struct X : A, B {
+ // CHECK-LABEL: VFTable for 'test3::A' in 'test3::X' (2 entries)
+ // CHECK-NEXT: 0 | void test3::A::f()
+ // CHECK-NEXT: 1 | void test3::X::i()
+
+ // CHECK-LABEL: VFTable for 'test3::B' in 'test3::X' (2 entries)
+ // CHECK-NEXT: 0 | void test3::B::g()
+ // CHECK-NEXT: 1 | void test3::B::h()
+
+ // CHECK-LABEL: VFTable indices for 'test3::X' (1 entry).
+ // CHECK-NEXT: 1 | void test3::X::i()
+
+ // Only adds a new method.
+ virtual void i();
+};
+
+void build_vftable(X *obj) { obj->i(); }
+}
+
+namespace test4 {
+struct A {
+ virtual void f();
+};
+
+struct Empty { }; // Doesn't have a vftable!
+
+// Only the right base has a vftable, so it's laid out before the left one!
+struct X : Empty, A {
+ // CHECK-LABEL: VFTable for 'test4::A' in 'test4::X' (1 entry)
+ // CHECK-NEXT: 0 | void test4::X::f()
+
+ // CHECK-LABEL: VFTable indices for 'test4::X' (1 entry).
+ // CHECK-NEXT: 0 | void test4::X::f()
+
+ // MANGLING-DAG: @"\01??_7X@test4@@6B@"
+
+ virtual void f();
+} x;
+
+void build_vftable(X *obj) { obj->f(); }
+}
+
+namespace test5 {
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void g();
+ virtual void h();
+};
+
+struct C : A, B {
+ virtual void f();
+};
+
+struct X : C {
+ // CHECK-LABEL: VFTable for 'test5::A' in 'test5::C' in 'test5::X' (1 entry).
+ // CHECK-NEXT: 0 | void test5::X::f()
+
+ // CHECK-LABEL: VFTable for 'test5::B' in 'test5::C' in 'test5::X' (2 entries).
+ // CHECK-NEXT: 0 | void test5::B::g()
+ // CHECK-NEXT: 1 | void test5::B::h()
+
+ // CHECK-LABEL: VFTable indices for 'test5::X' (1 entry).
+ // CHECK-NEXT: 0 | void test5::X::f()
+
+ // MANGLING-DAG: @"\01??_7X@test5@@6BA@1@@"
+ // MANGLING-DAG: @"\01??_7X@test5@@6BB@1@@"
+
+ // Overrides both C::f and A::f.
+ virtual void f();
+} x;
+
+void build_vftable(X *obj) { obj->f(); }
+}
+
+namespace test6 {
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void g();
+ virtual void h();
+};
+
+struct C : A, B {
+ virtual void g();
+};
+
+struct X : C {
+ // CHECK-LABEL: VFTable for 'test6::A' in 'test6::C' in 'test6::X' (1 entry).
+ // CHECK-NEXT: 0 | void test6::A::f()
+
+ // CHECK-LABEL: VFTable for 'test6::B' in 'test6::C' in 'test6::X' (2 entries).
+ // CHECK-NEXT: 0 | void test6::X::g()
+ // CHECK-NEXT: 1 | void test6::B::h()
+
+ // CHECK-LABEL: VFTable indices for 'test6::X' (1 entry).
+ // CHECK-NEXT: via vfptr at offset 4
+ // CHECK-NEXT: 0 | void test6::X::g()
+
+ // Overrides both C::g and B::g.
+ virtual void g();
+};
+
+void build_vftable(X *obj) { obj->g(); }
+}
+
+namespace test7 {
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void g();
+ virtual void h();
+};
+
+struct C : A, B {
+ // Only adds a new method.
+ virtual void i();
+};
+
+struct X : C {
+ // CHECK-LABEL: VFTable for 'test7::A' in 'test7::C' in 'test7::X' (2 entries).
+ // CHECK-NEXT: 0 | void test7::A::f()
+ // CHECK-NEXT: 1 | void test7::C::i()
+
+ // CHECK-LABEL: VFTable for 'test7::B' in 'test7::C' in 'test7::X' (2 entries).
+ // CHECK-NEXT: 0 | void test7::X::g()
+ // CHECK-NEXT: 1 | void test7::B::h()
+
+ // CHECK-LABEL: VFTable indices for 'test7::X' (1 entry).
+ // CHECK-NEXT: via vfptr at offset 4
+ // CHECK-NEXT: 0 | void test7::X::g()
+
+ // Overrides grandparent's B::g.
+ virtual void g();
+};
+
+void build_vftable(X *obj) { obj->g(); }
+}
+
+namespace test8 {
+struct A {
+ virtual void f();
+};
+
+struct B : A {
+ virtual void g();
+};
+
+// There are two 'A' subobjects in this class.
+struct X : A, B {
+ // CHECK-LABEL: VFTable for 'test8::A' in 'test8::X' (2 entries).
+ // CHECK-NEXT: 0 | void test8::A::f()
+ // CHECK-NEXT: 1 | void test8::X::h()
+
+ // CHECK-LABEL: VFTable for 'test8::A' in 'test8::B' in 'test8::X' (2 entries).
+ // CHECK-NEXT: 0 | void test8::A::f()
+ // CHECK-NEXT: 1 | void test8::B::g()
+
+ // CHECK-LABEL: VFTable indices for 'test8::X' (1 entry).
+ // CHECK-NEXT: 1 | void test8::X::h()
+
+ // MANGLING-DAG: @"\01??_7X@test8@@6BA@1@@"
+ // MANGLING-DAG: @"\01??_7X@test8@@6BB@1@@"
+
+ virtual void h();
+} x;
+
+void build_vftable(X *obj) { obj->h(); }
+}
+
+namespace test9 {
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void g();
+ virtual void h();
+};
+
+struct C : A, B {
+ // Overrides only the left child's method (A::f).
+ virtual void f();
+};
+
+struct D : A, B {
+ // Overrides only the right child's method (B::g).
+ virtual void g();
+};
+
+// 2-level structure with repeating subobject types, but no thunks needed.
+struct X : C, D {
+ // CHECK-LABEL: VFTable for 'test9::A' in 'test9::C' in 'test9::X' (2 entries)
+ // CHECK-NEXT: 0 | void test9::C::f()
+ // CHECK-NEXT: 1 | void test9::X::z()
+
+ // CHECK-LABEL: VFTable for 'test9::B' in 'test9::C' in 'test9::X' (2 entries)
+ // CHECK-NEXT: 0 | void test9::B::g()
+ // CHECK-NEXT: 1 | void test9::B::h()
+
+ // CHECK-LABEL: VFTable for 'test9::A' in 'test9::D' in 'test9::X' (1 entry)
+ // CHECK-NEXT: 0 | void test9::A::f()
+
+ // CHECK-LABEL: VFTable for 'test9::B' in 'test9::D' in 'test9::X' (2 entries)
+ // CHECK-NEXT: 0 | void test9::D::g()
+ // CHECK-NEXT: 1 | void test9::B::h()
+
+ // CHECK-LABEL: VFTable indices for 'test9::X' (1 entry).
+ // CHECK-NEXT: 1 | void test9::X::z()
+
+ // MANGLING-DAG: @"\01??_7X@test9@@6BA@1@C@1@@"
+ // MANGLING-DAG: @"\01??_7X@test9@@6BA@1@D@1@@"
+ // MANGLING-DAG: @"\01??_7X@test9@@6BB@1@C@1@@"
+ // MANGLING-DAG: @"\01??_7X@test9@@6BB@1@D@1@@"
+
+ virtual void z();
+} x;
+
+void build_vftable(test9::X *obj) { obj->z(); }
+}
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-pure-virtual.cpp b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-pure-virtual.cpp
new file mode 100644
index 0000000000..76182a2e33
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-pure-virtual.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t
+// RUN: FileCheck %s < %t
+// RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
+
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void g() = 0;
+ virtual void h();
+};
+
+struct C : A, B {
+ // CHECK-LABEL: VFTable for 'A' in 'C' (1 entry)
+ // CHECK-NEXT: 0 | void A::f()
+
+ // CHECK-LABEL: VFTable for 'B' in 'C' (2 entries)
+ // CHECK-NEXT: 0 | void C::g()
+ // CHECK-NEXT: 1 | void B::h()
+
+ // CHECK-LABEL: VFTable indices for 'C' (1 entry).
+ // CHECK-NEXT: via vfptr at offset 4
+ // CHECK-NEXT: 0 | void C::g()
+
+ // MANGLING-DAG: @"\01??_7C@@6BA@@@"
+ // MANGLING-DAG: @"\01??_7C@@6BB@@@"
+
+ // Overrides only the right child's method (B::g),
+ // needs this adjustment but not thunks.
+ virtual void g();
+};
+
+C c;
+void build_vftable(C *obj) { obj->g(); }
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-return-adjustment.cpp b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-return-adjustment.cpp
new file mode 100644
index 0000000000..2d0bf63622
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-return-adjustment.cpp
@@ -0,0 +1,297 @@
+// RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t
+// RUN: FileCheck %s < %t
+// RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
+
+namespace test1 {
+struct A {
+ virtual void g();
+ // Add an extra virtual method so it's easier to check for the absence of thunks.
+ virtual void h();
+};
+
+struct B {
+ virtual void g();
+};
+
+// Overrides a method of two bases at the same time, thus needing thunks.
+struct C : A, B {
+ virtual void g();
+};
+
+struct D {
+ virtual B* foo();
+ virtual void z();
+};
+
+struct X : D {
+ // CHECK-LABEL: VFTable for 'test1::D' in 'test1::X' (3 entries).
+ // CHECK-NEXT: 0 | test1::C *test1::X::foo()
+ // CHECK-NEXT: [return adjustment (to type 'struct test1::B *'): 4 non-virtual]
+ // CHECK-NEXT: 1 | void test1::D::z()
+ // CHECK-NEXT: 2 | test1::C *test1::X::foo()
+
+ // CHECK-LABEL: Thunks for 'test1::C *test1::X::foo()' (1 entry).
+ // CHECK-NEXT: 0 | [return adjustment (to type 'struct test1::B *'): 4 non-virtual]
+
+ // CHECK-LABEL: VFTable indices for 'test1::X' (1 entry).
+ // CHECK-NEXT: 2 | test1::C *test1::X::foo()
+
+ // MANGLING-DAG: @"\01??_7X@test1@@6B@"
+
+ virtual C* foo();
+} x;
+
+void build_vftable(X *obj) { obj->foo(); }
+}
+
+namespace test2 {
+struct A {
+ virtual void g();
+ virtual void h();
+};
+
+struct B {
+ virtual void g();
+};
+
+struct C : A, B {
+ virtual void g();
+};
+
+struct D {
+ virtual B* foo();
+ virtual void z();
+};
+
+struct E : D {
+ virtual C* foo();
+};
+
+struct F : C { };
+
+struct X : E {
+ virtual F* foo();
+ // CHECK-LABEL: VFTable for 'test2::D' in 'test2::E' in 'test2::X' (4 entries).
+ // CHECK-NEXT: 0 | test2::F *test2::X::foo()
+ // CHECK-NEXT: [return adjustment (to type 'struct test2::B *'): 4 non-virtual]
+ // CHECK-NEXT: 1 | void test2::D::z()
+ // CHECK-NEXT: 2 | test2::F *test2::X::foo()
+ // CHECK-NEXT: [return adjustment (to type 'struct test2::C *'): 0 non-virtual]
+ // CHECK-NEXT: 3 | test2::F *test2::X::foo()
+
+ // CHECK-LABEL: Thunks for 'test2::F *test2::X::foo()' (2 entries).
+ // CHECK-NEXT: 0 | [return adjustment (to type 'struct test2::C *'): 0 non-virtual]
+ // CHECK-NEXT: 1 | [return adjustment (to type 'struct test2::B *'): 4 non-virtual]
+
+ // CHECK-LABEL: VFTable indices for 'test2::X' (1 entry).
+ // CHECK-NEXT: 3 | test2::F *test2::X::foo()
+};
+
+void build_vftable(X *obj) { obj->foo(); }
+}
+
+namespace test3 {
+struct A {
+ virtual void g();
+ virtual void h();
+};
+
+struct B {
+ virtual void g();
+};
+
+struct C : A, B {
+ virtual void g();
+};
+
+struct D {
+ virtual B* foo();
+ virtual void z();
+};
+
+struct E : D {
+ virtual C* foo();
+};
+
+struct F : A, C { };
+
+struct X : E {
+ // CHECK-LABEL: VFTable for 'test3::D' in 'test3::E' in 'test3::X' (4 entries).
+ // CHECK-NEXT: 0 | test3::F *test3::X::foo()
+ // CHECK-NEXT: [return adjustment (to type 'struct test3::B *'): 8 non-virtual]
+ // CHECK-NEXT: 1 | void test3::D::z()
+ // CHECK-NEXT: 2 | test3::F *test3::X::foo()
+ // CHECK-NEXT: [return adjustment (to type 'struct test3::C *'): 4 non-virtual]
+ // CHECK-NEXT: 3 | test3::F *test3::X::foo()
+
+ // CHECK-LABEL: Thunks for 'test3::F *test3::X::foo()' (2 entries).
+ // CHECK-NEXT: 0 | [return adjustment (to type 'struct test3::C *'): 4 non-virtual]
+ // CHECK-NEXT: 1 | [return adjustment (to type 'struct test3::B *'): 8 non-virtual]
+
+ // CHECK-LABEL: VFTable indices for 'test3::X' (1 entry).
+ // CHECK-NEXT: 3 | test3::F *test3::X::foo()
+
+ virtual F* foo();
+};
+
+void build_vftable(X *obj) { obj->foo(); }
+}
+
+namespace test4 {
+struct A {
+ virtual void g();
+ virtual void h();
+};
+
+struct B {
+ virtual void g();
+};
+
+struct C : A, B {
+ virtual void g();
+};
+
+struct D {
+ virtual B* foo();
+ virtual void z();
+};
+
+struct E : D {
+ virtual C* foo();
+};
+
+struct F : A, C { };
+
+struct X : D, E {
+ // CHECK-LABEL: VFTable for 'test4::D' in 'test4::X' (3 entries).
+ // CHECK-NEXT: 0 | test4::F *test4::X::foo()
+ // CHECK-NEXT: [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
+ // CHECK-NEXT: 1 | void test4::D::z()
+ // CHECK-NEXT: 2 | test4::F *test4::X::foo()
+
+ // CHECK-LABEL: Thunks for 'test4::F *test4::X::foo()' (1 entry).
+ // CHECK-NEXT: 0 | [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
+
+ // CHECK-LABEL: VFTable for 'test4::D' in 'test4::E' in 'test4::X' (4 entries).
+ // CHECK-NEXT: 0 | test4::F *test4::X::foo()
+ // CHECK-NEXT: [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+ // CHECK-NEXT: 1 | void test4::D::z()
+ // CHECK-NEXT: 2 | test4::F *test4::X::foo()
+ // CHECK-NEXT: [return adjustment (to type 'struct test4::C *'): 4 non-virtual]
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+ // CHECK-NEXT: 3 | test4::F *test4::X::foo()
+ // CHECK-NEXT: [return adjustment (to type 'struct test4::F *'): 0 non-virtual]
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+
+ // CHECK-LABEL: Thunks for 'test4::F *test4::X::foo()' (3 entries).
+ // CHECK-NEXT: 0 | [return adjustment (to type 'struct test4::F *'): 0 non-virtual]
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+ // CHECK-NEXT: 1 | [return adjustment (to type 'struct test4::C *'): 4 non-virtual]
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+ // CHECK-NEXT: 2 | [return adjustment (to type 'struct test4::B *'): 8 non-virtual]
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+
+ // CHECK-LABEL: VFTable indices for 'test4::X' (1 entry).
+ // CHECK-NEXT: 2 | test4::F *test4::X::foo()
+
+ virtual F* foo();
+};
+
+void build_vftable(X *obj) { obj->foo(); }
+}
+
+namespace test5 {
+struct A {
+ virtual void g();
+ virtual void h();
+};
+
+struct B {
+ virtual void g();
+};
+
+struct C : A, B {
+ virtual void g();
+};
+
+struct D {
+ virtual B* foo();
+ virtual void z();
+};
+
+struct X : A, D {
+ // CHECK-LABEL: VFTable for 'test5::A' in 'test5::X' (2 entries).
+ // CHECK-NEXT: 0 | void test5::A::g()
+ // CHECK-NEXT: 1 | void test5::A::h()
+
+ // CHECK-LABEL: VFTable for 'test5::D' in 'test5::X' (3 entries).
+ // CHECK-NEXT: 0 | test5::C *test5::X::foo()
+ // CHECK-NEXT: [return adjustment (to type 'struct test5::B *'): 4 non-virtual]
+ // CHECK-NEXT: 1 | void test5::D::z()
+ // CHECK-NEXT: 2 | test5::C *test5::X::foo()
+
+ // CHECK-LABEL: Thunks for 'test5::C *test5::X::foo()' (1 entry).
+ // CHECK-NEXT: 0 | [return adjustment (to type 'struct test5::B *'): 4 non-virtual]
+
+ // CHECK-LABEL: VFTable indices for 'test5::X' (1 entry).
+ // CHECK-NEXT: via vfptr at offset 4
+ // CHECK-NEXT: 2 | test5::C *test5::X::foo()
+
+ virtual C* foo();
+};
+
+void build_vftable(X *obj) { obj->foo(); }
+}
+
+namespace test6 {
+struct A {
+ virtual void g();
+ virtual void h();
+};
+
+struct B {
+ virtual void g();
+};
+
+struct C : A, B {
+ virtual void g();
+};
+
+struct D {
+ virtual B* foo();
+ virtual void z();
+};
+
+struct E : A, D {
+ virtual C* foo();
+};
+
+struct F : A, C { };
+
+struct X : E {
+ // CHECK-LABEL: VFTable for 'test6::A' in 'test6::E' in 'test6::X' (2 entries).
+ // CHECK-NEXT: 0 | void test6::A::g()
+ // CHECK-NEXT: 1 | void test6::A::h()
+
+ // CHECK-LABEL: VFTable for 'test6::D' in 'test6::E' in 'test6::X' (4 entries).
+ // CHECK-NEXT: 0 | test6::F *test6::X::foo()
+ // CHECK-NEXT: [return adjustment (to type 'struct test6::B *'): 8 non-virtual]
+ // CHECK-NEXT: 1 | void test6::D::z()
+ // CHECK-NEXT: 2 | test6::F *test6::X::foo()
+ // CHECK-NEXT: [return adjustment (to type 'struct test6::C *'): 4 non-virtual]
+ // CHECK-NEXT: 3 | test6::F *test6::X::foo()
+
+ // CHECK-LABEL: Thunks for 'test6::F *test6::X::foo()' (2 entries).
+ // CHECK-NEXT: 0 | [return adjustment (to type 'struct test6::C *'): 4 non-virtual]
+ // CHECK-NEXT: 1 | [return adjustment (to type 'struct test6::B *'): 8 non-virtual]
+
+ // CHECK-LABEL: VFTable indices for 'test6::X' (1 entry).
+ // CHECK-NEXT: -- accessible via vfptr at offset 4 --
+ // CHECK-NEXT: 3 | test6::F *test6::X::foo()
+
+ virtual F* foo();
+};
+
+void build_vftable(X *obj) { obj->foo(); }
+}
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-this-adjustment.cpp b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-this-adjustment.cpp
new file mode 100644
index 0000000000..957980aa95
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-this-adjustment.cpp
@@ -0,0 +1,140 @@
+// RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t
+// RUN: FileCheck %s < %t
+// RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
+
+namespace test1 {
+struct A {
+ virtual void g();
+ // Add an extra virtual method so it's easier to check for the absence of thunks.
+ virtual void h();
+};
+
+struct B {
+ virtual void g(); // Collides with A::g if both are bases of some class.
+};
+
+// Overrides methods of two bases at the same time, thus needing thunks.
+struct X : A, B {
+ // CHECK-LABEL: VFTable for 'test1::A' in 'test1::X' (2 entries).
+ // CHECK-NEXT: 0 | void test1::X::g()
+ // CHECK-NEXT: 1 | void test1::A::h()
+
+ // CHECK-LABEL: VFTable for 'test1::B' in 'test1::X' (1 entry).
+ // CHECK-NEXT: 0 | void test1::X::g()
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+
+ // CHECK-LABEL: Thunks for 'void test1::X::g()' (1 entry).
+ // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
+
+ // CHECK-LABEL: VFTable indices for 'test1::X' (1 entry).
+ // CHECK-NEXT: 0 | void test1::X::g()
+
+ // MANGLING-DAG: @"\01??_7X@test1@@6BA@1@@"
+ // MANGLING-DAG: @"\01??_7X@test1@@6BB@1@@"
+
+ virtual void g();
+} x;
+
+void build_vftable(X *obj) { obj->g(); }
+}
+
+namespace test2 {
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void g();
+ virtual void h();
+};
+
+struct C {
+ virtual void g();
+};
+
+struct X : A, B, C {
+ // CHECK-LABEL: VFTable for 'test2::A' in 'test2::X' (1 entry).
+ // CHECK-NEXT: 0 | void test2::A::f()
+
+ // CHECK-LABEL: VFTable for 'test2::B' in 'test2::X' (2 entries).
+ // CHECK-NEXT: 0 | void test2::X::g()
+ // CHECK-NEXT: 1 | void test2::B::h()
+
+ // CHECK-LABEL: VFTable for 'test2::C' in 'test2::X' (1 entry).
+ // CHECK-NEXT: 0 | void test2::X::g()
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+
+ // CHECK-LABEL: Thunks for 'void test2::X::g()' (1 entry).
+ // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
+
+ // CHECK-LABEL: VFTable indices for 'test2::X' (1 entry).
+ // CHECK-NEXT: via vfptr at offset 4
+ // CHECK-NEXT: 0 | void test2::X::g()
+
+ // MANGLING-DAG: @"\01??_7X@test2@@6BA@1@@"
+ // MANGLING-DAG: @"\01??_7X@test2@@6BB@1@@"
+ // MANGLING-DAG: @"\01??_7X@test2@@6BC@1@@"
+
+ virtual void g();
+} x;
+
+void build_vftable(X *obj) { obj->g(); }
+}
+
+namespace test3 {
+struct A {
+ virtual void f();
+};
+
+struct B {
+ virtual void g();
+ virtual void h();
+};
+
+struct C: A, B {
+ // Overrides only the left child's method (A::f), needs no thunks.
+ virtual void f();
+};
+
+struct D: A, B {
+ // Overrides only the right child's method (B::g),
+ // needs this adjustment but not thunks.
+ virtual void g();
+};
+
+// Overrides methods of two bases at the same time, thus needing thunks.
+struct X: C, D {
+ // CHECK-LABEL: VFTable for 'test3::A' in 'test3::C' in 'test3::X' (1 entry).
+ // CHECK-NEXT: 0 | void test3::X::f()
+
+ // CHECK-LABEL: VFTable for 'test3::B' in 'test3::C' in 'test3::X' (2 entries).
+ // CHECK-NEXT: 0 | void test3::X::g()
+ // CHECK-NEXT: 1 | void test3::B::h()
+
+ // CHECK-LABEL: VFTable for 'test3::A' in 'test3::D' in 'test3::X' (1 entry).
+ // CHECK-NEXT: 0 | void test3::X::f()
+ // CHECK-NEXT: [this adjustment: -8 non-virtual]
+
+ // CHECK-LABEL: Thunks for 'void test3::X::f()' (1 entry).
+ // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
+
+ // CHECK-LABEL: VFTable for 'test3::B' in 'test3::D' in 'test3::X' (2 entries).
+ // CHECK-NEXT: 0 | void test3::X::g()
+ // CHECK-NEXT: [this adjustment: -8 non-virtual]
+ // CHECK-NEXT: 1 | void test3::B::h()
+
+ // CHECK-LABEL: Thunks for 'void test3::X::g()' (1 entry).
+ // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
+
+ // CHECK-LABEL: VFTable indices for 'test3::X' (2 entries).
+ // CHECK-NEXT: via vfptr at offset 0
+ // CHECK-NEXT: 0 | void test3::X::f()
+ // CHECK-NEXT: via vfptr at offset 4
+ // CHECK-NEXT: 0 | void test3::X::g()
+
+ virtual void f();
+ virtual void g();
+} x;
+
+void build_vftable(X *obj) { obj->g(); }
+}
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-vdtors.cpp b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-vdtors.cpp
new file mode 100644
index 0000000000..a407766f8e
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-vdtors.cpp
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t
+// RUN: FileCheck %s < %t
+
+struct A {
+ virtual ~A();
+ virtual void z1();
+};
+
+struct B {
+ virtual ~B();
+};
+
+struct C : A, B {
+ // CHECK-LABEL: VFTable for 'A' in 'C' (2 entries).
+ // CHECK-NEXT: 0 | C::~C() [scalar deleting]
+ // CHECK-NEXT: 1 | void A::z1()
+
+ // CHECK-LABEL: VFTable for 'B' in 'C' (1 entry).
+ // CHECK-NEXT: 0 | C::~C() [scalar deleting]
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+
+ // CHECK-LABEL: Thunks for 'C::~C()' (1 entry).
+ // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
+
+ // CHECK-LABEL: VFTable indices for 'C' (1 entry).
+ // CHECK-NEXT: 0 | C::~C() [scalar deleting]
+ virtual ~C();
+};
+
+void build_vftable(C *obj) { delete obj; }
+
+struct D {
+ // No virtual destructor here!
+ virtual void z4();
+};
+
+struct E : D, B {
+ // Implicit virtual dtor here!
+
+ // CHECK-LABEL: VFTable for 'D' in 'E' (1 entry).
+ // CHECK-NEXT: 0 | void D::z4()
+
+ // CHECK-LABEL: VFTable for 'B' in 'E' (1 entry).
+ // CHECK-NEXT: 0 | E::~E() [scalar deleting]
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+
+ // CHECK-LABEL: Thunks for 'E::~E()' (1 entry).
+ // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
+
+ // CHECK-LABEL: VFTable indices for 'E' (1 entry).
+ // CHECK-NEXT: -- accessible via vfptr at offset 4 --
+ // CHECK-NEXT: 0 | E::~E() [scalar deleting]
+};
+
+void build_vftable(E *obj) { delete obj; }
+
+struct F : D, B {
+ // Implicit virtual dtor here!
+
+ // CHECK-LABEL: VFTable for 'D' in 'F' (1 entry).
+ // CHECK-NEXT: 0 | void D::z4()
+
+ // CHECK-LABEL: VFTable for 'B' in 'F' (1 entry).
+ // CHECK-NEXT: 0 | F::~F() [scalar deleting]
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+
+ // CHECK-LABEL: Thunks for 'F::~F()' (1 entry).
+ // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
+
+ // CHECK-LABEL: VFTable indices for 'F' (1 entry).
+ // CHECK-NEXT: -- accessible via vfptr at offset 4 --
+ // CHECK-NEXT: 0 | F::~F() [scalar deleting]
+};
+
+void build_vftable(F *obj) { delete obj; }
+
+struct G : F {
+ // CHECK-LABEL: VFTable for 'D' in 'F' in 'G' (1 entry).
+ // CHECK-NEXT: 0 | void D::z4()
+
+ // CHECK-LABEL: VFTable for 'B' in 'F' in 'G' (1 entry).
+ // CHECK-NEXT: 0 | G::~G() [scalar deleting]
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+
+ // CHECK-LABEL: Thunks for 'G::~G()' (1 entry).
+ // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
+
+ // CHECK-LABEL: VFTable indices for 'G' (1 entry).
+ // CHECK-NEXT: -- accessible via vfptr at offset 4 --
+ // CHECK-NEXT: 0 | G::~G() [scalar deleting]
+ virtual ~G();
+};
+
+void build_vftable(G *obj) { delete obj; }
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp
deleted file mode 100644
index 39f2079017..0000000000
--- a/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance.cpp
+++ /dev/null
@@ -1,609 +0,0 @@
-// RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t
-// RUN: FileCheck %s < %t
-// RUN: FileCheck --check-prefix=MANGLING %s < %t.ll
-
-struct Empty {
- // Doesn't have a vftable!
-};
-
-struct A {
- virtual void f();
-};
-
-struct B {
- virtual void g();
- // Add an extra virtual method so it's easier to check for the absence of thunks.
- virtual void h();
-};
-
-struct C {
- virtual void g(); // Might "collide" with B::g if both are bases of some class.
-};
-
-
-namespace no_thunks {
-
-struct Test1: A, B {
- // CHECK-LABEL:Test1' (1 entry)
- // CHECK-NEXT: 0 | void no_thunks::Test1::f()
-
- // CHECK-LABEL:Test1' (2 entries)
- // CHECK-NEXT: 0 | void B::g()
- // CHECK-NEXT: 1 | void B::h()
-
- // CHECK-LABEL:Test1' (1 entry)
- // CHECK-NEXT: 0 | void no_thunks::Test1::f()
-
- // MANGLING-DAG: @"\01??_7Test1@no_thunks@@6BA@@@"
- // MANGLING-DAG: @"\01??_7Test1@no_thunks@@6BB@@@"
-
- // Overrides only the left child's method (A::f), needs no thunks.
- virtual void f();
-};
-
-Test1 t1;
-void use(Test1 *obj) { obj->f(); }
-
-struct Test2: A, B {
- // CHECK-LABEL: VFTable for 'A' in 'no_thunks::Test2' (1 entry)
- // CHECK-NEXT: 0 | void A::f()
-
- // CHECK-LABEL: VFTable for 'B' in 'no_thunks::Test2' (2 entries)
- // CHECK-NEXT: 0 | void no_thunks::Test2::g()
- // CHECK-NEXT: 1 | void B::h()
-
- // CHECK-LABEL: VFTable indices for 'no_thunks::Test2' (1 entry).
- // CHECK-NEXT: via vfptr at offset 4
- // CHECK-NEXT: 0 | void no_thunks::Test2::g()
-
- // Overrides only the right child's method (B::g), needs this adjustment but
- // not thunks.
- virtual void g();
-};
-
-Test2 t2;
-void use(Test2 *obj) { obj->g(); }
-
-struct Test3: A, B {
- // CHECK-LABEL: VFTable for 'A' in 'no_thunks::Test3' (2 entries)
- // CHECK-NEXT: 0 | void A::f()
- // CHECK-NEXT: 1 | void no_thunks::Test3::i()
-
- // CHECK-LABEL: VFTable for 'B' in 'no_thunks::Test3' (2 entries)
- // CHECK-NEXT: 0 | void B::g()
- // CHECK-NEXT: 1 | void B::h()
-
- // CHECK-LABEL: VFTable indices for 'no_thunks::Test3' (1 entry).
- // CHECK-NEXT: 1 | void no_thunks::Test3::i()
-
- // Only adds a new method.
- virtual void i();
-};
-
-Test3 t3;
-void use(Test3 *obj) { obj->i(); }
-
-// Only the right base has a vftable, so it's laid out before the left one!
-struct Test4 : Empty, A {
- // CHECK-LABEL: VFTable for 'A' in 'no_thunks::Test4' (1 entry)
- // CHECK-NEXT: 0 | void no_thunks::Test4::f()
-
- // CHECK-LABEL: VFTable indices for 'no_thunks::Test4' (1 entry).
- // CHECK-NEXT: 0 | void no_thunks::Test4::f()
-
- // MANGLING-DAG: @"\01??_7Test4@no_thunks@@6B@"
-
- virtual void f();
-};
-
-Test4 t4;
-void use(Test4 *obj) { obj->f(); }
-
-// 2-level structure with repeating subobject types, but no thunks needed.
-struct Test5: Test1, Test2 {
- // CHECK-LABEL: VFTable for 'A' in 'no_thunks::Test1' in 'no_thunks::Test5' (2 entries)
- // CHECK-NEXT: 0 | void no_thunks::Test1::f()
- // CHECK-NEXT: 1 | void no_thunks::Test5::z()
-
- // CHECK-LABEL: VFTable for 'B' in 'no_thunks::Test1' in 'no_thunks::Test5' (2 entries)
- // CHECK-NEXT: 0 | void B::g()
- // CHECK-NEXT: 1 | void B::h()
-
- // CHECK-LABEL: VFTable for 'A' in 'no_thunks::Test2' in 'no_thunks::Test5' (1 entry)
- // CHECK-NEXT: 0 | void A::f()
-
- // CHECK-LABEL: VFTable for 'B' in 'no_thunks::Test2' in 'no_thunks::Test5' (2 entries)
- // CHECK-NEXT: 0 | void no_thunks::Test2::g()
- // CHECK-NEXT: 1 | void B::h()
-
- // CHECK-LABEL: VFTable indices for 'no_thunks::Test5' (1 entry).
- // CHECK-NEXT: 1 | void no_thunks::Test5::z()
-
- // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BA@@Test1@1@@"
- // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BA@@Test2@1@@"
- // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BB@@Test1@1@@"
- // MANGLING-DAG: @"\01??_7Test5@no_thunks@@6BB@@Test2@1@@"
-
- virtual void z();
-};
-
-Test5 t5;
-void use(Test5 *obj) { obj->z(); }
-
-struct Test6: Test1 {
- // CHECK-LABEL: VFTable for 'A' in 'no_thunks::Test1' in 'no_thunks::Test6' (1 entry).
- // CHECK-NEXT: 0 | void no_thunks::Test6::f()
-
- // CHECK-LABEL: VFTable for 'B' in 'no_thunks::Test1' in 'no_thunks::Test6' (2 entries).
- // CHECK-NEXT: 0 | void B::g()
- // CHECK-NEXT: 1 | void B::h()
-
- // CHECK-LABEL: VFTable indices for 'no_thunks::Test6' (1 entry).
- // CHECK-NEXT: 0 | void no_thunks::Test6::f()
-
- // MANGLING-DAG: @"\01??_7Test6@no_thunks@@6BA@@@"
- // MANGLING-DAG: @"\01??_7Test6@no_thunks@@6BB@@@"
-
- // Overrides both no_thunks::Test1::f and A::f.
- virtual void f();
-};
-
-Test6 t6;
-void use(Test6 *obj) { obj->f(); }
-
-struct Test7: Test2 {
- // CHECK-LABEL: VFTable for 'A' in 'no_thunks::Test2' in 'no_thunks::Test7' (1 entry).
- // CHECK-NEXT: 0 | void A::f()
-
- // CHECK-LABEL: VFTable for 'B' in 'no_thunks::Test2' in 'no_thunks::Test7' (2 entries).
- // CHECK-NEXT: 0 | void no_thunks::Test7::g()
- // CHECK-NEXT: 1 | void B::h()
-
- // CHECK-LABEL: VFTable indices for 'no_thunks::Test7' (1 entry).
- // CHECK-NEXT: via vfptr at offset 4
- // CHECK-NEXT: 0 | void no_thunks::Test7::g()
-
- // Overrides both no_thunks::Test2::g and B::g.
- virtual void g();
-};
-
-Test7 t7;
-void use(Test7 *obj) { obj->g(); }
-
-struct Test8: Test3 {
- // CHECK-LABEL: VFTable for 'A' in 'no_thunks::Test3' in 'no_thunks::Test8' (2 entries).
- // CHECK-NEXT: 0 | void A::f()
- // CHECK-NEXT: 1 | void no_thunks::Test3::i()
-
- // CHECK-LABEL: VFTable for 'B' in 'no_thunks::Test3' in 'no_thunks::Test8' (2 entries).
- // CHECK-NEXT: 0 | void no_thunks::Test8::g()
- // CHECK-NEXT: 1 | void B::h()
-
- // CHECK-LABEL: VFTable indices for 'no_thunks::Test8' (1 entry).
- // CHECK-NEXT: via vfptr at offset 4
- // CHECK-NEXT: 0 | void no_thunks::Test8::g()
-
- // Overrides grandparent's B::g.
- virtual void g();
-};
-
-Test8 t8;
-void use(Test8 *obj) { obj->g(); }
-
-struct D : A {
- virtual void g();
-};
-
-// Repeating subobject.
-struct Test9: A, D {
- // CHECK-LABEL: VFTable for 'A' in 'no_thunks::Test9' (2 entries).
- // CHECK-NEXT: 0 | void A::f()
- // CHECK-NEXT: 1 | void no_thunks::Test9::h()
-
- // CHECK-LABEL: VFTable for 'A' in 'no_thunks::D' in 'no_thunks::Test9' (2 entries).
- // CHECK-NEXT: 0 | void A::f()
- // CHECK-NEXT: 1 | void no_thunks::D::g()
-
- // CHECK-LABEL: VFTable indices for 'no_thunks::Test9' (1 entry).
- // CHECK-NEXT: 1 | void no_thunks::Test9::h()
-
- // MANGLING-DAG: @"\01??_7Test9@no_thunks@@6BA@@@"
- // MANGLING-DAG: @"\01??_7Test9@no_thunks@@6BD@1@@"
-
- virtual void h();
-};
-
-Test9 t9;
-void use(Test9 *obj) { obj->h(); }
-}
-
-namespace pure_virtual {
-struct D {
- virtual void g() = 0;
- virtual void h();
-};
-
-
-struct Test1: A, D {
- // CHECK: VFTable for 'A' in 'pure_virtual::Test1' (1 entry)
- // CHECK-NEXT: 0 | void A::f()
-
- // CHECK: VFTable for 'pure_virtual::D' in 'pure_virtual::Test1' (2 entries)
- // CHECK-NEXT: 0 | void pure_virtual::Test1::g()
- // CHECK-NEXT: 1 | void pure_virtual::D::h()
-
- // CHECK: VFTable indices for 'pure_virtual::Test1' (1 entry).
- // CHECK-NEXT: via vfptr at offset 4
- // CHECK-NEXT: 0 | void pure_virtual::Test1::g()
-
- // MANGLING-DAG: @"\01??_7Test1@pure_virtual@@6BA@@@"
- // MANGLING-DAG: @"\01??_7Test1@pure_virtual@@6BD@1@@"
-
- // Overrides only the right child's method (pure_virtual::D::g), needs this adjustment but
- // not thunks.
- virtual void g();
-};
-
-Test1 t1;
-void use(Test1 *obj) { obj->g(); }
-}
-
-namespace this_adjustment {
-
-// Overrides methods of two bases at the same time, thus needing thunks.
-struct Test1 : B, C {
- // CHECK-LABEL: VFTable for 'B' in 'this_adjustment::Test1' (2 entries).
- // CHECK-NEXT: 0 | void this_adjustment::Test1::g()
- // CHECK-NEXT: 1 | void B::h()
-
- // CHECK-LABEL: VFTable for 'C' in 'this_adjustment::Test1' (1 entry).
- // CHECK-NEXT: 0 | void this_adjustment::Test1::g()
- // CHECK-NEXT: [this adjustment: -4 non-virtual]
-
- // CHECK-LABEL: Thunks for 'void this_adjustment::Test1::g()' (1 entry).
- // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
-
- // CHECK-LABEL: VFTable indices for 'this_adjustment::Test1' (1 entry).
- // CHECK-NEXT: 0 | void this_adjustment::Test1::g()
-
- // MANGLING-DAG: @"\01??_7Test1@this_adjustment@@6BB@@@"
- // MANGLING-DAG: @"\01??_7Test1@this_adjustment@@6BC@@@"
-
- virtual void g();
-};
-
-Test1 t1;
-void use(Test1 *obj) { obj->g(); }
-
-struct Test2 : A, B, C {
- // CHECK-LABEL: VFTable for 'A' in 'this_adjustment::Test2' (1 entry).
- // CHECK-NEXT: 0 | void A::f()
-
- // CHECK-LABEL: VFTable for 'B' in 'this_adjustment::Test2' (2 entries).
- // CHECK-NEXT: 0 | void this_adjustment::Test2::g()
- // CHECK-NEXT: 1 | void B::h()
-
- // CHECK-LABEL: VFTable for 'C' in 'this_adjustment::Test2' (1 entry).
- // CHECK-NEXT: 0 | void this_adjustment::Test2::g()
- // CHECK-NEXT: [this adjustment: -4 non-virtual]
-
- // CHECK-LABEL: Thunks for 'void this_adjustment::Test2::g()' (1 entry).
- // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
-
- // CHECK-LABEL: VFTable indices for 'this_adjustment::Test2' (1 entry).
- // CHECK-NEXT: via vfptr at offset 4
- // CHECK-NEXT: 0 | void this_adjustment::Test2::g()
-
- // MANGLING-DAG: @"\01??_7Test2@this_adjustment@@6BA@@@"
- // MANGLING-DAG: @"\01??_7Test2@this_adjustment@@6BB@@@"
- // MANGLING-DAG: @"\01??_7Test2@this_adjustment@@6BC@@@"
-
- virtual void g();
-};
-
-Test2 t2;
-void use(Test2 *obj) { obj->g(); }
-
-// Overrides methods of two bases at the same time, thus needing thunks.
-struct Test3: no_thunks::Test1, no_thunks::Test2 {
- // CHECK-LABEL: VFTable for 'A' in 'no_thunks::Test1' in 'this_adjustment::Test3' (1 entry).
- // CHECK-NEXT: 0 | void this_adjustment::Test3::f()
-
- // CHECK-LABEL: VFTable for 'B' in 'no_thunks::Test1' in 'this_adjustment::Test3' (2 entries).
- // CHECK-NEXT: 0 | void this_adjustment::Test3::g()
- // CHECK-NEXT: 1 | void B::h()
-
- // CHECK-LABEL: VFTable for 'A' in 'no_thunks::Test2' in 'this_adjustment::Test3' (1 entry).
- // CHECK-NEXT: 0 | void this_adjustment::Test3::f()
- // CHECK-NEXT: [this adjustment: -8 non-virtual]
-
- // CHECK-LABEL: Thunks for 'void this_adjustment::Test3::f()' (1 entry).
- // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
-
- // CHECK-LABEL: VFTable for 'B' in 'no_thunks::Test2' in 'this_adjustment::Test3' (2 entries).
- // CHECK-NEXT: 0 | void this_adjustment::Test3::g()
- // CHECK-NEXT: [this adjustment: -8 non-virtual]
- // CHECK-NEXT: 1 | void B::h()
-
- // CHECK-LABEL: Thunks for 'void this_adjustment::Test3::g()' (1 entry).
- // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
-
- // CHECK-LABEL: VFTable indices for 'this_adjustment::Test3' (2 entries).
- // CHECK-NEXT: via vfptr at offset 0
- // CHECK-NEXT: 0 | void this_adjustment::Test3::f()
- // CHECK-NEXT: via vfptr at offset 4
- // CHECK-NEXT: 0 | void this_adjustment::Test3::g()
-
- virtual void f();
- virtual void g();
-};
-
-Test3 t3;
-void use(Test3 *obj) { obj->g(); }
-}
-
-namespace vdtor {
-struct Test1 {
- virtual ~Test1();
- virtual void z1();
-};
-
-struct Test2 {
- virtual ~Test2();
-};
-
-struct Test3 : Test1, Test2 {
- // CHECK-LABEL: VFTable for 'vdtor::Test1' in 'vdtor::Test3' (2 entries).
- // CHECK-NEXT: 0 | vdtor::Test3::~Test3() [scalar deleting]
- // CHECK-NEXT: 1 | void vdtor::Test1::z1()
-
- // CHECK-LABEL: VFTable for 'vdtor::Test2' in 'vdtor::Test3' (1 entry).
- // CHECK-NEXT: 0 | vdtor::Test3::~Test3() [scalar deleting]
- // CHECK-NEXT: [this adjustment: -4 non-virtual]
-
- // CHECK-LABEL: Thunks for 'vdtor::Test3::~Test3()' (1 entry).
- // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
-
- // CHECK-LABEL: VFTable indices for 'vdtor::Test3' (1 entry).
- // CHECK-NEXT: 0 | vdtor::Test3::~Test3() [scalar deleting]
- virtual ~Test3();
-};
-
-Test3 t3;
-void use(Test3 *obj) { delete obj; }
-
-struct Test4 {
- // No virtual destructor here!
- virtual void z4();
-};
-
-struct Test5 : Test4, Test2 {
- // Implicit virtual dtor here!
-
- // CHECK-LABEL: VFTable for 'vdtor::Test4' in 'vdtor::Test5' (1 entry).
- // CHECK-NEXT: 0 | void vdtor::Test4::z4()
-
- // CHECK-LABEL: VFTable for 'vdtor::Test2' in 'vdtor::Test5' (1 entry).
- // CHECK-NEXT: 0 | vdtor::Test5::~Test5() [scalar deleting]
- // CHECK-NEXT: [this adjustment: -4 non-virtual]
-
- // CHECK-LABEL: Thunks for 'vdtor::Test5::~Test5()' (1 entry).
- // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
-
- // CHECK-LABEL: VFTable indices for 'vdtor::Test5' (1 entry).
- // CHECK-NEXT: -- accessible via vfptr at offset 4 --
- // CHECK-NEXT: 0 | vdtor::Test5::~Test5() [scalar deleting]
-};
-
-Test5 t5;
-void use(Test5 *obj) { delete obj; }
-
-struct Test6 : Test4, Test2 {
- // Implicit virtual dtor here!
-
- // CHECK-LABEL: VFTable for 'vdtor::Test4' in 'vdtor::Test6' (1 entry).
- // CHECK-NEXT: 0 | void vdtor::Test4::z4()
-
- // CHECK-LABEL: VFTable for 'vdtor::Test2' in 'vdtor::Test6' (1 entry).
- // CHECK-NEXT: 0 | vdtor::Test6::~Test6() [scalar deleting]
- // CHECK-NEXT: [this adjustment: -4 non-virtual]
-
- // CHECK-LABEL: Thunks for 'vdtor::Test6::~Test6()' (1 entry).
- // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
-
- // CHECK-LABEL: VFTable indices for 'vdtor::Test6' (1 entry).
- // CHECK-NEXT: -- accessible via vfptr at offset 4 --
- // CHECK-NEXT: 0 | vdtor::Test6::~Test6() [scalar deleting]
-};
-
-Test6 t6;
-void use(Test6 *obj) { delete obj; }
-
-struct Test7 : Test5 {
- // CHECK-LABEL: VFTable for 'vdtor::Test4' in 'vdtor::Test5' in 'vdtor::Test7' (1 entry).
- // CHECK-NEXT: 0 | void vdtor::Test4::z4()
-
- // CHECK-LABEL: VFTable for 'vdtor::Test2' in 'vdtor::Test5' in 'vdtor::Test7' (1 entry).
- // CHECK-NEXT: 0 | vdtor::Test7::~Test7() [scalar deleting]
- // CHECK-NEXT: [this adjustment: -4 non-virtual]
-
- // CHECK-LABEL: Thunks for 'vdtor::Test7::~Test7()' (1 entry).
- // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
-
- // CHECK-LABEL: VFTable indices for 'vdtor::Test7' (1 entry).
- // CHECK-NEXT: -- accessible via vfptr at offset 4 --
- // CHECK-NEXT: 0 | vdtor::Test7::~Test7() [scalar deleting]
- virtual ~Test7();
-};
-
-Test7 t7;
-void use(Test7 *obj) { delete obj; }
-
-}
-
-namespace return_adjustment {
-
-struct Ret1 {
- virtual C* foo();
- virtual void z();
-};
-
-struct Test1 : Ret1 {
- // CHECK-LABEL: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' (3 entries).
- // CHECK-NEXT: 0 | this_adjustment::Test1 *return_adjustment::Test1::foo()
- // CHECK-NEXT: [return adjustment (to type 'struct C *'): 4 non-virtual]
- // CHECK-NEXT: 1 | void return_adjustment::Ret1::z()
- // CHECK-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test1::foo()
-
- // CHECK-LABEL: Thunks for 'this_adjustment::Test1 *return_adjustment::Test1::foo()' (1 entry).
- // CHECK-NEXT: 0 | [return adjustment (to type 'struct C *'): 4 non-virtual]
-
- // CHECK-LABEL: VFTable indices for 'return_adjustment::Test1' (1 entry).
- // CHECK-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test1::foo()
-
- // MANGLING-DAG: @"\01??_7Test1@return_adjustment@@6B@"
-
- virtual this_adjustment::Test1* foo();
-};
-
-Test1 t1;
-void use(Test1 *obj) { obj->foo(); }
-
-struct Ret2 : B, this_adjustment::Test1 { };
-
-struct Test2 : Test1 {
- // CHECK-LABEL: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' in 'return_adjustment::Test2' (4 entries).
- // CHECK-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
- // CHECK-NEXT: [return adjustment (to type 'struct C *'): 8 non-virtual]
- // CHECK-NEXT: 1 | void return_adjustment::Ret1::z()
- // CHECK-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
- // CHECK-NEXT: [return adjustment (to type 'struct this_adjustment::Test1 *'): 4 non-virtual]
- // CHECK-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
-
- // CHECK-LABEL: Thunks for 'return_adjustment::Ret2 *return_adjustment::Test2::foo()' (2 entries).
- // CHECK-NEXT: 0 | [return adjustment (to type 'struct this_adjustment::Test1 *'): 4 non-virtual]
- // CHECK-NEXT: 1 | [return adjustment (to type 'struct C *'): 8 non-virtual]
-
- // CHECK-LABEL: VFTable indices for 'return_adjustment::Test2' (1 entry).
- // CHECK-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test2::foo()
-
- virtual Ret2* foo();
-};
-
-Test2 t2;
-void use(Test2 *obj) { obj->foo(); }
-
-struct Test3: B, Ret1 {
- // CHECK-LABEL: VFTable for 'B' in 'return_adjustment::Test3' (2 entries).
- // CHECK-NEXT: 0 | void B::g()
- // CHECK-NEXT: 1 | void B::h()
-
- // CHECK-LABEL: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test3' (3 entries).
- // CHECK-NEXT: 0 | this_adjustment::Test1 *return_adjustment::Test3::foo()
- // CHECK-NEXT: [return adjustment (to type 'struct C *'): 4 non-virtual]
- // CHECK-NEXT: 1 | void return_adjustment::Ret1::z()
- // CHECK-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test3::foo()
-
- // CHECK-LABEL: Thunks for 'this_adjustment::Test1 *return_adjustment::Test3::foo()' (1 entry).
- // CHECK-NEXT: 0 | [return adjustment (to type 'struct C *'): 4 non-virtual]
-
- // CHECK-LABEL: VFTable indices for 'return_adjustment::Test3' (1 entry).
- // CHECK-NEXT: via vfptr at offset 4
- // CHECK-NEXT: 2 | this_adjustment::Test1 *return_adjustment::Test3::foo()
-
- virtual this_adjustment::Test1* foo();
-};
-
-Test3 t3;
-void use(Test3 *obj) { obj->foo(); }
-
-struct Test4 : Test3 {
- // CHECK-LABEL: VFTable for 'B' in 'return_adjustment::Test3' in 'return_adjustment::Test4' (2 entries).
- // CHECK-NEXT: 0 | void B::g()
- // CHECK-NEXT: 1 | void B::h()
-
- // CHECK-LABEL: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test3' in 'return_adjustment::Test4' (4 entries).
- // CHECK-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
- // CHECK-NEXT: [return adjustment (to type 'struct C *'): 8 non-virtual]
- // CHECK-NEXT: 1 | void return_adjustment::Ret1::z()
- // CHECK-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
- // CHECK-NEXT: [return adjustment (to type 'struct this_adjustment::Test1 *'): 4 non-virtual]
- // CHECK-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
-
- // CHECK-LABEL: Thunks for 'return_adjustment::Ret2 *return_adjustment::Test4::foo()' (2 entries).
- // CHECK-NEXT: 0 | [return adjustment (to type 'struct this_adjustment::Test1 *'): 4 non-virtual]
- // CHECK-NEXT: 1 | [return adjustment (to type 'struct C *'): 8 non-virtual]
-
- // CHECK-LABEL: VFTable indices for 'return_adjustment::Test4' (1 entry).
- // CHECK-NEXT: -- accessible via vfptr at offset 4 --
- // CHECK-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test4::foo()
-
- virtual Ret2* foo();
-};
-
-Test4 t4;
-void use(Test4 *obj) { obj->foo(); }
-
-struct Test5 : Ret1, Test1 {
- // CHECK-LABEL: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test5' (3 entries).
- // CHECK-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
- // CHECK-NEXT: [return adjustment (to type 'struct C *'): 8 non-virtual]
- // CHECK-NEXT: 1 | void return_adjustment::Ret1::z()
- // CHECK-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
-
- // CHECK-LABEL: Thunks for 'return_adjustment::Ret2 *return_adjustment::Test5::foo()' (1 entry).
- // CHECK-NEXT: 0 | [return adjustment (to type 'struct C *'): 8 non-virtual]
-
- // CHECK-LABEL: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' in 'return_adjustment::Test5' (4 entries).
- // CHECK-NEXT: 0 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
- // CHECK-NEXT: [return adjustment (to type 'struct C *'): 8 non-virtual]
- // CHECK-NEXT: [this adjustment: -4 non-virtual]
- // CHECK-NEXT: 1 | void return_adjustment::Ret1::z()
- // CHECK-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
- // CHECK-NEXT: [return adjustment (to type 'struct this_adjustment::Test1 *'): 4 non-virtual]
- // CHECK-NEXT: [this adjustment: -4 non-virtual]
- // CHECK-NEXT: 3 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
- // CHECK-NEXT: [return adjustment (to type 'struct return_adjustment::Ret2 *'): 0 non-virtual]
- // CHECK-NEXT: [this adjustment: -4 non-virtual]
-
- // CHECK-LABEL: Thunks for 'return_adjustment::Ret2 *return_adjustment::Test5::foo()' (3 entries).
- // CHECK-NEXT: 0 | [return adjustment (to type 'struct return_adjustment::Ret2 *'): 0 non-virtual]
- // CHECK-NEXT: [this adjustment: -4 non-virtual]
- // CHECK-NEXT: 1 | [return adjustment (to type 'struct this_adjustment::Test1 *'): 4 non-virtual]
- // CHECK-NEXT: [this adjustment: -4 non-virtual]
- // CHECK-NEXT: 2 | [return adjustment (to type 'struct C *'): 8 non-virtual]
- // CHECK-NEXT: [this adjustment: -4 non-virtual]
-
- // CHECK-LABEL: VFTable indices for 'return_adjustment::Test5' (1 entry).
- // CHECK-NEXT: 2 | return_adjustment::Ret2 *return_adjustment::Test5::foo()
-
- virtual Ret2* foo();
-};
-
-Test5 t5;
-void use(Test5 *obj) { obj->foo(); }
-
-struct Ret3 : this_adjustment::Test1 { };
-
-struct Test6 : Test1 {
- virtual Ret3* foo();
- // CHECK-LABEL: VFTable for 'return_adjustment::Ret1' in 'return_adjustment::Test1' in 'return_adjustment::Test6' (4 entries).
- // CHECK-NEXT: 0 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
- // CHECK-NEXT: [return adjustment (to type 'struct C *'): 4 non-virtual]
- // CHECK-NEXT: 1 | void return_adjustment::Ret1::z()
- // CHECK-NEXT: 2 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
- // CHECK-NEXT: [return adjustment (to type 'struct this_adjustment::Test1 *'): 0 non-virtual]
- // CHECK-NEXT: 3 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
-
- // CHECK-LABEL: Thunks for 'return_adjustment::Ret3 *return_adjustment::Test6::foo()' (2 entries).
- // CHECK-NEXT: 0 | [return adjustment (to type 'struct this_adjustment::Test1 *'): 0 non-virtual]
- // CHECK-NEXT: 1 | [return adjustment (to type 'struct C *'): 4 non-virtual]
-
- // CHECK-LABEL: VFTable indices for 'return_adjustment::Test6' (1 entry).
- // CHECK-NEXT: 3 | return_adjustment::Ret3 *return_adjustment::Test6::foo()
-};
-
-Test6 t6;
-void use(Test6 *obj) { obj->foo(); }
-
-}
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp
index 6dac30eb9a..f63808a898 100644
--- a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp
@@ -157,6 +157,67 @@ struct C : virtual V4 {
C c;
void use(C *obj) { obj->f(); }
+
+class D : B {
+ // CHECK-LABEL: VFTable for 'V2' in 'V3' in 'simple::B' in 'simple::D' (2 entries).
+ // CHECK-NEXT: 0 | void simple::B::f()
+ // CHECK-NEXT: [this adjustment: vtordisp at -12, -4 non-virtual]
+ // CHECK-NEXT: 1 | simple::D::~D() [scalar deleting]
+ // CHECK-NEXT: [this adjustment: vtordisp at -12, -8 non-virtual]
+ D();
+ int z;
+
+ // MANGLING-DAG: @"\01?f@B@simple@@$4PPPPPPPE@3AEXXZ"
+};
+
+D::D() {}
+
+struct E : V3 {
+ virtual void f();
+};
+
+struct F : virtual E {
+ // CHECK-LABEL: VFTable for 'Z' in 'V3' in 'simple::E' in 'simple::F' (2 entries).
+ // CHECK-NEXT: 0 | void simple::F::g()
+ // CHECK-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
+ // CHECK-NEXT: 1 | simple::F::~F() [scalar deleting]
+ // CHECK-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
+
+ // CHECK-LABEL: VFTable for 'V2' in 'V3' in 'simple::E' in 'simple::F' (2 entries).
+ // CHECK-NEXT: 0 | void simple::E::f()
+ // CHECK-NEXT: 1 | simple::F::~F() [scalar deleting]
+ // CHECK-NEXT: [this adjustment: vtordisp at -12, -8 non-virtual]
+
+ F();
+ virtual void g(); // Force a vtordisp.
+ int f;
+
+ // MANGLING-DAG: @"\01?g@F@simple@@$4PPPPPPPM@A@AEXXZ"{{.*}}??_EF@simple@@$4PPPPPPPM@A@AEPAXI@Z
+ // MANGLING-DAG: ?f@E@simple@@UAEXXZ{{.*}}??_EF@simple@@$4PPPPPPPE@7AEPAXI@Z
+};
+
+F::F() {}
+
+struct G : F {
+ // CHECK-LABEL: VFTable for 'Z' in 'V3' in 'simple::E' in 'simple::F' in 'simple::G' (2 entries).
+ // CHECK-NEXT: 0 | void simple::F::g()
+ // CHECK-NEXT: [this adjustment: vtordisp at -4, -4 non-virtual]
+ // CHECK-NEXT: 1 | simple::G::~G() [scalar deleting]
+ // CHECK-NEXT: [this adjustment: vtordisp at -4, 0 non-virtual]
+
+ // CHECK-LABEL: VFTable for 'V2' in 'V3' in 'simple::E' in 'simple::F' in 'simple::G' (2 entries).
+ // CHECK-NEXT: 0 | void simple::E::f()
+ // CHECK-NEXT: 1 | simple::G::~G() [scalar deleting]
+ // CHECK-NEXT: [this adjustment: vtordisp at -12, -8 non-virtual]
+
+ G();
+ int g;
+
+ // MANGLING-DAG: @"\01?g@F@simple@@$4PPPPPPPM@3AEXXZ"{{.*}}@"\01??_EG@simple@@$4PPPPPPPM@A@AEPAXI@Z"
+ // MANGLING-DAG: @"\01?f@E@simple@@UAEXXZ"{{.*}}@"\01??_EG@simple@@$4PPPPPPPE@7AEPAXI@Z"
+};
+
+G::G() {}
}
namespace extended {
@@ -355,6 +416,40 @@ A a;
void use(A *obj) { delete obj; }
}
+namespace pr19408 {
+// In this test, the vptr used to vcall D::f() is located in the A vbase.
+// The offset of A in different in C and D, so the D vtordisp thunk should
+// adjust "this" so C::f gets the right value.
+struct A {
+ A();
+ virtual void f();
+ int a;
+};
+
+struct B : virtual A {
+ B();
+ int b;
+};
+
+struct C : B {
+ C();
+ virtual void f();
+ int c;
+};
+
+struct D : C {
+ // CHECK-LABEL: VFTable for 'pr19408::A' in 'pr19408::B' in 'pr19408::C' in 'pr19408::D' (1 entry).
+ // CHECK-NEXT: 0 | void pr19408::C::f()
+ // CHECK-NEXT: [this adjustment: vtordisp at -4, -4 non-virtual]
+
+ // MANGLING-DAG: @"\01?f@C@pr19408@@$4PPPPPPPM@3AEXXZ"
+ D();
+ int d;
+};
+
+D::D() {}
+}
+
namespace access {
struct A {
virtual ~A();
@@ -385,3 +480,90 @@ struct C : virtual B {
C c;
}
+
+namespace pr19505 {
+struct A {
+ virtual void f();
+ virtual void z();
+};
+
+struct B : A {
+ virtual void f();
+};
+
+struct C : A, B {
+ virtual void g();
+};
+
+struct X : B, virtual C {
+ X() {}
+ virtual void g();
+
+ // CHECK-LABEL: VFTable for 'pr19505::A' in 'pr19505::B' in 'pr19505::C' in 'pr19505::X' (2 entries).
+ // CHECK-NEXT: 0 | void pr19505::B::f()
+ // CHECK-NEXT: 1 | void pr19505::A::z()
+
+ // MANGLING-DAG: @"\01??_7X@pr19505@@6BB@1@@" = {{.*}}@"\01?f@B@pr19505@@UAEXXZ"
+} x;
+
+void build_vftable(X *obj) { obj->g(); }
+}
+
+namespace pr19506 {
+struct A {
+ virtual void f();
+ virtual void g();
+};
+
+struct B : A {
+ virtual void f();
+};
+
+struct C : B {};
+
+struct X : C, virtual B {
+ virtual void g();
+ X() {}
+
+ // CHECK-LABEL: VFTable for 'pr19506::A' in 'pr19506::B' in 'pr19506::X' (2 entries).
+ // CHECK-NEXT: 0 | void pr19506::B::f()
+ // CHECK-NEXT: 1 | void pr19506::X::g()
+ // CHECK-NEXT: [this adjustment: vtordisp at -4, -12 non-virtual]
+
+ // MANGLING-DAG: @"\01??_7X@pr19506@@6BB@1@@" = {{.*}}@"\01?f@B@pr19506@@UAEXXZ"
+} x;
+
+void build_vftable(X *obj) { obj->g(); }
+}
+
+namespace pr19519 {
+// VS2013 CL miscompiles this, just make sure we don't regress.
+
+struct A {
+ virtual void f();
+ virtual void g();
+};
+
+struct B : virtual A {
+ virtual void f();
+ B();
+};
+
+struct C : virtual A {
+ virtual void g();
+};
+
+struct X : B, C {
+ X();
+
+ // CHECK-LABEL: VFTable for 'pr19519::A' in 'pr19519::B' in 'pr19519::X' (2 entries).
+ // CHECK-NEXT: 0 | void pr19519::B::f()
+ // CHECK-NEXT: [this adjustment: vtordisp at -4, -4 non-virtual]
+ // CHECK-NEXT: 1 | void pr19519::C::g()
+ // CHECK-NEXT: [this adjustment: vtordisp at -4, -4 non-virtual]
+
+ // MANGLING-DAG: @"\01??_7X@pr19519@@6B@" = {{.*}}@"\01?g@C@pr19519@@$4PPPPPPPM@3AEXXZ"
+};
+
+X::X() {}
+}
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
index 1947b59715..6ef3176935 100644
--- a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp
@@ -455,6 +455,35 @@ struct W : virtual X, A {};
W w;
}
+namespace Test12 {
+struct X : B, A { };
+
+struct Y : X {
+ virtual void f(); // Overrides A::f.
+};
+
+struct Z : virtual Y {
+ // CHECK-LABEL: VFTable for 'A' in 'Test12::X' in 'Test12::Y' in 'Test12::Z' (2 entries).
+ // CHECK-NEXT: 0 | void Test12::Y::f()
+ // CHECK-NEXT: 1 | void A::z()
+
+ int z;
+ // MANGLING-DAG: @"\01??_7Z@Test12@@6BA@@@" = {{.*}}@"\01?f@Y@Test12@@UAEXXZ"
+};
+
+struct W : Z {
+ // CHECK-LABEL: VFTable for 'A' in 'Test12::X' in 'Test12::Y' in 'Test12::Z' in 'Test12::W' (2 entries).
+ // CHECK-NEXT: 0 | void Test12::Y::f()
+ // CHECK-NEXT: 1 | void A::z()
+ W();
+
+ int w;
+ // MANGLING-DAG: @"\01??_7W@Test12@@6BA@@@" = {{.*}}@"\01?f@Y@Test12@@UAEXXZ"
+};
+
+W::W() {}
+}
+
namespace vdtors {
struct X {
virtual ~X();
@@ -697,3 +726,41 @@ D obj;
// MANGLING-DAG: @"\01??_7B@pr19240@@6B@"
}
+
+namespace pr19408 {
+// This test is a non-vtordisp version of the reproducer for PR19408.
+struct X : virtual A {
+ int x;
+};
+
+struct Y : X {
+ virtual void f();
+ int y;
+};
+
+struct Z : Y {
+ // CHECK-LABEL: VFTable for 'A' in 'pr19408::X' in 'pr19408::Y' in 'pr19408::Z' (2 entries).
+ // CHECK-NEXT: 0 | void pr19408::Y::f()
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+ // CHECK-NEXT: 1 | void A::z()
+
+ Z();
+ int z;
+ // MANGLING-DAG: @"\01??_7Z@pr19408@@6B@" = {{.*}}@"\01?f@Y@pr19408@@W3AEXXZ"
+};
+
+Z::Z() {}
+
+struct W : B, Y {
+ // CHECK-LABEL: VFTable for 'A' in 'pr19408::X' in 'pr19408::Y' in 'pr19408::W' (2 entries).
+ // CHECK-NEXT: 0 | void pr19408::Y::f()
+ // CHECK-NEXT: [this adjustment: -4 non-virtual]
+ // CHECK-NEXT: 1 | void A::z()
+
+ W();
+ int w;
+ // MANGLING-DAG: @"\01??_7W@pr19408@@6BY@1@@" = {{.*}}@"\01?f@Y@pr19408@@W3AEXXZ"
+};
+
+W::W() {}
+}
diff --git a/test/CodeGenCXX/mips-size_t-ptrdiff_t.cpp b/test/CodeGenCXX/mips-size_t-ptrdiff_t.cpp
new file mode 100644
index 0000000000..7c94ea0d54
--- /dev/null
+++ b/test/CodeGenCXX/mips-size_t-ptrdiff_t.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -x c++ -emit-llvm -triple=mips-unknown-linux-gnu < %s | FileCheck --check-prefix=O32 %s
+// RUN: %clang_cc1 -x c++ -emit-llvm -triple=mips64-unknown-linux-gnu -target-abi n32 < %s | FileCheck --check-prefix=N32 %s
+// RUN: %clang_cc1 -x c++ -emit-llvm -triple=mips64-unknown-linux-gnu -target-abi 64 < %s | FileCheck --check-prefix=N64 %s
+
+// Test that the size_t is correct for the ABI. It's not sufficient to be the
+// correct size, it must be the same type for correct name mangling.
+
+long *alloc_long() {
+ long *rv = new long; // size_t is implicit in the new operator
+ return rv;
+}
+// O32-LABEL: define i32* @_Z10alloc_longv()
+// O32: call noalias i8* @_Znwj(i32 4)
+
+// N32-LABEL: define i32* @_Z10alloc_longv()
+// N32: call noalias i8* @_Znwj(i32 4)
+
+// N64-LABEL: define i64* @_Z10alloc_longv()
+// N64: call noalias i8* @_Znwm(i64 8)
+
+long *alloc_long_array() {
+ long *rv = new long[2];
+ return rv;
+}
+
+// O32-LABEL: define i32* @_Z16alloc_long_arrayv()
+// O32: call noalias i8* @_Znaj(i32 8)
+
+// N32-LABEL: define i32* @_Z16alloc_long_arrayv()
+// N32: call noalias i8* @_Znaj(i32 8)
+
+// N64-LABEL: define i64* @_Z16alloc_long_arrayv()
+// N64: call noalias i8* @_Znam(i64 16)
+
+#include <stddef.h>
+
+void size_t_arg(size_t a) {
+}
+
+// O32-LABEL: _Z10size_t_argj
+// N32-LABEL: _Z10size_t_argj
+// N64-LABEL: _Z10size_t_argm
+
+void ptrdiff_t_arg(ptrdiff_t a) {
+}
+
+// O32-LABEL: _Z13ptrdiff_t_argi
+// N32-LABEL: _Z13ptrdiff_t_argi
+// N64-LABEL: _Z13ptrdiff_t_argl
diff --git a/test/CodeGenCXX/poly-unsigned.cpp b/test/CodeGenCXX/poly-unsigned.cpp
index 9851a06089..e2ab430a96 100644
--- a/test/CodeGenCXX/poly-unsigned.cpp
+++ b/test/CodeGenCXX/poly-unsigned.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios -ffreestanding -S -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-UNSIGNED-POLY %s
-// RUN: %clang_cc1 -triple arm64-linux-gnu -ffreestanding -S -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-UNSIGNED-POLY %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -target-feature +neon -ffreestanding -S -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-UNSIGNED-POLY %s
+// RUN: %clang_cc1 -triple arm64-linux-gnu -target-feature +neon -ffreestanding -S -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-UNSIGNED-POLY %s
// RUN: %clang_cc1 -triple armv7-apple-ios -ffreestanding -target-cpu cortex-a8 -S -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-SIGNED-POLY %s
#include <arm_neon.h>
diff --git a/test/CodeGenCXX/pragma-init_seg.cpp b/test/CodeGenCXX/pragma-init_seg.cpp
new file mode 100644
index 0000000000..7356c52aa3
--- /dev/null
+++ b/test/CodeGenCXX/pragma-init_seg.cpp
@@ -0,0 +1,16 @@
+// RUN: not %clang_cc1 %s -triple=i686-pc-win32 -fms-extensions -emit-llvm-only 2>&1 | FileCheck %s
+
+// Reduced from WebKit.
+
+// FIXME: Implement this pragma and test the codegen. We probably want to
+// completely skip @llvm.global_ctors and just create global function pointers
+// to the initializer with the right section.
+
+// CHECK: '#pragma init_seg' not implemented
+#pragma init_seg(".unwantedstaticinits")
+struct A {
+ A();
+ ~A();
+ int a;
+};
+A a;
diff --git a/test/CodeGenCXX/rtti-fundamental.cpp b/test/CodeGenCXX/rtti-fundamental.cpp
index 14297b68cf..e70c3aa365 100644
--- a/test/CodeGenCXX/rtti-fundamental.cpp
+++ b/test/CodeGenCXX/rtti-fundamental.cpp
@@ -89,6 +89,11 @@ namespace __cxxabiv1 {
// CHECK: @_ZTIPy = constant
// CHECK: @_ZTIPKy = constant
+// half
+// CHECK: @_ZTIDh = constant
+// CHECK: @_ZTIPDh = constant
+// CHECK: @_ZTIPKDh = constant
+
// float
// CHECK: @_ZTIf = constant
// CHECK: @_ZTIPf = constant
diff --git a/test/CodeGenObjC/encode-test-6.m b/test/CodeGenObjC/encode-test-6.m
index 54a4eb03d5..4e9c422203 100644
--- a/test/CodeGenObjC/encode-test-6.m
+++ b/test/CodeGenObjC/encode-test-6.m
@@ -53,3 +53,14 @@ typedef struct
}
@end
// CHECK: private global [39 x i8] c"{?=\22presentationInstance\22^{SCNCamera}}\00"
+
+// rdar://16655340
+int i;
+typeof(@encode(typeof(i))) e = @encode(typeof(i));
+const char * Test()
+{
+ return e;
+}
+// CHECK: @e = global [2 x i8] c"i\00", align 1
+// CHECK: define i8* @Test()
+// CHECK: ret i8* getelementptr inbounds ([2 x i8]* @e, i32 0, i32 0)
diff --git a/test/CodeGenOpenCL/address-space-constant-initializers.cl b/test/CodeGenOpenCL/address-space-constant-initializers.cl
new file mode 100644
index 0000000000..ae8cedc1ca
--- /dev/null
+++ b/test/CodeGenOpenCL/address-space-constant-initializers.cl
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 %s -ffake-address-space-map -emit-llvm -o - | FileCheck %s
+
+typedef struct {
+ int i;
+ float f; // At non-zero offset.
+} ArrayStruct;
+
+__constant ArrayStruct constant_array_struct = { 0, 0.0f };
+
+typedef struct {
+ __constant float* constant_float_ptr;
+} ConstantArrayPointerStruct;
+
+// CHECK: %struct.ConstantArrayPointerStruct = type { float addrspace(3)* }
+// CHECK: addrspace(3) global %struct.ConstantArrayPointerStruct { float addrspace(3)* bitcast (i8 addrspace(3)* getelementptr (i8 addrspace(3)* bitcast (%struct.ArrayStruct addrspace(3)* @constant_array_struct to i8 addrspace(3)*), i64 4) to float addrspace(3)*) }
+// Bug 18567
+__constant ConstantArrayPointerStruct constant_array_pointer_struct = {
+ &constant_array_struct.f
+};
+
diff --git a/test/CodeGenOpenCL/kernel-arg-info.cl b/test/CodeGenOpenCL/kernel-arg-info.cl
index 0123f374fe..9832604b04 100644
--- a/test/CodeGenOpenCL/kernel-arg-info.cl
+++ b/test/CodeGenOpenCL/kernel-arg-info.cl
@@ -18,3 +18,11 @@ kernel void foo2(read_only image1d_t img1, image2d_t img2, write_only image2d_ar
// CHECK: metadata !{metadata !"kernel_arg_type", metadata !"image1d_t", metadata !"image2d_t", metadata !"image2d_array_t"}
// CHECK: metadata !{metadata !"kernel_arg_type_qual", metadata !"", metadata !"", metadata !""}
// CHECK: metadata !{metadata !"kernel_arg_name", metadata !"img1", metadata !"img2", metadata !"img3"}
+
+kernel void foo3(__global half * X) {
+}
+// CHECK: metadata !{metadata !"kernel_arg_addr_space", i32 1}
+// CHECK: metadata !{metadata !"kernel_arg_access_qual", metadata !"none"}
+// CHECK: metadata !{metadata !"kernel_arg_type", metadata !"half*"}
+// CHECK: metadata !{metadata !"kernel_arg_type_qual", metadata !""}
+// CHECK: metadata !{metadata !"kernel_arg_name", metadata !"X"}
diff --git a/test/Driver/Inputs/basic_android_tree/aarch64-linux-android/bin/.keep b/test/Driver/Inputs/basic_android_tree/aarch64-linux-android/bin/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/aarch64-linux-android/bin/.keep
diff --git a/test/Driver/Inputs/basic_android_tree/aarch64-linux-android/include/c++/4.8/.keep b/test/Driver/Inputs/basic_android_tree/aarch64-linux-android/include/c++/4.8/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/aarch64-linux-android/include/c++/4.8/.keep
diff --git a/test/Driver/Inputs/basic_android_tree/aarch64-linux-android/lib/.keep b/test/Driver/Inputs/basic_android_tree/aarch64-linux-android/lib/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/aarch64-linux-android/lib/.keep
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtbegin.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtbegin.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtbegin.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtbeginS.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtbeginS.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtbeginS.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtbeginT.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtbeginT.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtbeginT.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtend.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtend.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtend.o
diff --git a/test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtendS.o b/test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtendS.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_android_tree/lib/gcc/aarch64-linux-android/4.8/crtendS.o
diff --git a/test/Driver/Inputs/basic_netbsd_tree/usr/lib/64/crti.o b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/64/crti.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/64/crti.o
diff --git a/test/Driver/Inputs/basic_netbsd_tree/usr/lib/eabi/crti.o b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/eabi/crti.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/eabi/crti.o
diff --git a/test/Driver/Inputs/basic_netbsd_tree/usr/lib/i386/crti.o b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/i386/crti.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/i386/crti.o
diff --git a/test/Driver/Inputs/basic_netbsd_tree/usr/lib/o32/crti.o b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/o32/crti.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/o32/crti.o
diff --git a/test/Driver/Inputs/basic_netbsd_tree/usr/lib/oabi/crti.o b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/oabi/crti.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/oabi/crti.o
diff --git a/test/Driver/Inputs/basic_netbsd_tree/usr/lib/sparc/crti.o b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/sparc/crti.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_netbsd_tree/usr/lib/sparc/crti.o
diff --git a/test/Driver/Inputs/file.ll b/test/Driver/Inputs/file.ll
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/file.ll
diff --git a/test/Driver/aarch64-cpus.c b/test/Driver/aarch64-cpus.c
index 4e32b3fb6a..886bb00d17 100644
--- a/test/Driver/aarch64-cpus.c
+++ b/test/Driver/aarch64-cpus.c
@@ -1,20 +1,64 @@
// Check target CPUs are correctly passed.
// RUN: %clang -target aarch64 -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC %s
+// RUN: %clang -target aarch64 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC %s
+// RUN: %clang -target aarch64_be -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC %s
// GENERIC: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic"
+// RUN: %clang -target arm64 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC %s
+// RUN: %clang -target arm64 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC %s
+// RUN: %clang -target arm64_be -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC %s
+// ARM64-GENERIC: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic"
+
+// RUN: %clang -target arm64-apple-darwin -arch arm64 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-DARWIN %s
+// ARM64-DARWIN: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cyclone"
+
// RUN: %clang -target aarch64 -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s
+// RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s
// CA53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a53"
+// RUN: %clang -target arm64 -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s
+// RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s
+// RUN: %clang -target arm64_be -mlittle-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s
+// ARM64-CA53: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a53"
+
// RUN: %clang -target aarch64 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s
+// RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s
+// RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s
// CA57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a57"
+// RUN: %clang -target arm64 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s
+// RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s
+// RUN: %clang -target arm64_be -mlittle-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s
+// ARM64-CA57: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a57"
+
// RUN: %clang -target aarch64_be -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC-BE %s
+// RUN: %clang -target aarch64 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC-BE %s
+// RUN: %clang -target aarch64_be -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC-BE %s
// GENERIC-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic"
+// RUN: %clang -target arm64_be -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC-BE %s
+// RUN: %clang -target arm64 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC-BE %s
+// RUN: %clang -target arm64_be -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-GENERIC-BE %s
+// ARM64-GENERIC-BE: "-cc1"{{.*}} "-triple" "arm64_be{{.*}}" "-target-cpu" "generic"
+
// RUN: %clang -target aarch64_be -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
+// RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s
// CA53-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a53"
+// RUN: %clang -target arm64_be -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53-BE %s
+// RUN: %clang -target arm64 -mbig-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53-BE %s
+// RUN: %clang -target arm64_be -mbig-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53-BE %s
+// ARM64-CA53-BE: "-cc1"{{.*}} "-triple" "arm64_be{{.*}}" "-target-cpu" "cortex-a53"
+
// RUN: %clang -target aarch64_be -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s
+// RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s
+// RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s
// CA57-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a57"
+// RUN: %clang -target arm64_be -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57-BE %s
+// RUN: %clang -target arm64 -mbig-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57-BE %s
+// RUN: %clang -target arm64_be -mbig-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57-BE %s
+// ARM64-CA57-BE: "-cc1"{{.*}} "-triple" "arm64_be{{.*}}" "-target-cpu" "cortex-a57"
diff --git a/test/Driver/aarch64-features.c b/test/Driver/aarch64-features.c
index 2acb7157f6..7c3f875404 100644
--- a/test/Driver/aarch64-features.c
+++ b/test/Driver/aarch64-features.c
@@ -1,4 +1,5 @@
// RUN: %clang -target aarch64-none-linux-gnu -### %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang -target arm64-none-linux-gnu -### %s -fsyntax-only 2>&1 | FileCheck %s
// The AArch64 PCS states that chars should be unsigned.
// CHECK: fno-signed-char
diff --git a/test/Driver/aarch64-mfpu.c b/test/Driver/aarch64-mfpu.c
index 2e55c7fc29..ba00bfbbb4 100644
--- a/test/Driver/aarch64-mfpu.c
+++ b/test/Driver/aarch64-mfpu.c
@@ -4,20 +4,29 @@
// RUN: | FileCheck --check-prefix=CHECK-NEON %s
// RUN: %clang -target aarch64-linux-eabi %s -### -o %t.o 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NEON %s
+// RUN: %clang -target arm64-linux-eabi -mfpu=neon %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NEON %s
+// RUN: %clang -target arm64-linux-eabi %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NEON %s
// CHECK-NEON: "-target-feature" "+neon"
// RUN: %clang -target aarch64-linux-eabi -mfpu=fp-armv8 %s -### -o %t.o 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-FP-ARMV8 %s
+// RUN: %clang -target arm64-linux-eabi -mfpu=fp-armv8 %s -### -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-FP-ARMV8 %s
// CHECK-FP-ARMV8: "-target-feature" "+fp-armv8"
// RUN: %clang -target aarch64-linux-eabi -mfpu=neon-fp-armv8 %s -### 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NEON-FP-ARMV8 %s
+// RUN: %clang -target arm64-linux-eabi -mfpu=neon-fp-armv8 %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NEON-FP-ARMV8 %s
// CHECK-NEON-FP-ARMV8: "-target-feature" "+fp-armv8"
// CHECK-NEON-FP-ARMV8: "-target-feature" "+neon"
// RUN: %clang -target aarch64-linux-eabi -mfpu=crypto-neon-fp-armv8 %s -### 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-CRYPTO-NEON-FP-ARMV8 %s
+// RUN: %clang -target arm64-linux-eabi -mfpu=crypto-neon-fp-armv8 %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-CRYPTO-NEON-FP-ARMV8 %s
// CHECK-CRYPTO-NEON-FP-ARMV8: "-target-feature" "+fp-armv8"
// CHECK-CRYPTO-NEON-FP-ARMV8: "-target-feature" "+neon"
// CHECK-CRYPTO-NEON-FP-ARMV8: "-target-feature" "+crypto"
-
diff --git a/test/Driver/aarch64-mgeneral_regs_only.c b/test/Driver/aarch64-mgeneral_regs_only.c
index 28cdd08d53..43172c7bd6 100644
--- a/test/Driver/aarch64-mgeneral_regs_only.c
+++ b/test/Driver/aarch64-mgeneral_regs_only.c
@@ -2,6 +2,8 @@
// RUN: %clang -target aarch64-linux-eabi -mgeneral-regs-only %s -### 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NO-FP %s
+// RUN: %clang -target arm64-linux-eabi -mgeneral-regs-only %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NO-FP %s
// CHECK-NO-FP: "-target-feature" "-fp-armv8"
// CHECK-NO-FP: "-target-feature" "-crypto"
// CHECK-NO-FP: "-target-feature" "-neon"
diff --git a/test/Driver/android-standalone.cpp b/test/Driver/android-standalone.cpp
index dc41ed7559..87eaf9c90c 100644
--- a/test/Driver/android-standalone.cpp
+++ b/test/Driver/android-standalone.cpp
@@ -17,6 +17,21 @@
// CHECK: "-L{{.*}}/sysroot/usr/lib"
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target aarch64-linux-android \
+// RUN: -B%S/Inputs/basic_android_tree \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: | FileCheck --check-prefix=CHECK-AARCH64 %s
+// CHECK-AARCH64: {{.*}}clang{{.*}}" "-cc1"
+// CHECK-AARCH64: "-internal-isystem" "{{.*}}/aarch64-linux-android/include/c++/4.8"
+// CHECK-AARCH64: "-internal-isystem" "{{.*}}/aarch64-linux-android/include/c++/4.8/aarch64-linux-android"
+// CHECK-AARCH64: "-internal-externc-isystem" "{{.*}}/sysroot/include"
+// CHECK-AARCH64: "-internal-externc-isystem" "{{.*}}/sysroot/usr/include"
+// CHECK-AARCH64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-AARCH64: "-L{{.*}}/lib/gcc/aarch64-linux-android/4.8"
+// CHECK-AARCH64: "-L{{.*}}/lib/gcc/aarch64-linux-android/4.8/../../../../aarch64-linux-android/lib"
+// CHECK-AARCH64: "-L{{.*}}/sysroot/usr/lib"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target mipsel-linux-android \
// RUN: -mips32 \
// RUN: -B%S/Inputs/basic_android_tree \
diff --git a/test/Driver/arm-cortex-cpus.c b/test/Driver/arm-cortex-cpus.c
index 242fe0d241..d2822b618a 100644
--- a/test/Driver/arm-cortex-cpus.c
+++ b/test/Driver/arm-cortex-cpus.c
@@ -104,30 +104,48 @@
// RUN: %clang -target arm-linux-gnueabi -march=armv7-r -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V7R-THUMB %s
// CHECK-V7R-THUMB: "-cc1"{{.*}} "-triple" "thumbv7r-{{.*}} "-target-cpu" "cortex-r4"
-// RUN: %clang -target armv8 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
+// RUN: %clang -target armv8 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
// RUN: %clang -target arm -march=armv8 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
// RUN: %clang -target armv8a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
// RUN: %clang -target arm -march=armv8a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
-// RUN: %clang -target arm -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
+// RUN: %clang -target arm -march=armv8-a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
+// RUN: %clang -target armv8 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
+// RUN: %clang -target arm -march=armv8 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
+// RUN: %clang -target armv8a -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
+// RUN: %clang -target arm -march=armv8a -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
+// RUN: %clang -target arm -mlittle-endian -march=armv8-a -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A %s
// CHECK-V8A: "-cc1"{{.*}} "-triple" "armv8-{{.*}}" "-target-cpu" "cortex-a53"
-// RUN: %clang -target armebv8 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A %s
+// RUN: %clang -target armebv8 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A %s
// RUN: %clang -target armeb -march=armebv8 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A %s
// RUN: %clang -target armebv8a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A %s
// RUN: %clang -target armeb -march=armebv8a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A %s
-// RUN: %clang -target armeb -march=armebv8-a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A %s
+// RUN: %clang -target armeb -march=armebv8-a -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A %s
+// RUN: %clang -target armv8 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A %s
+// RUN: %clang -target arm -march=armebv8 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A %s
+// RUN: %clang -target armv8a -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A %s
+// RUN: %clang -target arm -march=armebv8a -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A %s
+// RUN: %clang -target arm -march=armebv8-a -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A %s
// CHECK-BE-V8A: "-cc1"{{.*}} "-triple" "armebv8-{{.*}}" "-target-cpu" "cortex-a53"
// RUN: %clang -target armv8 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A-THUMB %s
// RUN: %clang -target arm -march=armv8 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A-THUMB %s
// RUN: %clang -target armv8a -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A-THUMB %s
// RUN: %clang -target arm -march=armv8a -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A-THUMB %s
+// RUN: %clang -target armv8 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A-THUMB %s
+// RUN: %clang -target arm -march=armv8 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A-THUMB %s
+// RUN: %clang -target armv8a -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A-THUMB %s
+// RUN: %clang -target arm -march=armv8a -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V8A-THUMB %s
// CHECK-V8A-THUMB: "-cc1"{{.*}} "-triple" "thumbv8-{{.*}}" "-target-cpu" "cortex-a53"
// RUN: %clang -target armebv8 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A-THUMB %s
// RUN: %clang -target armeb -march=armebv8 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A-THUMB %s
// RUN: %clang -target armebv8a -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A-THUMB %s
// RUN: %clang -target armeb -march=armebv8a -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A-THUMB %s
+// RUN: %clang -target armv8 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A-THUMB %s
+// RUN: %clang -target arm -march=armebv8 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A-THUMB %s
+// RUN: %clang -target armv8a -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A-THUMB %s
+// RUN: %clang -target arm -march=armebv8a -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-V8A-THUMB %s
// CHECK-BE-V8A-THUMB: "-cc1"{{.*}} "-triple" "thumbebv8-{{.*}}" "-target-cpu" "cortex-a53"
// ================== Check default Architecture on each Cortex CPU
@@ -137,6 +155,12 @@
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a9 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a12 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a15 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a5 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a7 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a8 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a9 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a12 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a15 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A %s
// CHECK-CPUV7A: "-cc1"{{.*}} "-triple" "armv7-{{.*}}
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a5 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
@@ -145,67 +169,105 @@
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a9 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a12 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a15 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a5 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a7 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a8 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a9 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a12 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a15 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A %s
// CHECK-BE-CPUV7A: "-cc1"{{.*}} "-triple" "armebv7-{{.*}}
-// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a5 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
-// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a7 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
-// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a8 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
-// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a9 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
-// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a12 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
-// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a15 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a5 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a7 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a8 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a9 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a12 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a15 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a5 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a7 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a8 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a9 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a12 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a15 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7A-THUMB %s
// CHECK-CPUV7A-THUMB: "-cc1"{{.*}} "-triple" "thumbv7-{{.*}}
-// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a5 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
-// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a7 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
-// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a8 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
-// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a9 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
-// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a12 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
-// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a15 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
+// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a5 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
+// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a7 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
+// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a8 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
+// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a9 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
+// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a12 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
+// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-a15 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a5 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a7 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a8 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a9 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a12 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-a15 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7A-THUMB %s
// CHECK-BE-CPUV7A-THUMB: "-cc1"{{.*}} "-triple" "thumbebv7-{{.*}}
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m0 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV6M %s
// CHECK-CPUV6M: "-cc1"{{.*}} "-triple" "thumbv6m-{{.*}}
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m3 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7M %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m3 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7M %s
// CHECK-CPUV7M: "-cc1"{{.*}} "-triple" "thumbv7m-{{.*}}
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-m3 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7M %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m3 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7M %s
// CHECK-BE-CPUV7M: "-cc1"{{.*}} "-triple" "thumbebv7m-{{.*}}
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m4 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7EM %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m4 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7EM %s
// CHECK-CPUV7EM: "-cc1"{{.*}} "-triple" "thumbv7em-{{.*}}
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-m4 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7EM %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-m4 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7EM %s
// CHECK-BE-CPUV7EM: "-cc1"{{.*}} "-triple" "thumbebv7em-{{.*}}
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r5 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r5 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R %s
// CHECK-CPUV7R: "-cc1"{{.*}} "-triple" "armv7r-{{.*}}
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-r4 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R %s
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-r5 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r5 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R %s
// CHECK-BE-CPUV7R: "-cc1"{{.*}} "-triple" "armebv7r-{{.*}}
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R-THUMB %s
// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r5 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r5 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV7R-THUMB %s
// CHECK-CPUV7R-THUMB: "-cc1"{{.*}} "-triple" "thumbv7r-{{.*}}
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-r4 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R-THUMB %s
// RUN: %clang -target armeb-linux-gnueabi -mcpu=cortex-r5 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r4 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R-THUMB %s
+// RUN: %clang -target arm-linux-gnueabi -mcpu=cortex-r5 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV7R-THUMB %s
// CHECK-BE-CPUV7R-THUMB: "-cc1"{{.*}} "-triple" "thumbebv7r-{{.*}}
// RUN: %clang -target arm -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
// RUN: %clang -target arm -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
+// RUN: %clang -target arm -mcpu=cortex-a53 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
+// RUN: %clang -target arm -mcpu=cortex-a57 -mlittle-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A %s
// CHECK-CPUV8A: "-cc1"{{.*}} "-triple" "armv8-{{.*}}
// RUN: %clang -target armeb -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
// RUN: %clang -target armeb -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
+// RUN: %clang -target arm -mcpu=cortex-a53 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
+// RUN: %clang -target arm -mcpu=cortex-a57 -mbig-endian -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A %s
// CHECK-BE-CPUV8A: "-cc1"{{.*}} "-triple" "armebv8-{{.*}}
// RUN: %clang -target arm -mcpu=cortex-a53 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A-THUMB %s
// RUN: %clang -target arm -mcpu=cortex-a57 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A-THUMB %s
+// RUN: %clang -target arm -mcpu=cortex-a53 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A-THUMB %s
+// RUN: %clang -target arm -mcpu=cortex-a57 -mlittle-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-CPUV8A-THUMB %s
// CHECK-CPUV8A-THUMB: "-cc1"{{.*}} "-triple" "thumbv8-{{.*}}
// RUN: %clang -target armeb -mcpu=cortex-a53 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
// RUN: %clang -target armeb -mcpu=cortex-a57 -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
+// RUN: %clang -target arm -mcpu=cortex-a53 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
+// RUN: %clang -target arm -mcpu=cortex-a57 -mbig-endian -mthumb -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-BE-CPUV8A-THUMB %s
// CHECK-BE-CPUV8A-THUMB: "-cc1"{{.*}} "-triple" "thumbebv8-{{.*}}
diff --git a/test/Driver/arm64-as.s b/test/Driver/arm64-as.s
new file mode 100644
index 0000000000..061e5b2eff
--- /dev/null
+++ b/test/Driver/arm64-as.s
@@ -0,0 +1,5 @@
+// Make sure the arm64 default on cyclone when compiling for apple.
+// RUN: %clang -target arm64-apple-ios -arch arm64 -### -c %s 2>&1 | FileCheck -check-prefix=TARGET %s
+//
+// TARGET: "-cc1as"
+// TARGET: "-target-cpu" "cyclone"
diff --git a/test/Driver/cl-fallback.c b/test/Driver/cl-fallback.c
index d90e5fa496..655535b65f 100644
--- a/test/Driver/cl-fallback.c
+++ b/test/Driver/cl-fallback.c
@@ -5,7 +5,8 @@
// command-line option, e.g. on Mac where %s is commonly under /Users.
// RUN: %clang_cl /fallback /Dfoo=bar /Ubaz /Ifoo /O0 /Ox /GR /GR- /Gy /Gy- \
-// RUN: /LD /LDd /MD /MDd /MTd /MT /FImyheader.h /Zi -### -- %s 2>&1 \
+// RUN: /Gw /Gw- /LD /LDd /MD /MDd /MTd /MT /FImyheader.h /Zi \
+// RUN: -### -- %s 2>&1 \
// RUN: | FileCheck %s
// CHECK: "-fdiagnostics-format" "msvc-fallback"
// CHECK: ||
@@ -19,6 +20,7 @@
// CHECK: "/Ox"
// CHECK: "/GR-"
// CHECK: "/Gy-"
+// CHECK: "/Gw-"
// CHECK: "/Z7"
// CHECK: "/FImyheader.h"
// CHECK: "/LD"
@@ -52,4 +54,11 @@
// RUN: FileCheck -check-prefix=ErrWarn %s
// ErrWarn: warning: falling back to {{.*}}cl.exe
+// Don't fall back on non-C or C++ files.
+// RUN: %clang_cl /fallback -### -- %S/Inputs/file.ll 2>&1 | FileCheck -check-prefix=LL %s
+// LL: file.ll
+// LL-NOT: ||
+// LL-NOT: "cl.exe"
+
+
#error "This fails to compile."
diff --git a/test/Driver/cl-link.c b/test/Driver/cl-link.c
index 24e0702c8a..309c27dab1 100644
--- a/test/Driver/cl-link.c
+++ b/test/Driver/cl-link.c
@@ -31,3 +31,7 @@
// ASAN-DLL: "-incremental:no"
// ASAN-DLL: "{{.*}}clang_rt.asan_dll_thunk-i386.lib"
// ASAN-DLL: "{{.*}}cl-link{{.*}}.obj"
+
+// RUN: %clang_cl /Zi /Tc%s -### 2>&1 | FileCheck --check-prefix=DEBUG %s
+// DEBUG: link.exe
+// DEBUG: "-debug"
diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c
index a666131173..48f1a9e4af 100644
--- a/test/Driver/cl-options.c
+++ b/test/Driver/cl-options.c
@@ -25,13 +25,17 @@
// GR_: -fno-rtti
// RUN: %clang_cl /Gy -### -- %s 2>&1 | FileCheck -check-prefix=Gy %s
-// Gy: -fdata-sections
// Gy: -ffunction-sections
// RUN: %clang_cl /Gy /Gy- -### -- %s 2>&1 | FileCheck -check-prefix=Gy_ %s
-// Gy_-NOT: -fdata-sections
// Gy_-NOT: -ffunction-sections
+// RUN: %clang_cl /Gw -### -- %s 2>&1 | FileCheck -check-prefix=Gw %s
+// Gw: -fdata-sections
+
+// RUN: %clang_cl /Gw /Gw- -### -- %s 2>&1 | FileCheck -check-prefix=Gw_ %s
+// Gw_-NOT: -fdata-sections
+
// RUN: %clang_cl /Imyincludedir -### -- %s 2>&1 | FileCheck -check-prefix=SLASH_I %s
// RUN: %clang_cl /I myincludedir -### -- %s 2>&1 | FileCheck -check-prefix=SLASH_I %s
// SLASH_I: "-I" "myincludedir"
@@ -129,6 +133,18 @@
// WJoined: "-cc1"
// WJoined: "-Wunused-pragmas"
+// We recognize -f[no-]strict-aliasing.
+// RUN: %clang_cl -c -### -- %s 2>&1 | FileCheck -check-prefix=DEFAULTSTRICT %s
+// DEFAULTSTRICT: "-relaxed-aliasing"
+// RUN: %clang_cl -c -fstrict-aliasing -### -- %s 2>&1 | FileCheck -check-prefix=STRICT %s
+// STRICT-NOT: "-relaxed-aliasing"
+// RUN: %clang_cl -c -fno-strict-aliasing -### -- %s 2>&1 | FileCheck -check-prefix=NOSTRICT %s
+// NOSTRICT: "-relaxed-aliasing"
+
+// For some warning ids, we can map from MSVC warning to Clang warning.
+// RUN: %clang_cl -wd4005 -### -- %s 2>&1 | FileCheck -check-prefix=wd4005 %s
+// wd4005: "-cc1"
+// wd4005: "-Wno-macro-redefined"
// Ignored options. Check that we don't get "unused during compilation" errors.
// (/Zs is for syntax-only)
diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c
index 63eaf41d5b..6e4fa72cb5 100644
--- a/test/Driver/clang_f_opts.c
+++ b/test/Driver/clang_f_opts.c
@@ -89,6 +89,17 @@
// RUN: %clang -### -S -fno-tree-slp-vectorize -fslp-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-SLP-VECTORIZE %s
// RUN: %clang -### -S -fno-tree-slp-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-SLP-VECTORIZE %s
// RUN: %clang -### -S -ftree-slp-vectorize -fno-slp-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-SLP-VECTORIZE %s
+// RUN: %clang -### -S -O %s 2>&1 | FileCheck -check-prefix=CHECK-SLP-VECTORIZE %s
+// RUN: %clang -### -S -O2 %s 2>&1 | FileCheck -check-prefix=CHECK-SLP-VECTORIZE %s
+// RUN: %clang -### -S -Os %s 2>&1 | FileCheck -check-prefix=CHECK-SLP-VECTORIZE %s
+// RUN: %clang -### -S -O3 %s 2>&1 | FileCheck -check-prefix=CHECK-SLP-VECTORIZE %s
+// RUN: %clang -### -S -fno-slp-vectorize -O3 %s 2>&1 | FileCheck -check-prefix=CHECK-SLP-VECTORIZE %s
+// RUN: %clang -### -S -O1 -fslp-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-SLP-VECTORIZE %s
+// RUN: %clang -### -S -Ofast %s 2>&1 | FileCheck -check-prefix=CHECK-SLP-VECTORIZE %s
+// RUN: %clang -### -S %s 2>&1 | FileCheck -check-prefix=CHECK-NO-SLP-VECTORIZE %s
+// RUN: %clang -### -S -O0 %s 2>&1 | FileCheck -check-prefix=CHECK-NO-SLP-VECTORIZE %s
+// RUN: %clang -### -S -O1 %s 2>&1 | FileCheck -check-prefix=CHECK-NO-SLP-VECTORIZE %s
+// RUN: %clang -### -S -Oz %s 2>&1 | FileCheck -check-prefix=CHECK-NO-SLP-VECTORIZE %s
// CHECK-SLP-VECTORIZE: "-vectorize-slp"
// CHECK-NO-SLP-VECTORIZE-NOT: "-vectorize-slp"
diff --git a/test/Driver/constructors.c b/test/Driver/constructors.c
index 680705fbf9..a8b0942f01 100644
--- a/test/Driver/constructors.c
+++ b/test/Driver/constructors.c
@@ -55,3 +55,12 @@
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target aarch64-none-none-eabi \
// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
+
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target arm64-none-linux-gnu \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target arm64-none-none-eabi \
+// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
diff --git a/test/Driver/crash-report.c b/test/Driver/crash-report.c
index 95c57f238e..acc1abdc4e 100644
--- a/test/Driver/crash-report.c
+++ b/test/Driver/crash-report.c
@@ -3,6 +3,7 @@
// RUN: not env TMPDIR=%t TEMP=%t TMP=%t RC_DEBUG_OPTIONS=1 %clang -fsyntax-only %s \
// RUN: -F/tmp/ -I /tmp/ -idirafter /tmp/ -iquote /tmp/ -isystem /tmp/ \
// RUN: -iprefix /the/prefix -iwithprefix /tmp -iwithprefixbefore /tmp/ \
+// RUN: -fmodules -fcxx-modules -fmodules-cache-path=/tmp/ \
// RUN: -Xclang -internal-isystem -Xclang /tmp/ \
// RUN: -Xclang -internal-externc-isystem -Xclang /tmp/ \
// RUN: -DFOO=BAR 2>&1 | FileCheck %s
@@ -33,6 +34,7 @@ FOO
// CHECKSH-NOT: -iprefix /the/prefix
// CHECKSH-NOT: -iwithprefix /tmp/
// CHECKSH-NOT: -iwithprefixbefore /tmp/
+// CHECKSH-NOT: -fmodules-cache-path=/tmp/
// CHECKSH-NOT: -internal-isystem /tmp/
// CHECKSH-NOT: -internal-externc-isystem /tmp/
// CHECKSH-NOT: -dwarf-debug-flags
diff --git a/test/Driver/linux-ld.c b/test/Driver/linux-ld.c
index ca390d9b3b..46fec499e9 100644
--- a/test/Driver/linux-ld.c
+++ b/test/Driver/linux-ld.c
@@ -592,6 +592,10 @@
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=aarch64-linux-android \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID %s
@@ -626,6 +630,11 @@
// RUN: -shared \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SO %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=aarch64-linux-android \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: -shared \
+// RUN: | FileCheck --check-prefix=CHECK-ANDROID-SO %s
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -shared \
@@ -665,6 +674,11 @@
// RUN: -static \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=aarch64-linux-android \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: -static \
+// RUN: | FileCheck --check-prefix=CHECK-ANDROID-STATIC %s
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -static \
@@ -703,6 +717,11 @@
// RUN: -pie \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PIE %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=aarch64-linux-android \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: -pie \
+// RUN: | FileCheck --check-prefix=CHECK-ANDROID-PIE %s
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mipsel-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: -pie \
@@ -742,6 +761,10 @@
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-32 %s
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: --target=aarch64-linux-android \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: | FileCheck --check-prefix=CHECK-ANDROID-64 %s
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: --target=mips64el-linux-android \
// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
// RUN: | FileCheck --check-prefix=CHECK-ANDROID-64 %s
diff --git a/test/Driver/netbsd.c b/test/Driver/netbsd.c
index b300bf4577..9cb7b4117e 100644
--- a/test/Driver/netbsd.c
+++ b/test/Driver/netbsd.c
@@ -13,6 +13,12 @@
// RUN: %clang -no-canonical-prefixes -target aarch64--netbsd7.0.0 \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=AARCH64-7 %s
+// RUN: %clang -no-canonical-prefixes -target arm64--netbsd \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=ARM64 %s
+// RUN: %clang -no-canonical-prefixes -target arm64--netbsd7.0.0 \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=ARM64-7 %s
// RUN: %clang -no-canonical-prefixes -target arm--netbsd-eabi \
// RUN: -no-integrated-as --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=ARM %s
@@ -53,6 +59,12 @@
// RUN: %clang -no-canonical-prefixes -target aarch64--netbsd7.0.0 -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-AARCH64-7 %s
+// RUN: %clang -no-canonical-prefixes -target arm64--netbsd -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-ARM64 %s
+// RUN: %clang -no-canonical-prefixes -target arm64--netbsd7.0.0 -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-ARM64-7 %s
// RUN: %clang -no-canonical-prefixes -target arm--netbsd-eabi -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-ARM %s
@@ -101,11 +113,26 @@
// AARCH64-7: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
// AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// ARM64: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd"
+// ARM64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// ARM64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// ARM64: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+// ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// ARM64-7: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd7.0.0"
+// ARM64-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// ARM64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// ARM64-7: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+// ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// ARM: clang{{.*}}" "-cc1" "-triple" "armv5e--netbsd-eabi"
// ARM: as{{.*}}" "-mcpu=arm926ej-s" "-o"
// ARM: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// ARM: "-m" "armelf_nbsd_eabi"
-// ARM: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// ARM: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// ARM: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o"
// ARM: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// ARM: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
@@ -113,7 +140,8 @@
// ARM-APCS: as{{.*}}" "-mcpu=strongarm" "-o"
// ARM-APCS: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// ARM-APCS: "-m" "armelf_nbsd"
-// ARM-APCS: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// ARM-APCS: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// ARM-APCS: "{{.*}}/usr/lib{{/|\\\\}}oabi{{/|\\\\}}crti.o"
// ARM-APCS: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// ARM-APCS: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
@@ -121,21 +149,24 @@
// THUMB: as{{.*}}" "-mcpu=arm926ej-s" "-o"
// THUMB: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// THUMB: "-m" "armelf_nbsd_eabi"
-// THUMB: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// THUMB: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// THUMB: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o"
// THUMB: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// THUMB: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
// ARM-7: clang{{.*}}" "-cc1" "-triple" "armv5e--netbsd7.0.0-eabi"
// ARM-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// ARM-7: "-m" "armelf_nbsd_eabi"
-// ARM-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// ARM-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// ARM-7: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o"
// ARM-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// ARM-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
// ARM-6: clang{{.*}}" "-cc1" "-triple" "armv5e--netbsd6.0.0-eabi"
// ARM-6: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// ARM-6: "-m" "armelf_nbsd_eabi"
-// ARM-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// ARM-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// ARM-6: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o"
// ARM-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// ARM-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
@@ -146,7 +177,8 @@
// SPARC: as{{.*}}" "-32" "-o"
// SPARC: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
// SPARC: "-m" "elf32_sparc"
-// SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// SPARC: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o"
// SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
@@ -191,17 +223,33 @@
// S-AARCH64-7: "-lgcc_eh" "-lc" "-lgcc"
// S-AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// S-ARM64: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd"
+// S-ARM64: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-ARM64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// S-ARM64: "-lgcc_eh" "-lc" "-lgcc"
+// S-ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-ARM64-7: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd7.0.0"
+// S-ARM64-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
+// S-ARM64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
+// S-ARM64-7: "-lgcc_eh" "-lc" "-lgcc"
+// S-ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// S-ARM: clang{{.*}}" "-cc1" "-triple" "armv5e--netbsd-eabi"
// S-ARM: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-ARM: "-m" "armelf_nbsd_eabi"
-// S-ARM: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-ARM: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// S-ARM: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o"
// S-ARM: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// S-ARM: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
// S-ARM-7: clang{{.*}}" "-cc1" "-triple" "armv5e--netbsd7.0.0-eabi"
// S-ARM-7: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-ARM-7: "-m" "armelf_nbsd_eabi"
-// S-ARM-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-ARM-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// S-ARM-7: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o"
// S-ARM-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// S-ARM-7: "-lgcc_eh" "-lc" "-lgcc"
// S-ARM-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
@@ -209,7 +257,8 @@
// S-ARM-6: clang{{.*}}" "-cc1" "-triple" "armv5e--netbsd6.0.0-eabi"
// S-ARM-6: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-ARM-6: "-m" "armelf_nbsd_eabi"
-// S-ARM-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-ARM-6: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// S-ARM-6: "{{.*}}/usr/lib{{/|\\\\}}eabi{{/|\\\\}}crti.o"
// S-ARM-6: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// S-ARM-6: "-lgcc_eh" "-lc" "-lgcc"
// S-ARM-6: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
@@ -217,7 +266,8 @@
// S-SPARC: clang{{.*}}" "-cc1" "-triple" "sparc--netbsd"
// S-SPARC: ld{{.*}}" "--eh-frame-hdr" "-Bstatic"
// S-SPARC: "-m" "elf32_sparc"
-// S-SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// S-SPARC: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o"
// S-SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lc"
// S-SPARC: "-lgcc_eh" "-lc" "-lgcc"
// S-SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
diff --git a/test/Driver/netbsd.cpp b/test/Driver/netbsd.cpp
index 97970dd8c8..7a9e8041e5 100644
--- a/test/Driver/netbsd.cpp
+++ b/test/Driver/netbsd.cpp
@@ -13,6 +13,12 @@
// RUN: %clangxx -no-canonical-prefixes -target aarch64--netbsd7.0.0 \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=AARCH64-7 %s
+// RUN: %clangxx -no-canonical-prefixes -target arm64--netbsd \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=ARM64 %s
+// RUN: %clangxx -no-canonical-prefixes -target arm64--netbsd7.0.0 \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=ARM64-7 %s
// RUN: %clangxx -no-canonical-prefixes -target sparc--netbsd \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=SPARC %s
@@ -35,6 +41,12 @@
// RUN: %clangxx -no-canonical-prefixes -target aarch64--netbsd7.0.0 -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-AARCH64-7 %s
+// RUN: %clangxx -no-canonical-prefixes -target arm64--netbsd -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-ARM64 %s
+// RUN: %clangxx -no-canonical-prefixes -target arm64--netbsd7.0.0 -static \
+// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=S-ARM64-7 %s
// RUN: %clangxx -no-canonical-prefixes -target sparc--netbsd -static \
// RUN: --sysroot=%S/Inputs/basic_netbsd_tree %s -### 2>&1 \
// RUN: | FileCheck -check-prefix=S-SPARC %s
@@ -75,9 +87,24 @@
// AARCH64-7: "-lm" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
// AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// ARM64: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd"
+// ARM64: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// ARM64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
+// ARM64: "-lm" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+// ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// ARM64-7: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd7.0.0"
+// ARM64-7: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
+// ARM64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
+// ARM64-7: "-lm" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+// ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// SPARC: clang{{.*}}" "-cc1" "-triple" "sparc--netbsd"
// SPARC: ld{{.*}}" "--eh-frame-hdr" "-dynamic-linker" "/libexec/ld.elf_so"
-// SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// SPARC: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o"
// SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
// SPARC: "-lm" "-lc" "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
// SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
@@ -122,9 +149,24 @@
// S-AARCH64-7: "-lm" "-lc" "-lgcc_eh" "-lc" "-lgcc"
// S-AARCH64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+// S-ARM64: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd"
+// S-ARM64: ld{{.*}}" "-Bstatic"
+// S-ARM64: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
+// S-ARM64: "-lm" "-lc" "-lgcc_eh" "-lc" "-lgcc"
+// S-ARM64: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
+// S-ARM64-7: clang{{.*}}" "-cc1" "-triple" "arm64--netbsd7.0.0"
+// S-ARM64-7: ld{{.*}}" "-Bstatic"
+// S-ARM64-7: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
+// S-ARM64-7: "-lm" "-lc" "-lgcc_eh" "-lc" "-lgcc"
+// S-ARM64-7: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
+
// S-SPARC: clang{{.*}}" "-cc1" "-triple" "sparc--netbsd"
// S-SPARC: ld{{.*}}" "-Bstatic"
-// S-SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o" "{{.*}}/usr/lib{{/|\\\\}}crti.o"
+// S-SPARC: "-o" "a.out" "{{.*}}/usr/lib{{/|\\\\}}crt0.o"
+// S-SPARC: "{{.*}}/usr/lib{{/|\\\\}}sparc{{/|\\\\}}crti.o"
// S-SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtbegin.o" "{{.*}}.o" "-lstdc++"
// S-SPARC: "-lm" "-lc" "-lgcc_eh" "-lc" "-lgcc"
// S-SPARC: "{{.*}}/usr/lib{{/|\\\\}}crtend.o" "{{.*}}/usr/lib{{/|\\\\}}crtn.o"
diff --git a/test/Driver/windows-arm-minimal-arch.c b/test/Driver/windows-arm-minimal-arch.c
new file mode 100644
index 0000000000..cf55b8f99d
--- /dev/null
+++ b/test/Driver/windows-arm-minimal-arch.c
@@ -0,0 +1,5 @@
+// RUN: not %clang -target thumbv5-windows -mcpu=arm10tdmi %s -o /dev/null 2>&1 \
+// RUN: | FileCheck %s
+
+// CHECK: error: the target architecture 'thumbv5' is not supported by the target 'thumbv5--windows-msvc'
+
diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp
index bfd8c3dcfe..5fe7ca4ea9 100644
--- a/test/FixIt/fixit-cxx0x.cpp
+++ b/test/FixIt/fixit-cxx0x.cpp
@@ -125,7 +125,8 @@ namespace NonStaticConstexpr {
struct foo {
constexpr int i; // expected-error {{non-static data member cannot be constexpr; did you intend to make it const?}}
constexpr int j = 7; // expected-error {{non-static data member cannot be constexpr; did you intend to make it static?}}
- foo() : i(3) {
+ constexpr const int k; // expected-error {{non-static data member cannot be constexpr; did you intend to make it const?}}
+ foo() : i(3), k(4) {
}
static int get_j() {
return j;
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
index 52bbb3849a..6a8e7d1e84 100644
--- a/test/FixIt/fixit.cpp
+++ b/test/FixIt/fixit.cpp
@@ -19,7 +19,7 @@ virtual void C1::f() { } // expected-error{{'virtual' can only be specified insi
static void C1::g() { } // expected-error{{'static' can only be specified inside the class definition}}
-template<int Value> struct CT { }; // expected-note{{previous use is here}}
+template<int Value> struct CT { template<typename> struct Inner; }; // expected-note{{previous use is here}}
CT<10 >> 2> ct; // expected-warning{{require parentheses}}
@@ -32,6 +32,8 @@ struct CT<0> { }; // expected-error{{'template<>'}}
template<> union CT<1> { }; // expected-error{{tag type}}
+struct CT<2>::Inner<int> { }; // expected-error 2{{'template<>'}}
+
// Access declarations
class A {
protected:
diff --git a/test/Frontend/optimization-remark.c b/test/Frontend/optimization-remark.c
new file mode 100644
index 0000000000..03bb8f875a
--- /dev/null
+++ b/test/Frontend/optimization-remark.c
@@ -0,0 +1,19 @@
+// This file tests the -Rpass= flag with the inliner. The test is
+// designed to always trigger the inliner, so it should be independent
+// of the optimization level.
+
+// RUN: %clang -c %s -Rpass=inline -O0 -gline-tables-only -S -o /dev/null 2> %t.err
+// RUN: FileCheck < %t.err %s --check-prefix=INLINE
+
+// RUN: %clang -c %s -Rpass=inline -O0 -S -o /dev/null 2> %t.err
+// RUN: FileCheck < %t.err %s --check-prefix=INLINE-NO-LOC
+
+int foo(int x, int y) __attribute__((always_inline));
+
+int foo(int x, int y) { return x + y; }
+int bar(int j) { return foo(j, j - 2); }
+
+// INLINE: remark: foo inlined into bar [-Rpass=inline]
+
+// INLINE-NO-LOC: {{^remark: foo inlined into bar}}
+// INLINE-NO-LOC: note: use -gline-tables-only -gcolumn-info to track
diff --git a/test/SemaObjC/cocoa.m b/test/Headers/cocoa.m
index a8cfb72e1e..d814b3ee21 100644
--- a/test/SemaObjC/cocoa.m
+++ b/test/Headers/cocoa.m
@@ -1,4 +1,4 @@
-// RUN: %clang -arch x86_64 %s -fsyntax-only -Xclang -print-stats
+// RUN: %clang -arch x86_64 %s -fsyntax-only -Xclang -print-stats
#ifdef __APPLE__
#include <Cocoa/Cocoa.h>
#endif
diff --git a/test/Headers/cxx11.cpp b/test/Headers/cxx11.cpp
index 8576c5ecbd..5b0ec0b79c 100644
--- a/test/Headers/cxx11.cpp
+++ b/test/Headers/cxx11.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -ffreestanding -fsyntax-only -std=c++11 %s
-// DISABLED: %clang_cc1 -ffreestanding -fsyntax-only -std=c++11 -fmodules %s
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -std=c++11 -fmodules %s
-// FIXME: This test fails on OS X 10.9 with headers in /usr/include, see PR18322
+// This test fails on systems with older OS X 10.9 SDK headers, see PR18322.
#include <stdalign.h>
diff --git a/test/Index/Inputs/CommentXML/valid-function-02.xml b/test/Index/Inputs/CommentXML/valid-function-02.xml
index 989d6a7c14..98e4fd1c1e 100644
--- a/test/Index/Inputs/CommentXML/valid-function-02.xml
+++ b/test/Index/Inputs/CommentXML/valid-function-02.xml
@@ -1,5 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Function>
<Name>aaa</Name>
-<Abstract><Para>Aaa <bold>bbb</bold> <monospaced>ccc</monospaced> <emphasized>ddd</emphasized>.</Para></Abstract>
+<Abstract>
+ <Para>Aaa
+ <bold>bbb</bold>
+ <monospaced>ccc</monospaced>
+ <emphasized>ddd</emphasized>
+ <rawHTML>&lt;eee&gt;</rawHTML>
+ <rawHTML isSafeToPassThrough="0">&lt;fff&gt;</rawHTML>
+ <rawHTML isSafeToPassThrough="1">&lt;ggg&gt;</rawHTML>.
+ </Para>
+</Abstract>
</Function>
diff --git a/test/Index/Inputs/base_module_needs_vfs.h b/test/Index/Inputs/base_module_needs_vfs.h
new file mode 100644
index 0000000000..9a7a2445a8
--- /dev/null
+++ b/test/Index/Inputs/base_module_needs_vfs.h
@@ -0,0 +1 @@
+void base_module_needs_vfs(void);
diff --git a/test/Index/Inputs/module.map b/test/Index/Inputs/module.map
new file mode 100644
index 0000000000..8f24840c81
--- /dev/null
+++ b/test/Index/Inputs/module.map
@@ -0,0 +1,6 @@
+// See vfsoverlay.yaml
+module ModuleNeedsVFS {
+ header "ModuleNeedsVFS.h"
+ export *
+}
+framework module * { }
diff --git a/test/Index/Inputs/module_needs_vfs.h b/test/Index/Inputs/module_needs_vfs.h
new file mode 100644
index 0000000000..d79cc3f0d3
--- /dev/null
+++ b/test/Index/Inputs/module_needs_vfs.h
@@ -0,0 +1,4 @@
+@import BaseModuleNeedsVFS;
+inline void module_needs_vfs(void) {
+ base_module_needs_vfs();
+}
diff --git a/test/Index/Inputs/vfsoverlay.yaml b/test/Index/Inputs/vfsoverlay.yaml
new file mode 100644
index 0000000000..95b00bef7d
--- /dev/null
+++ b/test/Index/Inputs/vfsoverlay.yaml
@@ -0,0 +1,18 @@
+{
+ 'version': 0,
+ 'roots': [
+ { 'name': 'OUT_DIR', 'type': 'directory',
+ 'contents': [
+ { 'name': 'module.map', 'type': 'file',
+ 'external-contents': 'INPUT_DIR/module.map'
+ },
+ { 'name': 'ModuleNeedsVFS.h', 'type': 'file',
+ 'external-contents': 'INPUT_DIR/module_needs_vfs.h'
+ },
+ { 'name': 'BaseModuleNeedsVFS.framework/Headers/BaseModuleNeedsVFS.h', 'type': 'file',
+ 'external-contents': 'INPUT_DIR/base_module_needs_vfs.h'
+ },
+ ]
+ }
+ ]
+}
diff --git a/test/Index/annotate-module.m b/test/Index/annotate-module.m
index 55e21d235e..3082e21086 100644
--- a/test/Index/annotate-module.m
+++ b/test/Index/annotate-module.m
@@ -44,6 +44,6 @@ int glob;
// RUN: c-index-test -cursor-at=%s:3:11 %s -fmodules-cache-path=%t.cache -fmodules -F %S/../Modules/Inputs \
// RUN: | FileCheck %s -check-prefix=CHECK-CURSOR
-// CHECK-CURSOR: 3:1 ModuleImport=DependsOnModule:3:1 (Definition) Extent=[3:1 - 3:24] Spelling=DependsOnModule ([3:9 - 3:24]) ModuleName=DependsOnModule ({{.*}}DependsOnModule.pcm) Headers(2):
+// CHECK-CURSOR: 3:1 ModuleImport=DependsOnModule:3:1 (Definition) Extent=[3:1 - 3:24] Spelling=DependsOnModule ([3:9 - 3:24]) ModuleName=DependsOnModule ({{.*}}DependsOnModule-{{[^.]*}}.pcm) Headers(2):
// CHECK-CURSOR-NEXT: {{.*}}other.h
// CHECK-CURSOR-NEXT: {{.*}}DependsOnModule.h
diff --git a/test/Index/comment-cplus-template-decls.cpp b/test/Index/comment-cplus-template-decls.cpp
index 9510c7ce15..7ef09bd691 100644
--- a/test/Index/comment-cplus-template-decls.cpp
+++ b/test/Index/comment-cplus-template-decls.cpp
@@ -67,3 +67,18 @@ void func_template_1(T AAA);
template<template<template<typename CCC> class DDD, class BBB> class AAA>
void func_template_2();
// FIXME: There is not Declaration field in the generated output.
+
+namespace rdar16128173 {
+// CHECK: <Declaration>template &lt;class PtrTy&gt; class OpaquePtr {}</Declaration>
+
+/// \brief Wrapper for void* pointer.
+/// \tparam PtrTy Either a pointer type like 'T*' or a type that behaves like
+/// a pointer.
+template <class PtrTy>
+class OpaquePtr {};
+
+// CHECK: <Declaration>typedef OpaquePtr&lt;int&gt; DeclGroupPtrTy</Declaration>
+typedef OpaquePtr<int> DeclGroupPtrTy;
+
+DeclGroupPtrTy blah;
+}
diff --git a/test/Index/comment-to-html-xml-conversion.cpp b/test/Index/comment-to-html-xml-conversion.cpp
index 327fa64483..f93126b1e5 100644
--- a/test/Index/comment-to-html-xml-conversion.cpp
+++ b/test/Index/comment-to-html-xml-conversion.cpp
@@ -472,7 +472,7 @@ void test_full_comment_1(int x1, int x2);
/// <br><a href="http://example.com/">Aaa</a>
void comment_to_html_conversion_24();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_24:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <br><a href="http://example.com/">Aaa</a></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_24</Name><USR>c:@F@comment_to_html_conversion_24#</USR><Declaration>void comment_to_html_conversion_24()</Declaration><Abstract><Para> <rawHTML><![CDATA[<br>]]></rawHTML><rawHTML><![CDATA[<a href="http://example.com/">]]></rawHTML>Aaa<rawHTML>&lt;/a&gt;</rawHTML></Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_24:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <br><a href="http://example.com/">Aaa</a></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_24</Name><USR>c:@F@comment_to_html_conversion_24#</USR><Declaration>void comment_to_html_conversion_24()</Declaration><Abstract><Para> <rawHTML isSafeToPassThrough="1"><![CDATA[<br>]]></rawHTML><rawHTML isSafeToPassThrough="1"><![CDATA[<a href="http://example.com/">]]></rawHTML>Aaa<rawHTML isSafeToPassThrough="1">&lt;/a&gt;</rawHTML></Para></Abstract></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -678,7 +678,7 @@ void comment_to_html_conversion_33();
/// <em>0&lt;i</em>
void comment_to_html_conversion_34();
-// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_34:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>0&lt;i</em></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_34</Name><USR>c:@F@comment_to_html_conversion_34#</USR><Declaration>void comment_to_html_conversion_34()</Declaration><Abstract><Para> <rawHTML><![CDATA[<em>]]></rawHTML>0&lt;i<rawHTML>&lt;/em&gt;</rawHTML></Para></Abstract></Function>]
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_34:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>0&lt;i</em></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_34</Name><USR>c:@F@comment_to_html_conversion_34#</USR><Declaration>void comment_to_html_conversion_34()</Declaration><Abstract><Para> <rawHTML isSafeToPassThrough="1"><![CDATA[<em>]]></rawHTML>0&lt;i<rawHTML isSafeToPassThrough="1">&lt;/em&gt;</rawHTML></Para></Abstract></Function>]
// CHECK-NEXT: CommentAST=[
// CHECK-NEXT: (CXComment_FullComment
// CHECK-NEXT: (CXComment_Paragraph
@@ -721,6 +721,18 @@ void comment_to_html_conversion_35();
// CHECK-NEXT: (CXComment_Text Text=[Γ])
// CHECK-NEXT: (CXComment_Text Text=[ Greek letter Gamma Γ.])))]
+/// <h1 id="]]>">Aaa</h1>
+void comment_to_html_conversion_36();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_36:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <h1 id="]]>">Aaa</h1></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_36</Name><USR>c:@F@comment_to_html_conversion_36#</USR><Declaration>void comment_to_html_conversion_36()</Declaration><Abstract><Para> <rawHTML isSafeToPassThrough="1"><![CDATA[<h1 id="]]]]><![CDATA[>">]]></rawHTML>Aaa<rawHTML isSafeToPassThrough="1">&lt;/h1&gt;</rawHTML></Para></Abstract></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_HTMLStartTag Name=[h1] Attrs: id=]]>)
+// CHECK-NEXT: (CXComment_Text Text=[Aaa])
+// CHECK-NEXT: (CXComment_HTMLEndTag Name=[h1])))]
+
/// Aaa.
class comment_to_xml_conversion_01 {
@@ -853,6 +865,34 @@ enum class comment_to_xml_conversion_17 {
// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:3: EnumConstantDecl=comment_to_xml_conversion_18:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="3"><Name>comment_to_xml_conversion_18</Name><USR>c:@E@comment_to_xml_conversion_17@comment_to_xml_conversion_18</USR><Declaration>comment_to_xml_conversion_18</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
};
+/// <a href="http://example.org/">
+void comment_to_xml_conversion_unsafe_html_01();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_unsafe_html_01:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_unsafe_html_01</Name><USR>c:@F@comment_to_xml_conversion_unsafe_html_01#</USR><Declaration>void comment_to_xml_conversion_unsafe_html_01()</Declaration><Abstract><Para> <rawHTML><![CDATA[<a href="http://example.org/">]]></rawHTML></Para></Abstract></Function>]
+
+/// <a href="http://example.org/"><em>Aaa</em>
+void comment_to_xml_conversion_unsafe_html_02();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_unsafe_html_02:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_unsafe_html_02</Name><USR>c:@F@comment_to_xml_conversion_unsafe_html_02#</USR><Declaration>void comment_to_xml_conversion_unsafe_html_02()</Declaration><Abstract><Para> <rawHTML><![CDATA[<a href="http://example.org/">]]></rawHTML><rawHTML isSafeToPassThrough="1"><![CDATA[<em>]]></rawHTML>Aaa<rawHTML isSafeToPassThrough="1">&lt;/em&gt;</rawHTML></Para></Abstract></Function>]
+
+/// <em>Aaa
+void comment_to_xml_conversion_unsafe_html_03();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_unsafe_html_03:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_unsafe_html_03</Name><USR>c:@F@comment_to_xml_conversion_unsafe_html_03#</USR><Declaration>void comment_to_xml_conversion_unsafe_html_03()</Declaration><Abstract><Para> <rawHTML><![CDATA[<em>]]></rawHTML>Aaa</Para></Abstract></Function>]
+
+/// <em>Aaa</b></em>
+void comment_to_xml_conversion_unsafe_html_04();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_unsafe_html_04:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_unsafe_html_04</Name><USR>c:@F@comment_to_xml_conversion_unsafe_html_04#</USR><Declaration>void comment_to_xml_conversion_unsafe_html_04()</Declaration><Abstract><Para> <rawHTML isSafeToPassThrough="1"><![CDATA[<em>]]></rawHTML>Aaa<rawHTML>&lt;/b&gt;</rawHTML><rawHTML isSafeToPassThrough="1">&lt;/em&gt;</rawHTML></Para></Abstract></Function>]
+
+/// <em>Aaa</em></b>
+void comment_to_xml_conversion_unsafe_html_05();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_unsafe_html_05:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_unsafe_html_05</Name><USR>c:@F@comment_to_xml_conversion_unsafe_html_05#</USR><Declaration>void comment_to_xml_conversion_unsafe_html_05()</Declaration><Abstract><Para> <rawHTML isSafeToPassThrough="1"><![CDATA[<em>]]></rawHTML>Aaa<rawHTML isSafeToPassThrough="1">&lt;/em&gt;</rawHTML><rawHTML>&lt;/b&gt;</rawHTML></Para></Abstract></Function>]
+
+/// </table>
+void comment_to_xml_conversion_unsafe_html_06();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_unsafe_html_06:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_unsafe_html_06</Name><USR>c:@F@comment_to_xml_conversion_unsafe_html_06#</USR><Declaration>void comment_to_xml_conversion_unsafe_html_06()</Declaration><Abstract><Para> <rawHTML>&lt;/table&gt;</rawHTML></Para></Abstract></Function>]
+
+/// <div onclick="alert('meow');">Aaa</div>
+void comment_to_xml_conversion_unsafe_html_07();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_unsafe_html_07:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_unsafe_html_07</Name><USR>c:@F@comment_to_xml_conversion_unsafe_html_07#</USR><Declaration>void comment_to_xml_conversion_unsafe_html_07()</Declaration><Abstract><Para> <rawHTML><![CDATA[<div onclick="alert('meow');">]]></rawHTML>Aaa<rawHTML>&lt;/div&gt;</rawHTML></Para></Abstract></Function>]
+
//===---
// Check that we attach comments from the base class to derived classes if they don't have a comment.
// rdar://13647476
diff --git a/test/Index/complete-macros.c b/test/Index/complete-macros.c
index 6d27b449ae..c81c8caad8 100644
--- a/test/Index/complete-macros.c
+++ b/test/Index/complete-macros.c
@@ -1,5 +1,5 @@
-// Note: the run lines follow their respective tests, since line/column
-// matter in this test.
+#include "complete-macros.h"
+// Note: the run lines follow their respective tests, since line/column matter in this test.
#define FOO(Arg1,Arg2) foobar
#define nil 0
#undef FOO
@@ -25,20 +25,23 @@ void test_variadic() {
}
-// RUN: c-index-test -code-completion-at=%s:7:1 %s | FileCheck -check-prefix=CHECK-CC0 %s
+// RUN: c-index-test -code-completion-at=%s:7:1 %s -I%S | FileCheck -check-prefix=CHECK-CC0 %s
// CHECK-CC0-NOT: FOO
-// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:1 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:7:1 %s -I%S | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: macro definition:{TypedText FOO}{LeftParen (}{Placeholder Arg1}{Comma , }{Placeholder Arg2}{RightParen )}
-// RUN: c-index-test -code-completion-at=%s:13:13 %s | FileCheck -check-prefix=CHECK-CC2 %s
-// RUN: c-index-test -code-completion-at=%s:14:8 %s | FileCheck -check-prefix=CHECK-CC2 %s
-// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:14:8 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// RUN: c-index-test -code-completion-at=%s:13:13 %s -I%S | FileCheck -check-prefix=CHECK-CC2 %s
+// RUN: c-index-test -code-completion-at=%s:14:8 %s -I%S | FileCheck -check-prefix=CHECK-CC2 %s
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:14:8 %s -I%S | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: macro definition:{TypedText nil} (32)
-// RUN: c-index-test -code-completion-at=%s:15:5 %s | FileCheck -check-prefix=CHECK-CC3 %s
-// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:15:5 %s | FileCheck -check-prefix=CHECK-CC3 %s
+// RUN: c-index-test -code-completion-at=%s:15:5 %s -I%S | FileCheck -check-prefix=CHECK-CC3 %s
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:15:5 %s -I%S | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: macro definition:{TypedText nil} (65)
-// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:25:2 %s | FileCheck -check-prefix=CHECK-VARIADIC %s
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:25:2 %s -I%S | FileCheck -check-prefix=CHECK-VARIADIC %s
// CHECK-VARIADIC: macro definition:{TypedText variadic1}{LeftParen (}{Placeholder ...}{RightParen )} (70)
// CHECK-VARIADIC: macro definition:{TypedText variadic2}{LeftParen (}{Placeholder args...}{RightParen )} (70)
// CHECK-VARIADIC: macro definition:{TypedText variadic3}{LeftParen (}{Placeholder args, ...}{RightParen )} (70)
// CHECK-VARIADIC: macro definition:{TypedText variadic4}{LeftParen (}{Placeholder first}{Comma , }{Placeholder second}{Comma , }{Placeholder args, ...}{RightParen )} (70)
// CHECK-VARIADIC: macro definition:{TypedText variadic5}{LeftParen (}{Placeholder first}{Comma , }{Placeholder second}{Comma , }{Placeholder args...}{RightParen )} (70)
+
+// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:15:5 %s -I%S | FileCheck -check-prefix=CHECK-CC4 %s
+// CHECK-CC4-NOT: COMPLETE_MACROS_H_GUARD
diff --git a/test/Index/complete-macros.h b/test/Index/complete-macros.h
new file mode 100644
index 0000000000..70f49e31a1
--- /dev/null
+++ b/test/Index/complete-macros.h
@@ -0,0 +1,6 @@
+#ifndef COMPLETE_MACROS_H_GUARD
+#define COMPLETE_MACROS_H_GUARD
+
+void in_header(int);
+
+#endif
diff --git a/test/Index/index-module-with-vfs.m b/test/Index/index-module-with-vfs.m
new file mode 100644
index 0000000000..f3ca60cf94
--- /dev/null
+++ b/test/Index/index-module-with-vfs.m
@@ -0,0 +1,26 @@
+// REQUIRES: shell
+@import ModuleNeedsVFS;
+
+void foo() {
+ module_needs_vfs();
+ base_module_needs_vfs();
+}
+
+// RUN: rm -rf %t.cache
+// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%t:g" %S/Inputs/vfsoverlay.yaml > %t.yaml
+// RUN: c-index-test -index-file %s -fmodules-cache-path=%t.cache -fmodules -F %t -I %t \
+// RUN: -ivfsoverlay %t.yaml -Xclang -fdisable-module-hash | FileCheck %s
+
+// CHECK: [importedASTFile]: {{.*}}ModuleNeedsVFS.pcm | loc: 2:1 | name: "ModuleNeedsVFS" | isImplicit: 0
+// CHECK: [indexEntityReference]: kind: function | name: module_needs_vfs
+// CHECK: [indexEntityReference]: kind: function | name: base_module_needs_vfs
+
+// RUN: c-index-test -index-tu %t.cache/ModuleNeedsVFS.pcm | FileCheck %s -check-prefix=CHECK-MOD
+
+// CHECK-MOD: [ppIncludedFile]: {{.*}}module_needs_vfs.h
+// CHECK-MOD: [importedASTFile]: {{.*}}BaseModuleNeedsVFS.pcm
+// CHECK-MOD: [indexEntityReference]: kind: function | name: base_module_needs_vfs
+
+// RUN: c-index-test -index-tu %t.cache/BaseModuleNeedsVFS.pcm | FileCheck %s -check-prefix=CHECK-MOD2
+
+// CHECK-MOD2: [ppIncludedFile]: {{.*}}base_module_needs_vfs.h
diff --git a/test/Index/load-classes.cpp b/test/Index/load-classes.cpp
index 9790d9e6f4..3b66be5398 100644
--- a/test/Index/load-classes.cpp
+++ b/test/Index/load-classes.cpp
@@ -7,13 +7,24 @@ protected:
~X();
private:
operator X*();
+
+ void constMemberFunction() const;
+ template<typename T>
+ void constMemberFunctionTemplate() const;
+
+ static void staticMemberFunction();
+ template<typename T>
+ static void staticMemberFunctionTemplate();
+
+ virtual void virtualMemberFunction();
+ virtual void pureVirtualMemberFunction() = 0;
};
X::X(int value) {
}
// RUN: c-index-test -test-load-source all %s | FileCheck %s
-// CHECK: load-classes.cpp:3:8: StructDecl=X:3:8 (Definition) Extent=[3:1 - 10:2]
+// CHECK: load-classes.cpp:3:8: StructDecl=X:3:8 (Definition) Extent=[3:1 - 21:2]
// CHECK: load-classes.cpp:4:3: CXXConstructor=X:4:3 Extent=[4:3 - 4:15] [access=public]
// FIXME: missing TypeRef in the constructor name
// CHECK: load-classes.cpp:4:9: ParmDecl=value:4:9 (Definition) Extent=[4:5 - 4:14]
@@ -21,10 +32,21 @@ X::X(int value) {
// FIXME: missing TypeRef in the constructor name
// CHECK: load-classes.cpp:5:14: ParmDecl=x:5:14 (Definition) Extent=[5:5 - 5:15]
// CHECK: load-classes.cpp:5:11: TypeRef=struct X:3:8 Extent=[5:11 - 5:12]
+// CHECK: load-classes.cpp:6:1: CXXAccessSpecifier=:6:1 (Definition) Extent=[6:1 - 6:11] [access=protected]
// CHECK: load-classes.cpp:7:3: CXXDestructor=~X:7:3 Extent=[7:3 - 7:7] [access=protected]
// FIXME: missing TypeRef in the destructor name
+// CHECK: load-classes.cpp:8:1: CXXAccessSpecifier=:8:1 (Definition) Extent=[8:1 - 8:9] [access=private]
// CHECK: load-classes.cpp:9:3: CXXConversion=operator X *:9:3 Extent=[9:3 - 9:16] [access=private]
// CHECK: load-classes.cpp:9:12: TypeRef=struct X:3:8 Extent=[9:12 - 9:13]
-// CHECK: load-classes.cpp:12:4: CXXConstructor=X:12:4 (Definition) Extent=[12:1 - 13:2] [access=public]
-// CHECK: load-classes.cpp:12:1: TypeRef=struct X:3:8 Extent=[12:1 - 12:2]
-// CHECK: load-classes.cpp:12:10: ParmDecl=value:12:10 (Definition) Extent=[12:6 - 12:15]
+// CHECK: load-classes.cpp:11:8: CXXMethod=constMemberFunction:11:8 (const) Extent=[11:3 - 11:35] [access=private]
+// CHECK: load-classes.cpp:13:8: FunctionTemplate=constMemberFunctionTemplate:13:8 (const) Extent=[12:3 - 13:43] [access=private]
+// CHECK: load-classes.cpp:12:21: TemplateTypeParameter=T:12:21 (Definition) Extent=[12:12 - 12:22] [access=public]
+// CHECK: load-classes.cpp:15:15: CXXMethod=staticMemberFunction:15:15 (static) Extent=[15:3 - 15:37] [access=private]
+// CHECK: load-classes.cpp:17:15: FunctionTemplate=staticMemberFunctionTemplate:17:15 (static) Extent=[16:3 - 17:45] [access=private]
+// CHECK: load-classes.cpp:16:21: TemplateTypeParameter=T:16:21 (Definition) Extent=[16:12 - 16:22] [access=public]
+// CHECK: load-classes.cpp:19:16: CXXMethod=virtualMemberFunction:19:16 (virtual) Extent=[19:3 - 19:39] [access=private]
+// CHECK: load-classes.cpp:20:16: CXXMethod=pureVirtualMemberFunction:20:16 (virtual) (pure) Extent=[20:3 - 20:47] [access=private]
+// CHECK: load-classes.cpp:23:4: CXXConstructor=X:23:4 (Definition) Extent=[23:1 - 24:2] [access=public]
+// CHECK: load-classes.cpp:23:1: TypeRef=struct X:3:8 Extent=[23:1 - 23:2]
+// CHECK: load-classes.cpp:23:10: ParmDecl=value:23:10 (Definition) Extent=[23:6 - 23:15]
+// CHECK: load-classes.cpp:23:17: CompoundStmt= Extent=[23:17 - 24:2]
diff --git a/test/Index/pch-depending-on-deleted-module.c b/test/Index/pch-depending-on-deleted-module.c
index 223b6361a8..4e85ff0f96 100644
--- a/test/Index/pch-depending-on-deleted-module.c
+++ b/test/Index/pch-depending-on-deleted-module.c
@@ -4,10 +4,10 @@
// RUN: mkdir %t
// RUN: %clang_cc1 -x c-header -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -emit-pch -I %S/Inputs/Headers -o %t/use_LibA.pch %s
-// RUN: %clang_cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -verify-pch %t/use_LibA.pch
+// RUN: %clang_cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -I %S/Inputs/Headers -verify-pch %t/use_LibA.pch
// RUN: rm -f %t/modules-cache/LibA.pcm
-// RUN: not %clang_cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=modules-cache -verify-pch %t/use_LibA.pch 2>&1 | FileCheck -check-prefix=VERIFY %s
-// RUN: not c-index-test -test-load-source all -x c -fmodules -fdisable-module-hash -fmodules-cache-path=modules-cache -include-pch %t/use_LibA.pch %s 2>&1 | FileCheck -check-prefix=INDEX %s
+// RUN: not %clang_cc1 -fmodules -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -I %S/Inputs/Headers -verify-pch %t/use_LibA.pch 2>&1 | FileCheck -check-prefix=VERIFY %s
+// RUN: not c-index-test -test-load-source all -x c -fmodules -Xclang -fdisable-module-hash -fmodules-cache-path=%t/modules-cache -I %S/Inputs/Headers -include-pch %t/use_LibA.pch %s 2>&1 | FileCheck -check-prefix=INDEX %s
// VERIFY: fatal error: malformed or corrupted AST file: 'Unable to load module
// INDEX: {{^}}Failure: AST deserialization error occurred{{$}}
diff --git a/test/Index/print-type.c b/test/Index/print-type.c
index 6c7095a4e5..35aab711db 100644
--- a/test/Index/print-type.c
+++ b/test/Index/print-type.c
@@ -14,27 +14,27 @@ int f2(int incompletearray[]);
// RUN: c-index-test -test-print-type %s | FileCheck %s
// CHECK: FunctionDecl=f:3:6 (Definition) [type=int *(int *, char *, FooType, int *, void (*)(int))] [typekind=FunctionProto] [canonicaltype=int *(int *, char *, int, int *, void (*)(int))] [canonicaltypekind=FunctionProto] [resulttype=int *] [resulttypekind=Pointer] [args= [int *] [Pointer] [char *] [Pointer] [FooType] [Typedef] [int [5]] [ConstantArray] [void (*)(int)] [Pointer]] [isPOD=0]
-// CHECK: ParmDecl=p:3:13 (Definition) [type=int *] [typekind=Pointer] [isPOD=1]
-// CHECK: ParmDecl=x:3:22 (Definition) [type=char *] [typekind=Pointer] [isPOD=1]
+// CHECK: ParmDecl=p:3:13 (Definition) [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
+// CHECK: ParmDecl=x:3:22 (Definition) [type=char *] [typekind=Pointer] [isPOD=1] [pointeetype=char] [pointeekind=Char_{{[US]}}]
// CHECK: ParmDecl=z:3:33 (Definition) [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: TypeRef=FooType:1:13 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: ParmDecl=arr:3:40 (Definition) [type=int [5]] [typekind=ConstantArray] [isPOD=1]
// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
-// CHECK: ParmDecl=fn:3:55 (Definition) [type=void (*)(int)] [typekind=Pointer] [canonicaltype=void (*)(int)] [canonicaltypekind=Pointer] [isPOD=1]
+// CHECK: ParmDecl=fn:3:55 (Definition) [type=void (*)(int)] [typekind=Pointer] [canonicaltype=void (*)(int)] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=void (int)] [pointeekind=Unexposed]
// CHECK: ParmDecl=:3:62 (Definition) [type=int] [typekind=Int] [isPOD=1]
// CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0]
// CHECK: CallExpr=fn:3:55 [type=void] [typekind=Void] [args= [int] [Int]] [isPOD=0]
-// CHECK: DeclRefExpr=fn:3:55 [type=void (*)(int)] [typekind=Pointer] [canonicaltype=void (*)(int)] [canonicaltypekind=Pointer] [isPOD=1]
+// CHECK: DeclRefExpr=fn:3:55 [type=void (*)(int)] [typekind=Pointer] [canonicaltype=void (*)(int)] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=void (int)] [pointeekind=Unexposed]
// CHECK: UnaryOperator= [type=int] [typekind=Int] [isPOD=1]
-// CHECK: DeclRefExpr=p:3:13 [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: DeclRefExpr=p:3:13 [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
// CHECK: DeclStmt= [type=] [typekind=Invalid] [isPOD=0]
// CHECK: VarDecl=w:5:17 (Definition) [type=const FooType] [typekind=Typedef] const [canonicaltype=const int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: TypeRef=FooType:1:13 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: DeclRefExpr=z:3:33 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: ReturnStmt= [type=] [typekind=Invalid] [isPOD=0]
-// CHECK: BinaryOperator= [type=int *] [typekind=Pointer] [isPOD=1]
-// CHECK: BinaryOperator= [type=int *] [typekind=Pointer] [isPOD=1]
-// CHECK: DeclRefExpr=p:3:13 [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: BinaryOperator= [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
+// CHECK: BinaryOperator= [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
+// CHECK: DeclRefExpr=p:3:13 [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
// CHECK: DeclRefExpr=z:3:33 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: ArraySubscriptExpr= [type=int] [typekind=Int] [isPOD=1]
// CHECK: UnexposedExpr=arr:3:40 [type=int [5]] [typekind=ConstantArray] [isPOD=1]
diff --git a/test/Index/print-type.cpp b/test/Index/print-type.cpp
index ef372a2fb7..af5c556c4d 100644
--- a/test/Index/print-type.cpp
+++ b/test/Index/print-type.cpp
@@ -60,15 +60,15 @@ int Blob::*member_pointer;
// CHECK: Namespace=inner:14:11 (Definition) [type=] [typekind=Invalid] [isPOD=0]
// CHECK: StructDecl=Bar:16:8 (Definition) [type=outer::inner::Bar] [typekind=Record] [isPOD=0]
// CHECK: CXXConstructor=Bar:17:3 (Definition) [type=void (outer::Foo<bool> *){{.*}}] [typekind=FunctionProto] [canonicaltype=void (outer::Foo<bool> *){{.*}}] [canonicaltypekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [args= [outer::Foo<bool> *] [Pointer]] [isPOD=0]
-// CHECK: ParmDecl=foo:17:25 (Definition) [type=outer::Foo<bool> *] [typekind=Pointer] [canonicaltype=outer::Foo<bool> *] [canonicaltypekind=Pointer] [isPOD=1]
+// CHECK: ParmDecl=foo:17:25 (Definition) [type=outer::Foo<bool> *] [typekind=Pointer] [canonicaltype=outer::Foo<bool> *] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=outer::Foo<bool>] [pointeekind=Unexposed]
// CHECK: NamespaceRef=outer:1:11 [type=] [typekind=Invalid] [isPOD=0]
// CHECK: TemplateRef=Foo:4:8 [type=] [typekind=Invalid] [isPOD=0]
// CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0]
// CHECK: TypedefDecl=FooType:19:15 (Definition) [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
-// CHECK: FieldDecl=p:20:8 (Definition) [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: FieldDecl=p:20:8 (Definition) [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
// CHECK: CXXMethod=f:21:8 (Definition) [type=int *(int *, char *, FooType){{.*}}] [typekind=FunctionProto] [canonicaltype=int *(int *, char *, int){{.*}}] [canonicaltypekind=FunctionProto] [resulttype=int *] [resulttypekind=Pointer] [args= [int *] [Pointer] [char *] [Pointer] [FooType] [Typedef]] [isPOD=0]
-// CHECK: ParmDecl=p:21:15 (Definition) [type=int *] [typekind=Pointer] [isPOD=1]
-// CHECK: ParmDecl=x:21:24 (Definition) [type=char *] [typekind=Pointer] [isPOD=1]
+// CHECK: ParmDecl=p:21:15 (Definition) [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
+// CHECK: ParmDecl=x:21:24 (Definition) [type=char *] [typekind=Pointer] [isPOD=1] [pointeetype=char] [pointeekind=Char_{{[US]}}]
// CHECK: ParmDecl=z:21:35 (Definition) [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: TypeRef=FooType:19:15 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0]
@@ -78,9 +78,9 @@ int Blob::*member_pointer;
// CHECK: UnexposedExpr=z:21:35 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: DeclRefExpr=z:21:35 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: ReturnStmt= [type=] [typekind=Invalid] [isPOD=0]
-// CHECK: BinaryOperator= [type=int *] [typekind=Pointer] [isPOD=1]
-// CHECK: UnexposedExpr=p:21:15 [type=int *] [typekind=Pointer] [isPOD=1]
-// CHECK: DeclRefExpr=p:21:15 [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: BinaryOperator= [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
+// CHECK: UnexposedExpr=p:21:15 [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
+// CHECK: DeclRefExpr=p:21:15 [type=int *] [typekind=Pointer] [isPOD=1] [pointeetype=int] [pointeekind=Int]
// CHECK: UnexposedExpr=z:21:35 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: DeclRefExpr=z:21:35 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
// CHECK: TypedefDecl=OtherType:25:18 (Definition) [type=OtherType] [typekind=Typedef] [canonicaltype=double] [canonicaltypekind=Double] [isPOD=1]
diff --git a/test/Index/print-type.m b/test/Index/print-type.m
index 6f146f8020..5a4272b131 100644
--- a/test/Index/print-type.m
+++ b/test/Index/print-type.m
@@ -12,4 +12,4 @@
// CHECK: ParmDecl=z:4:52 (Definition) [type=SEL] [typekind=ObjCSel] [canonicaltype=SEL *] [canonicaltypekind=Pointer] [isPOD=1]
// CHECK: ObjCInstanceMethodDecl=methodIn:andOut::5:10 (variadic) [Bycopy,] [type=] [typekind=Invalid] [resulttype=id] [resulttypekind=ObjCId] [args= [int] [Int] [short *] [Pointer]] [isPOD=0]
// CHECK: ParmDecl=i:5:27 (Definition) [In,] [type=int] [typekind=Int] [isPOD=1]
-// CHECK: ParmDecl=j:5:49 (Definition) [Out,] [type=short *] [typekind=Pointer] [isPOD=1]
+// CHECK: ParmDecl=j:5:49 (Definition) [Out,] [type=short *] [typekind=Pointer] [isPOD=1] [pointeetype=short] [pointeekind=Short]
diff --git a/test/Index/recursive-cxx-member-calls.cpp b/test/Index/recursive-cxx-member-calls.cpp
index ab30d43905..34a5652954 100644
--- a/test/Index/recursive-cxx-member-calls.cpp
+++ b/test/Index/recursive-cxx-member-calls.cpp
@@ -1680,17 +1680,17 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 49:60: MemberRef=Length:44:10 Extent=[49:60 - 49:66]
// CHECK: 49:67: DeclRefExpr=length:49:38 Extent=[49:67 - 49:73]
// CHECK: 49:75: CompoundStmt= Extent=[49:75 - 49:77]
-// CHECK: 50:12: CXXMethod=end:50:12 (Definition) Extent=[50:3 - 50:40]
+// CHECK: 50:12: CXXMethod=end:50:12 (Definition) (const) Extent=[50:3 - 50:40] [access=public]
// CHECK: 50:3: TypeRef=iterator:40:23 Extent=[50:3 - 50:11]
// CHECK: 50:24: CompoundStmt= Extent=[50:24 - 50:40]
// CHECK: 50:26: ReturnStmt= Extent=[50:26 - 50:37]
// CHECK: 50:33: MemberRefExpr=Data:43:15 Extent=[50:33 - 50:37]
-// CHECK: 51:10: CXXMethod=size:51:10 (Definition) Extent=[51:3 - 51:41]
+// CHECK: 51:10: CXXMethod=size:51:10 (Definition) (const) Extent=[51:3 - 51:41] [access=public]
// CHECK: 51:3: TypeRef=size_t:2:25 Extent=[51:3 - 51:9]
// CHECK: 51:23: CompoundStmt= Extent=[51:23 - 51:41]
// CHECK: 51:25: ReturnStmt= Extent=[51:25 - 51:38]
// CHECK: 51:32: MemberRefExpr=Length:44:10 Extent=[51:32 - 51:38]
-// CHECK: 52:8: CXXMethod=startswith:52:8 (Definition) Extent=[52:3 - 55:4]
+// CHECK: 52:8: CXXMethod=startswith:52:8 (Definition) (const) Extent=[52:3 - 55:4] [access=public]
// CHECK: 52:29: ParmDecl=Prefix:52:29 (Definition) Extent=[52:19 - 52:35]
// CHECK: 52:19: TypeRef=class llvm::StringRef:38:7 Extent=[52:19 - 52:28]
// CHECK: 52:43: CompoundStmt= Extent=[52:43 - 55:4]
@@ -1713,7 +1713,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 54:44: MemberRefExpr=Length:44:10 SingleRefName=[54:44 - 54:50] RefName=[54:44 - 54:50] Extent=[54:37 - 54:50]
// CHECK: 54:37: DeclRefExpr=Prefix:52:29 Extent=[54:37 - 54:43]
// CHECK: 54:55: IntegerLiteral= Extent=[54:55 - 54:56]
-// CHECK: 56:8: CXXMethod=endswith:56:8 (Definition) Extent=[56:3 - 59:4]
+// CHECK: 56:8: CXXMethod=endswith:56:8 (Definition) (const) Extent=[56:3 - 59:4] [access=public]
// CHECK: 56:27: ParmDecl=Suffix:56:27 (Definition) Extent=[56:17 - 56:33]
// CHECK: 56:17: TypeRef=class llvm::StringRef:38:7 Extent=[56:17 - 56:26]
// CHECK: 56:41: CompoundStmt= Extent=[56:41 - 59:4]
@@ -1740,7 +1740,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 58:57: MemberRefExpr=Length:44:10 SingleRefName=[58:57 - 58:63] RefName=[58:57 - 58:63] Extent=[58:50 - 58:63]
// CHECK: 58:50: DeclRefExpr=Suffix:56:27 Extent=[58:50 - 58:56]
// CHECK: 58:68: IntegerLiteral= Extent=[58:68 - 58:69]
-// CHECK: 60:13: CXXMethod=substr:60:13 (Definition) Extent=[60:3 - 62:4]
+// CHECK: 60:13: CXXMethod=substr:60:13 (Definition) (const) Extent=[60:3 - 62:4] [access=public]
// CHECK: 60:3: TypeRef=class llvm::StringRef:38:7 Extent=[60:3 - 60:12]
// CHECK: 60:27: ParmDecl=Start:60:27 (Definition) Extent=[60:20 - 60:32]
// CHECK: 60:20: TypeRef=size_t:2:25 Extent=[60:20 - 60:26]
@@ -1769,7 +1769,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 66:7: ClassDecl=IdentifierInfo:66:7 (Definition) Extent=[66:1 - 80:2]
// CHECK: 67:1: CXXAccessSpecifier=:67:1 (Definition) Extent=[67:1 - 67:8]
// CHECK: 67:8: CXXConstructor=IdentifierInfo:67:8 Extent=[67:8 - 67:24]
-// CHECK: 68:15: CXXMethod=getNameStart:68:15 (Definition) Extent=[68:3 - 71:4]
+// CHECK: 68:15: CXXMethod=getNameStart:68:15 (Definition) (const) Extent=[68:3 - 71:4] [access=public]
// CHECK: 68:36: CompoundStmt= Extent=[68:36 - 71:4]
// CHECK: 69:5: DeclStmt= Extent=[69:5 - 69:65]
// CHECK: 69:54: TypedefDecl=actualtype:69:54 (Definition) Extent=[69:5 - 69:64]
@@ -1781,7 +1781,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 70:13: CStyleCastExpr= Extent=[70:13 - 70:38]
// CHECK: 70:20: TypeRef=actualtype:69:54 Extent=[70:20 - 70:30]
// CHECK: 70:34: CXXThisExpr= Extent=[70:34 - 70:38]
-// CHECK: 72:12: CXXMethod=getLength:72:12 (Definition) Extent=[72:3 - 76:4]
+// CHECK: 72:12: CXXMethod=getLength:72:12 (Definition) (const) Extent=[72:3 - 76:4] [access=public]
// CHECK: 72:30: CompoundStmt= Extent=[72:30 - 76:4]
// CHECK: 73:5: DeclStmt= Extent=[73:5 - 73:65]
// CHECK: 73:54: TypedefDecl=actualtype:73:54 (Definition) Extent=[73:5 - 73:64]
@@ -1820,7 +1820,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 75:55: IntegerLiteral= Extent=[75:55 - 75:56]
// CHECK: 75:61: UnexposedExpr= Extent=[75:61 - 75:62]
// CHECK: 75:61: IntegerLiteral= Extent=[75:61 - 75:62]
-// CHECK: 77:19: CXXMethod=getName:77:19 (Definition) Extent=[77:3 - 79:4]
+// CHECK: 77:19: CXXMethod=getName:77:19 (Definition) (const) Extent=[77:3 - 79:4] [access=public]
// CHECK: 77:35: CompoundStmt= Extent=[77:35 - 79:4]
// CHECK: 78:5: ReturnStmt= Extent=[78:5 - 78:56]
// CHECK: 78:12: CallExpr= Extent=[78:12 - 78:56]
@@ -1858,7 +1858,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 90:5: ReturnStmt= Extent=[90:5 - 90:17]
// CHECK: 90:12: UnaryOperator= Extent=[90:12 - 90:17]
// CHECK: 90:13: CXXThisExpr= Extent=[90:13 - 90:17]
-// CHECK: 92:5: CXXMethod=Default:92:5 (Definition) Extent=[92:3 - 94:4]
+// CHECK: 92:5: CXXMethod=Default:92:5 (Definition) (const) Extent=[92:3 - 94:4] [access=public]
// CHECK: 92:23: ParmDecl=Value:92:23 (Definition) Extent=[92:13 - 92:28]
// CHECK: 92:36: CompoundStmt= Extent=[92:36 - 94:4]
// CHECK: 93:5: ReturnStmt= Extent=[93:5 - 93:17]
diff --git a/test/Layout/ms-x86-alias-avoidance-padding.cpp b/test/Layout/ms-x86-alias-avoidance-padding.cpp
index aac652135a..e51bab3871 100644
--- a/test/Layout/ms-x86-alias-avoidance-padding.cpp
+++ b/test/Layout/ms-x86-alias-avoidance-padding.cpp
@@ -298,6 +298,287 @@ struct JC4 : JC1, JC2 {
// CHECK-X64-NEXT: | [sizeof=24, align=8
// CHECK-X64-NEXT: | nvsize=24, nvalign=8]
+struct RA {};
+struct RB { char c; };
+struct RV {};
+struct RW { char c; };
+struct RY { RY() { printf("%Id\n", (char*)this - buffer); } };
+struct RX0 : RB, RA {};
+struct RX1 : RA, RB {};
+struct RX2 : RA { char a; };
+struct RX3 : RA { RB a; };
+struct RX4 { RA a; char b; };
+struct RX5 { RA a; RB b; };
+struct RX6 : virtual RV { RB a; };
+struct RX7 : virtual RW { RA a; };
+struct RX8 : RA, virtual RW {};
+
+struct RZ0 : RX0, RY {};
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct RZ0
+// CHECK-NEXT: 0 | struct RX0 (base)
+// CHECK-NEXT: 0 | struct RB (base)
+// CHECK-NEXT: 0 | char c
+// CHECK-NEXT: 1 | struct RA (base) (empty)
+// CHECK-NEXT: 2 | struct RY (base) (empty)
+// CHECK-NEXT: | [sizeof=2, align=1
+// CHECK-NEXT: | nvsize=2, nvalign=1]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct RZ0
+// CHECK-X64-NEXT: 0 | struct RX0 (base)
+// CHECK-X64-NEXT: 0 | struct RB (base)
+// CHECK-X64-NEXT: 0 | char c
+// CHECK-X64-NEXT: 1 | struct RA (base) (empty)
+// CHECK-X64-NEXT: 2 | struct RY (base) (empty)
+// CHECK-X64-NEXT: | [sizeof=2, align=1
+// CHECK-X64-NEXT: | nvsize=2, nvalign=1]
+
+struct RZ1 : RX1, RY {};
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct RZ1
+// CHECK-NEXT: 0 | struct RX1 (base)
+// CHECK-NEXT: 0 | struct RA (base) (empty)
+// CHECK-NEXT: 0 | struct RB (base)
+// CHECK-NEXT: 0 | char c
+// CHECK-NEXT: 1 | struct RY (base) (empty)
+// CHECK-NEXT: | [sizeof=1, align=1
+// CHECK-NEXT: | nvsize=1, nvalign=1]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct RZ1
+// CHECK-X64-NEXT: 0 | struct RX1 (base)
+// CHECK-X64-NEXT: 0 | struct RA (base) (empty)
+// CHECK-X64-NEXT: 0 | struct RB (base)
+// CHECK-X64-NEXT: 0 | char c
+// CHECK-X64-NEXT: 1 | struct RY (base) (empty)
+// CHECK-X64-NEXT: | [sizeof=1, align=1
+// CHECK-X64-NEXT: | nvsize=1, nvalign=1]
+
+struct RZ2 : RX2, RY {};
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct RZ2
+// CHECK-NEXT: 0 | struct RX2 (base)
+// CHECK-NEXT: 0 | struct RA (base) (empty)
+// CHECK-NEXT: 0 | char a
+// CHECK-NEXT: 2 | struct RY (base) (empty)
+// CHECK-NEXT: | [sizeof=2, align=1
+// CHECK-NEXT: | nvsize=2, nvalign=1]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct RZ2
+// CHECK-X64-NEXT: 0 | struct RX2 (base)
+// CHECK-X64-NEXT: 0 | struct RA (base) (empty)
+// CHECK-X64-NEXT: 0 | char a
+// CHECK-X64-NEXT: 2 | struct RY (base) (empty)
+// CHECK-X64-NEXT: | [sizeof=2, align=1
+// CHECK-X64-NEXT: | nvsize=2, nvalign=1]
+
+struct RZ3 : RX3, RY {};
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct RZ3
+// CHECK-NEXT: 0 | struct RX3 (base)
+// CHECK-NEXT: 0 | struct RA (base) (empty)
+// CHECK-NEXT: 0 | struct RB a
+// CHECK-NEXT: 0 | char c
+// CHECK-NEXT: | [sizeof=1, align=1
+// CHECK-NEXT: | nvsize=1, nvalign=1]
+// CHECK-NEXT: 1 | struct RY (base) (empty)
+// CHECK-NEXT: | [sizeof=1, align=1
+// CHECK-NEXT: | nvsize=1, nvalign=1]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct RZ3
+// CHECK-X64-NEXT: 0 | struct RX3 (base)
+// CHECK-X64-NEXT: 0 | struct RA (base) (empty)
+// CHECK-X64-NEXT: 0 | struct RB a
+// CHECK-X64-NEXT: 0 | char c
+// CHECK-X64-NEXT: | [sizeof=1, align=1
+// CHECK-X64-NEXT: | nvsize=1, nvalign=1]
+// CHECK-X64-NEXT: 1 | struct RY (base) (empty)
+// CHECK-X64-NEXT: | [sizeof=1, align=1
+// CHECK-X64-NEXT: | nvsize=1, nvalign=1]
+
+struct RZ4 : RX4, RY {};
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct RZ4
+// CHECK-NEXT: 0 | struct RX4 (base)
+// CHECK-NEXT: 0 | struct RA a (empty)
+// CHECK-NEXT: | [sizeof=1, align=1
+// CHECK-NEXT: | nvsize=0, nvalign=1]
+// CHECK-NEXT: 1 | char b
+// CHECK-NEXT: 3 | struct RY (base) (empty)
+// CHECK-NEXT: | [sizeof=3, align=1
+// CHECK-NEXT: | nvsize=3, nvalign=1]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct RZ4
+// CHECK-X64-NEXT: 0 | struct RX4 (base)
+// CHECK-X64-NEXT: 0 | struct RA a (empty)
+// CHECK-X64-NEXT: | [sizeof=1, align=1
+// CHECK-X64-NEXT: | nvsize=0, nvalign=1]
+// CHECK-X64-NEXT: 1 | char b
+// CHECK-X64-NEXT: 3 | struct RY (base) (empty)
+// CHECK-X64-NEXT: | [sizeof=3, align=1
+// CHECK-X64-NEXT: | nvsize=3, nvalign=1]
+
+struct RZ5 : RX5, RY {};
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct RZ5
+// CHECK-NEXT: 0 | struct RX5 (base)
+// CHECK-NEXT: 0 | struct RA a (empty)
+// CHECK-NEXT: | [sizeof=1, align=1
+// CHECK-NEXT: | nvsize=0, nvalign=1]
+// CHECK-NEXT: 1 | struct RB b
+// CHECK-NEXT: 1 | char c
+// CHECK-NEXT: | [sizeof=1, align=1
+// CHECK-NEXT: | nvsize=1, nvalign=1]
+// CHECK-NEXT: 2 | struct RY (base) (empty)
+// CHECK-NEXT: | [sizeof=2, align=1
+// CHECK-NEXT: | nvsize=2, nvalign=1]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct RZ5
+// CHECK-X64-NEXT: 0 | struct RX5 (base)
+// CHECK-X64-NEXT: 0 | struct RA a (empty)
+// CHECK-X64-NEXT: | [sizeof=1, align=1
+// CHECK-X64-NEXT: | nvsize=0, nvalign=1]
+// CHECK-X64-NEXT: 1 | struct RB b
+// CHECK-X64-NEXT: 1 | char c
+// CHECK-X64-NEXT: | [sizeof=1, align=1
+// CHECK-X64-NEXT: | nvsize=1, nvalign=1]
+// CHECK-X64-NEXT: 2 | struct RY (base) (empty)
+// CHECK-X64-NEXT: | [sizeof=2, align=1
+// CHECK-X64-NEXT: | nvsize=2, nvalign=1]
+
+struct RZ6 : RX6, RY {};
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct RZ6
+// CHECK-NEXT: 0 | struct RX6 (base)
+// CHECK-NEXT: 0 | (RX6 vbtable pointer)
+// CHECK-NEXT: 4 | struct RB a
+// CHECK-NEXT: 4 | char c
+// CHECK-NEXT: | [sizeof=1, align=1
+// CHECK-NEXT: | nvsize=1, nvalign=1]
+// CHECK-NEXT: 9 | struct RY (base) (empty)
+// CHECK-NEXT: 12 | struct RV (virtual base) (empty)
+// CHECK-NEXT: | [sizeof=12, align=4
+// CHECK-NEXT: | nvsize=12, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct RZ6
+// CHECK-X64-NEXT: 0 | struct RX6 (base)
+// CHECK-X64-NEXT: 0 | (RX6 vbtable pointer)
+// CHECK-X64-NEXT: 8 | struct RB a
+// CHECK-X64-NEXT: 8 | char c
+// CHECK-X64-NEXT: | [sizeof=1, align=1
+// CHECK-X64-NEXT: | nvsize=1, nvalign=1]
+// CHECK-X64-NEXT: 17 | struct RY (base) (empty)
+// CHECK-X64-NEXT: 24 | struct RV (virtual base) (empty)
+// CHECK-X64-NEXT: | [sizeof=24, align=8
+// CHECK-X64-NEXT: | nvsize=24, nvalign=8]
+
+struct RZ7 : RX7, RY {};
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct RZ7
+// CHECK-NEXT: 0 | struct RX7 (base)
+// CHECK-NEXT: 0 | (RX7 vbtable pointer)
+// CHECK-NEXT: 4 | struct RA a (empty)
+// CHECK-NEXT: | [sizeof=1, align=1
+// CHECK-NEXT: | nvsize=0, nvalign=1]
+// CHECK-NEXT: 8 | struct RY (base) (empty)
+// CHECK-NEXT: 8 | struct RW (virtual base)
+// CHECK-NEXT: 8 | char c
+// CHECK-NEXT: | [sizeof=9, align=4
+// CHECK-NEXT: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct RZ7
+// CHECK-X64-NEXT: 0 | struct RX7 (base)
+// CHECK-X64-NEXT: 0 | (RX7 vbtable pointer)
+// CHECK-X64-NEXT: 8 | struct RA a (empty)
+// CHECK-X64-NEXT: | [sizeof=1, align=1
+// CHECK-X64-NEXT: | nvsize=0, nvalign=1]
+// CHECK-X64-NEXT: 16 | struct RY (base) (empty)
+// CHECK-X64-NEXT: 16 | struct RW (virtual base)
+// CHECK-X64-NEXT: 16 | char c
+// CHECK-X64-NEXT: | [sizeof=24, align=8
+// CHECK-X64-NEXT: | nvsize=16, nvalign=8]
+
+struct RZ8 : RX8, RY {};
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct RZ8
+// CHECK-NEXT: 0 | struct RX8 (base)
+// CHECK-NEXT: 4 | struct RA (base) (empty)
+// CHECK-NEXT: 0 | (RX8 vbtable pointer)
+// CHECK-NEXT: 4 | struct RY (base) (empty)
+// CHECK-NEXT: 4 | struct RW (virtual base)
+// CHECK-NEXT: 4 | char c
+// CHECK-NEXT: | [sizeof=5, align=4
+// CHECK-NEXT: | nvsize=4, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct RZ8
+// CHECK-X64-NEXT: 0 | struct RX8 (base)
+// CHECK-X64-NEXT: 8 | struct RA (base) (empty)
+// CHECK-X64-NEXT: 0 | (RX8 vbtable pointer)
+// CHECK-X64-NEXT: 8 | struct RY (base) (empty)
+// CHECK-X64-NEXT: 8 | struct RW (virtual base)
+// CHECK-X64-NEXT: 8 | char c
+// CHECK-X64-NEXT: | [sizeof=16, align=8
+// CHECK-X64-NEXT: | nvsize=8, nvalign=8]
+
+struct JA {};
+struct JB {};
+struct JC : JA { virtual void f() {} };
+struct JD : virtual JB, virtual JC { virtual void f() {} JD() {} };
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct JD
+// CHECK-NEXT: 0 | (JD vbtable pointer)
+// CHECK-NEXT: 4 | struct JB (virtual base) (empty)
+// CHECK-NEXT: 4 | (vtordisp for vbase JC)
+// CHECK-NEXT: 8 | struct JC (virtual base)
+// CHECK-NEXT: 8 | (JC vftable pointer)
+// CHECK-NEXT: 12 | struct JA (base) (empty)
+// CHECK-NEXT: | [sizeof=12, align=4
+// CHECK-NEXT: | nvsize=4, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct JD
+// CHECK-X64-NEXT: 0 | (JD vbtable pointer)
+// CHECK-X64-NEXT: 8 | struct JB (virtual base) (empty)
+// CHECK-X64-NEXT: 12 | (vtordisp for vbase JC)
+// CHECK-X64-NEXT: 16 | struct JC (virtual base)
+// CHECK-X64-NEXT: 16 | (JC vftable pointer)
+// CHECK-X64-NEXT: 24 | struct JA (base) (empty)
+// CHECK-X64-NEXT: | [sizeof=24, align=8
+// CHECK-X64-NEXT: | nvsize=8, nvalign=8]
+
int a[
sizeof(AT3) +
sizeof(BT3) +
@@ -305,4 +586,14 @@ sizeof(T3) +
sizeof(E) +
sizeof(F) +
sizeof(JC4) +
+sizeof(RZ0) +
+sizeof(RZ1) +
+sizeof(RZ2) +
+sizeof(RZ3) +
+sizeof(RZ4) +
+sizeof(RZ5) +
+sizeof(RZ6) +
+sizeof(RZ7) +
+sizeof(RZ8) +
+sizeof(JD) +
0];
diff --git a/test/Layout/ms-x86-bitfields-vbases.cpp b/test/Layout/ms-x86-bitfields-vbases.cpp
index 7cffa8c8e4..5b54596bbb 100644
--- a/test/Layout/ms-x86-bitfields-vbases.cpp
+++ b/test/Layout/ms-x86-bitfields-vbases.cpp
@@ -13,17 +13,17 @@ struct A : virtual B0 { char a : 1; };
// CHECK-NEXT: 0 | struct A
// CHECK-NEXT: 0 | (A vbtable pointer)
// CHECK-NEXT: 4 | char a
-// CHECK-NEXT: 12 | struct B0 (virtual base)
-// CHECK-NEXT: 12 | int a
-// CHECK-NEXT: | [sizeof=16, align=4
+// CHECK-NEXT: 8 | struct B0 (virtual base)
+// CHECK-NEXT: 8 | int a
+// CHECK-NEXT: | [sizeof=12, align=4
// CHECK-NEXT: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct A
// CHECK-X64-NEXT: 0 | (A vbtable pointer)
// CHECK-X64-NEXT: 8 | char a
-// CHECK-X64-NEXT: 20 | struct B0 (virtual base)
-// CHECK-X64-NEXT: 20 | int a
+// CHECK-X64-NEXT: 16 | struct B0 (virtual base)
+// CHECK-X64-NEXT: 16 | int a
// CHECK-X64-NEXT: | [sizeof=24, align=8
// CHECK-X64-NEXT: | nvsize=16, nvalign=8]
@@ -33,16 +33,16 @@ struct B : virtual B0 { short a : 1; };
// CHECK-NEXT: 0 | struct B
// CHECK-NEXT: 0 | (B vbtable pointer)
// CHECK-NEXT: 4 | short a
-// CHECK-NEXT: 12 | struct B0 (virtual base)
-// CHECK-NEXT: 12 | int a
-// CHECK-NEXT: | [sizeof=16, align=4
+// CHECK-NEXT: 8 | struct B0 (virtual base)
+// CHECK-NEXT: 8 | int a
+// CHECK-NEXT: | [sizeof=12, align=4
// CHECK-NEXT: | nvsize=8, nvalign=4]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct B
// CHECK-X64-NEXT: 0 | (B vbtable pointer)
// CHECK-X64-NEXT: 8 | short a
-// CHECK-X64-NEXT: 20 | struct B0 (virtual base)
-// CHECK-X64-NEXT: 20 | int a
+// CHECK-X64-NEXT: 16 | struct B0 (virtual base)
+// CHECK-X64-NEXT: 16 | int a
// CHECK-X64-NEXT: | [sizeof=24, align=8
// CHECK-X64-NEXT: | nvsize=16, nvalign=8]
@@ -94,22 +94,22 @@ struct E : virtual B0, virtual B1 { long long : 1; };
// CHECK-NEXT: 0 | struct E
// CHECK-NEXT: 0 | (E vbtable pointer)
// CHECK-NEXT: 8 | long long
-// CHECK-NEXT: 24 | struct B0 (virtual base)
-// CHECK-NEXT: 24 | int a
-// CHECK-NEXT: 36 | struct B1 (virtual base)
-// CHECK-NEXT: 36 | int a
-// CHECK-NEXT: | [sizeof=40, align=8
+// CHECK-NEXT: 16 | struct B0 (virtual base)
+// CHECK-NEXT: 16 | int a
+// CHECK-NEXT: 20 | struct B1 (virtual base)
+// CHECK-NEXT: 20 | int a
+// CHECK-NEXT: | [sizeof=24, align=8
// CHECK-NEXT: | nvsize=16, nvalign=8]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct E
// CHECK-X64-NEXT: 0 | (E vbtable pointer)
// CHECK-X64-NEXT: 8 | long long
-// CHECK-X64-NEXT: 24 | struct B0 (virtual base)
-// CHECK-X64-NEXT: 24 | int a
-// CHECK-X64-NEXT: 36 | struct B1 (virtual base)
-// CHECK-X64-NEXT: 36 | int a
-// CHECK-X64-NEXT: | [sizeof=40, align=8
+// CHECK-X64-NEXT: 16 | struct B0 (virtual base)
+// CHECK-X64-NEXT: 16 | int a
+// CHECK-X64-NEXT: 20 | struct B1 (virtual base)
+// CHECK-X64-NEXT: 20 | int a
+// CHECK-X64-NEXT: | [sizeof=24, align=8
// CHECK-X64-NEXT: | nvsize=16, nvalign=8]
int a[
diff --git a/test/Layout/ms-x86-lazy-empty-nonvirtual-base.cpp b/test/Layout/ms-x86-lazy-empty-nonvirtual-base.cpp
index 5bea872ae1..34ae0cf9dd 100644
--- a/test/Layout/ms-x86-lazy-empty-nonvirtual-base.cpp
+++ b/test/Layout/ms-x86-lazy-empty-nonvirtual-base.cpp
@@ -766,6 +766,45 @@ struct C2 : public C1, public C0 {};
// CHECK-X64-NEXT: | [sizeof=8, align=4
// CHECK-X64-NEXT: | nvsize=8, nvalign=4]
+struct JA { char a; };
+struct JB {
+ char a;
+ virtual void f() {}
+};
+struct JC { char a; };
+struct JD : JA, JB, virtual JC {};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct JD
+// CHECK-NEXT: 0 | struct JB (primary base)
+// CHECK-NEXT: 0 | (JB vftable pointer)
+// CHECK-NEXT: 4 | char a
+// CHECK-NEXT: 12 | struct JA (base)
+// CHECK-NEXT: 12 | char a
+// CHECK-NEXT: 8 | (JD vbtable pointer)
+// CHECK-NEXT: 16 | struct JC (virtual base)
+// CHECK-NEXT: 16 | char a
+// CHECK-NEXT: | [sizeof=17, align=4
+// CHECK-NEXT: | nvsize=16, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct JD
+// CHECK-X64-NEXT: 0 | struct JB (primary base)
+// CHECK-X64-NEXT: 0 | (JB vftable pointer)
+// CHECK-X64-NEXT: 8 | char a
+// CHECK-X64-NEXT: 24 | struct JA (base)
+// CHECK-X64-NEXT: 24 | char a
+// CHECK-X64-NEXT: 16 | (JD vbtable pointer)
+// CHECK-X64-NEXT: 32 | struct JC (virtual base)
+// CHECK-X64-NEXT: 32 | char a
+// CHECK-X64-NEXT: | [sizeof=40, align=8
+// CHECK-X64-NEXT: | nvsize=32, nvalign=8]
+
int a[
sizeof(AA)+
sizeof(AB)+
@@ -793,4 +832,6 @@ sizeof(AX)+
sizeof(BX)+
sizeof(CX)+
sizeof(DX)+
-sizeof(C2)];
+sizeof(C2)+
+sizeof(JD)+
+0];
diff --git a/test/Layout/ms-x86-pack-and-align.cpp b/test/Layout/ms-x86-pack-and-align.cpp
index 27de729074..be0499c2cb 100644
--- a/test/Layout/ms-x86-pack-and-align.cpp
+++ b/test/Layout/ms-x86-pack-and-align.cpp
@@ -40,7 +40,9 @@ struct X {
// CHECK-NEXT: 0 | struct X
// CHECK-NEXT: 0 | struct B a
// CHECK-NEXT: 0 | long long a
-// CHECK: 8 | char b
+// CHECK-NEXT: | [sizeof=8, align=8
+// CHECK-NEXT: | nvsize=8, nvalign=8]
+// CHECK-NEXT: 8 | char b
// CHECK-NEXT: 10 | int c
// CHECK-NEXT: | [sizeof=16, align=4
// CHECK-NEXT: | nvsize=14, nvalign=4]
@@ -49,7 +51,9 @@ struct X {
// CHECK-X64-NEXT: 0 | struct X
// CHECK-X64-NEXT: 0 | struct B a
// CHECK-X64-NEXT: 0 | long long a
-// CHECK-X64: 8 | char b
+// CHECK-X64-NEXT: | [sizeof=8, align=8
+// CHECK-X64-NEXT: | nvsize=8, nvalign=8]
+// CHECK-X64-NEXT: 8 | char b
// CHECK-X64-NEXT: 10 | int c
// CHECK-X64-NEXT: | [sizeof=16, align=4
// CHECK-X64-NEXT: | nvsize=14, nvalign=4]
@@ -208,14 +212,18 @@ struct YB {
// CHECK-NEXT: 0 | char a
// CHECK-NEXT: 1 | struct YA b (empty)
// CHECK-NEXT: 1 | char
-// CHECK: | [sizeof=33, align=1
+// CHECK-NEXT: | [sizeof=32, align=32
+// CHECK-NEXT: | nvsize=32, nvalign=32]
+// CHECK-NEXT: | [sizeof=33, align=1
// CHECK-NEXT: | nvsize=33, nvalign=1]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct YB
// CHECK-X64-NEXT: 0 | char a
// CHECK-X64-NEXT: 1 | struct YA b (empty)
// CHECK-X64-NEXT: 1 | char
-// CHECK-X64: | [sizeof=33, align=1
+// CHECK-X64-NEXT: | [sizeof=32, align=32
+// CHECK-X64-NEXT: | nvsize=32, nvalign=32]
+// CHECK-X64-NEXT: | [sizeof=33, align=1
// CHECK-X64-NEXT: | nvsize=33, nvalign=1]
#pragma pack(8)
@@ -230,8 +238,8 @@ struct YC {
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct YC (empty)
// CHECK-X64-NEXT: 0 | char
-// CHECK-X64-NEXT: | [sizeof=8, align=8
-// CHECK-X64-NEXT: | nvsize=8, nvalign=8]
+// CHECK-X64-NEXT: | [sizeof=8, align=32
+// CHECK-X64-NEXT: | nvsize=8, nvalign=32]
#pragma pack(1)
struct YD {
@@ -243,14 +251,18 @@ struct YD {
// CHECK-NEXT: 0 | char a
// CHECK-NEXT: 1 | struct YC b (empty)
// CHECK-NEXT: 1 | char
-// CHECK: | [sizeof=33, align=1
+// CHECK-NEXT: | [sizeof=32, align=32
+// CHECK-NEXT: | nvsize=32, nvalign=32]
+// CHECK-NEXT: | [sizeof=33, align=1
// CHECK-NEXT: | nvsize=33, nvalign=1]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct YD
// CHECK-X64-NEXT: 0 | char a
// CHECK-X64-NEXT: 1 | struct YC b (empty)
// CHECK-X64-NEXT: 1 | char
-// CHECK-X64: | [sizeof=9, align=1
+// CHECK-X64-NEXT: | [sizeof=8, align=32
+// CHECK-X64-NEXT: | nvsize=8, nvalign=32]
+// CHECK-X64-NEXT: | [sizeof=9, align=1
// CHECK-X64-NEXT: | nvsize=9, nvalign=1]
#pragma pack(4)
@@ -260,13 +272,13 @@ struct YE {
// CHECK: *** Dumping AST Record Layout
// CHECK-NEXT: 0 | struct YE (empty)
// CHECK-NEXT: 0 | char
-// CHECK-NEXT: | [sizeof=4, align=4
-// CHECK-NEXT: | nvsize=4, nvalign=4]
+// CHECK-NEXT: | [sizeof=4, align=32
+// CHECK-NEXT: | nvsize=4, nvalign=32]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct YE (empty)
// CHECK-X64-NEXT: 0 | char
-// CHECK-X64-NEXT: | [sizeof=4, align=4
-// CHECK-X64-NEXT: | nvsize=4, nvalign=4]
+// CHECK-X64-NEXT: | [sizeof=4, align=32
+// CHECK-X64-NEXT: | nvsize=4, nvalign=32]
#pragma pack(1)
struct YF {
@@ -278,14 +290,18 @@ struct YF {
// CHECK-NEXT: 0 | char a
// CHECK-NEXT: 1 | struct YE b (empty)
// CHECK-NEXT: 1 | char
-// CHECK: | [sizeof=5, align=1
+// CHECK-NEXT: | [sizeof=4, align=32
+// CHECK-NEXT: | nvsize=4, nvalign=32]
+// CHECK-NEXT: | [sizeof=5, align=1
// CHECK-NEXT: | nvsize=5, nvalign=1]
// CHECK-X64: *** Dumping AST Record Layout
// CHECK-X64-NEXT: 0 | struct YF
// CHECK-X64-NEXT: 0 | char a
// CHECK-X64-NEXT: 1 | struct YE b (empty)
// CHECK-X64-NEXT: 1 | char
-// CHECK-X64: | [sizeof=5, align=1
+// CHECK-X64-NEXT: | [sizeof=4, align=32
+// CHECK-X64-NEXT: | nvsize=4, nvalign=32]
+// CHECK-X64-NEXT: | [sizeof=5, align=1
// CHECK-X64-NEXT: | nvsize=5, nvalign=1]
#pragma pack(16)
@@ -411,6 +427,123 @@ struct MB : virtual MA {
// CHECK-X64-NEXT: | [sizeof=512, align=256
// CHECK-X64-NEXT: | nvsize=260, nvalign=256]
+struct RA {};
+#pragma pack(1)
+struct __declspec(align(8)) RB0 {
+ __declspec(align(1024)) int b : 3;
+};
+
+struct __declspec(align(8)) RB1 {
+ __declspec(align(1024)) int b : 3;
+ virtual void f() {}
+};
+
+struct __declspec(align(8)) RB2 : virtual RA {
+ __declspec(align(1024)) int b : 3;
+};
+
+struct __declspec(align(8)) RB3 : virtual RA {
+ __declspec(align(1024)) int b : 3;
+ virtual void f() {}
+};
+
+struct RC {
+ char _;
+ __declspec(align(1024)) int c : 3;
+};
+struct RE {
+ char _;
+ RC c;
+};
+#pragma pack()
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct RB0
+// CHECK-NEXT: 0 | int b
+// CHECK-NEXT: | [sizeof=8, align=1024
+// CHECK-NEXT: | nvsize=4, nvalign=1024]
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct RB1
+// CHECK-NEXT: 0 | (RB1 vftable pointer)
+// CHECK-NEXT: 1024 | int b
+// CHECK-NEXT: | [sizeof=1032, align=1024
+// CHECK-NEXT: | nvsize=1028, nvalign=1024]
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct RB2
+// CHECK-NEXT: 0 | (RB2 vbtable pointer)
+// CHECK-NEXT: 1024 | int b
+// CHECK-NEXT: 1028 | struct RA (virtual base) (empty)
+// CHECK-NEXT: | [sizeof=1032, align=1024
+// CHECK-NEXT: | nvsize=1028, nvalign=1024]
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct RB3
+// CHECK-NEXT: 0 | (RB3 vftable pointer)
+// CHECK-NEXT: 1024 | (RB3 vbtable pointer)
+// CHECK-NEXT: 2048 | int b
+// CHECK-NEXT: 2052 | struct RA (virtual base) (empty)
+// CHECK-NEXT: | [sizeof=2056, align=1024
+// CHECK-NEXT: | nvsize=2052, nvalign=1024]
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct RC
+// CHECK-NEXT: 0 | char _
+// CHECK-NEXT: 1024 | int c
+// CHECK-NEXT: | [sizeof=1028, align=1024
+// CHECK-NEXT: | nvsize=1028, nvalign=1024]
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct RE
+// CHECK-NEXT: 0 | char _
+// CHECK-NEXT: 1 | struct RC c
+// CHECK-NEXT: 1 | char _
+// CHECK-NEXT: 1025 | int c
+// CHECK-NEXT: | [sizeof=1028, align=1024
+// CHECK-NEXT: | nvsize=1028, nvalign=1024]
+// CHECK-NEXT: | [sizeof=1029, align=1
+// CHECK-NEXT: | nvsize=1029, nvalign=1]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct RB0
+// CHECK-X64-NEXT: 0 | int b
+// CHECK-X64-NEXT: | [sizeof=8, align=1024
+// CHECK-X64-NEXT: | nvsize=4, nvalign=1024]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct RB1
+// CHECK-X64-NEXT: 0 | (RB1 vftable pointer)
+// CHECK-X64-NEXT: 1024 | int b
+// CHECK-X64-NEXT: | [sizeof=1032, align=1024
+// CHECK-X64-NEXT: | nvsize=1028, nvalign=1024]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct RB2
+// CHECK-X64-NEXT: 0 | (RB2 vbtable pointer)
+// CHECK-X64-NEXT: 1024 | int b
+// CHECK-X64-NEXT: 1028 | struct RA (virtual base) (empty)
+// CHECK-X64-NEXT: | [sizeof=1032, align=1024
+// CHECK-X64-NEXT: | nvsize=1028, nvalign=1024]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct RB3
+// CHECK-X64-NEXT: 0 | (RB3 vftable pointer)
+// CHECK-X64-NEXT: 1024 | (RB3 vbtable pointer)
+// CHECK-X64-NEXT: 2048 | int b
+// CHECK-X64-NEXT: 2052 | struct RA (virtual base) (empty)
+// CHECK-X64-NEXT: | [sizeof=2056, align=1024
+// CHECK-X64-NEXT: | nvsize=2052, nvalign=1024]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct RC
+// CHECK-X64-NEXT: 0 | char _
+// CHECK-X64-NEXT: 1024 | int c
+// CHECK-X64-NEXT: | [sizeof=1028, align=1024
+// CHECK-X64-NEXT: | nvsize=1028, nvalign=1024]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct RE
+// CHECK-X64-NEXT: 0 | char _
+// CHECK-X64-NEXT: 1 | struct RC c
+// CHECK-X64-NEXT: 1 | char _
+// CHECK-X64-NEXT: 1025 | int c
+// CHECK-X64-NEXT: | [sizeof=1028, align=1024
+// CHECK-X64-NEXT: | nvsize=1028, nvalign=1024]
+// CHECK-X64-NEXT: | [sizeof=1029, align=1
+// CHECK-X64-NEXT: | nvsize=1029, nvalign=1]
+
int a[
sizeof(X)+
sizeof(Y)+
@@ -429,4 +562,10 @@ sizeof(JC)+
sizeof(KB)+
sizeof(L)+
sizeof(MB)+
+sizeof(RB0)+
+sizeof(RB1)+
+sizeof(RB2)+
+sizeof(RB3)+
+sizeof(RC)+
+sizeof(RE)+
0];
diff --git a/test/Layout/ms-x86-vtordisp.cpp b/test/Layout/ms-x86-vtordisp.cpp
index 1f03b4ad44..60779fb197 100644
--- a/test/Layout/ms-x86-vtordisp.cpp
+++ b/test/Layout/ms-x86-vtordisp.cpp
@@ -234,6 +234,9 @@ struct C : virtual B { int c; };
// CHECK-NEXT: 24 | int b
// CHECK-NEXT: | [sizeof=28, align=4
// CHECK-NEXT: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
}
namespace pragma_test2 {
@@ -260,6 +263,9 @@ struct C : virtual B { int c; };
// CHECK-NEXT: 32 | int b
// CHECK-NEXT: | [sizeof=36, align=4
// CHECK-NEXT: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
}
namespace pragma_test3 {
@@ -284,6 +290,9 @@ struct C : virtual B { int c; };
// CHECK-NEXT: 24 | int b
// CHECK-NEXT: | [sizeof=28, align=4
// CHECK-NEXT: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
}
namespace pragma_test4 {
@@ -324,8 +333,89 @@ struct C : virtual B<int> { int c; };
// CHECK-NEXT: 28 | int b
// CHECK-NEXT: | [sizeof=32, align=4
// CHECK-NEXT: | nvsize=8, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
}
+struct GA {
+ virtual void fun() {}
+};
+struct GB: public GA {};
+struct GC: public virtual GA {
+ virtual void fun() {}
+ GC() {}
+};
+struct GD: public virtual GC, public virtual GB {};
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct GD
+// CHECK-NEXT: 0 | (GD vbtable pointer)
+// CHECK-NEXT: 4 | (vtordisp for vbase GA)
+// CHECK-NEXT: 8 | struct GA (virtual base)
+// CHECK-NEXT: 8 | (GA vftable pointer)
+// CHECK-NEXT: 12 | struct GC (virtual base)
+// CHECK-NEXT: 12 | (GC vbtable pointer)
+// CHECK-NEXT: 16 | struct GB (virtual base)
+// CHECK-NEXT: 16 | struct GA (primary base)
+// CHECK-NEXT: 16 | (GA vftable pointer)
+// CHECK-NEXT: | [sizeof=20, align=4
+// CHECK-NEXT: | nvsize=4, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct GD
+// CHECK-X64-NEXT: 0 | (GD vbtable pointer)
+// CHECK-X64-NEXT: 12 | (vtordisp for vbase GA)
+// CHECK-X64-NEXT: 16 | struct GA (virtual base)
+// CHECK-X64-NEXT: 16 | (GA vftable pointer)
+// CHECK-X64-NEXT: 24 | struct GC (virtual base)
+// CHECK-X64-NEXT: 24 | (GC vbtable pointer)
+// CHECK-X64-NEXT: 32 | struct GB (virtual base)
+// CHECK-X64-NEXT: 32 | struct GA (primary base)
+// CHECK-X64-NEXT: 32 | (GA vftable pointer)
+// CHECK-X64-NEXT: | [sizeof=40, align=8
+// CHECK-X64-NEXT: | nvsize=8, nvalign=8]
+
+struct HA {
+ virtual void fun() {}
+};
+#pragma vtordisp(push, 2)
+struct HB : virtual HA {};
+#pragma vtordisp(pop)
+#pragma vtordisp(push, 0)
+struct HC : virtual HB {};
+#pragma vtordisp(pop)
+
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK: *** Dumping AST Record Layout
+// CHECK-NEXT: 0 | struct HC
+// CHECK-NEXT: 0 | (HC vbtable pointer)
+// CHECK-NEXT: 4 | (vtordisp for vbase HA)
+// CHECK-NEXT: 8 | struct HA (virtual base)
+// CHECK-NEXT: 8 | (HA vftable pointer)
+// CHECK-NEXT: 12 | struct HB (virtual base)
+// CHECK-NEXT: 12 | (HB vbtable pointer)
+// CHECK-NEXT: | [sizeof=16, align=4
+// CHECK-NEXT: | nvsize=4, nvalign=4]
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64: *** Dumping AST Record Layout
+// CHECK-X64-NEXT: 0 | struct HC
+// CHECK-X64-NEXT: 0 | (HC vbtable pointer)
+// CHECK-X64-NEXT: 12 | (vtordisp for vbase HA)
+// CHECK-X64-NEXT: 16 | struct HA (virtual base)
+// CHECK-X64-NEXT: 16 | (HA vftable pointer)
+// CHECK-X64-NEXT: 24 | struct HB (virtual base)
+// CHECK-X64-NEXT: 24 | (HB vbtable pointer)
+// CHECK-X64-NEXT: | [sizeof=32, align=8
+// CHECK-X64-NEXT: | nvsize=8, nvalign=8]
+
int a[
sizeof(A)+
sizeof(C)+
@@ -335,4 +425,7 @@ sizeof(XC)+
sizeof(pragma_test1::C)+
sizeof(pragma_test2::C)+
sizeof(pragma_test3::C)+
-sizeof(pragma_test4::C)];
+sizeof(pragma_test4::C)+
+sizeof(GD)+
+sizeof(HC)+
+0];
diff --git a/test/Lexer/cxx1y_digit_separators.cpp b/test/Lexer/cxx1y_digit_separators.cpp
index dcfb6d093f..c4c6aee963 100644
--- a/test/Lexer/cxx1y_digit_separators.cpp
+++ b/test/Lexer/cxx1y_digit_separators.cpp
@@ -34,6 +34,20 @@ namespace floating {
float d = 1.0'e1; // expected-error {{digit separator cannot appear at end of digit sequence}}
float e = 1e'1; // expected-error {{digit separator cannot appear at start of digit sequence}}
float f = 1e1'ms; // expected-error {{digit separator cannot appear at end of digit sequence}}
+ float g = 0.'0; // expected-error {{digit separator cannot appear at start of digit sequence}}
+ float h = .'0; // '; // expected-error {{expected expression}}, lexed as . followed by character literal
+ float i = 0x.'0p0; // expected-error {{digit separator cannot appear at start of digit sequence}}
+ float j = 0x'0.0p0; // expected-error {{invalid suffix 'x'0.0p0'}}
+ float k = 0x0'.0p0; // '; // expected-error {{expected ';'}}
+ float l = 0x0.'0p0; // expected-error {{digit separator cannot appear at start of digit sequence}}
+ float m = 0x0.0'p0; // expected-error {{digit separator cannot appear at end of digit sequence}}
+ float n = 0x0.0p'0; // expected-error {{digit separator cannot appear at start of digit sequence}}
+ float o = 0x0.0p0'ms; // expected-error {{digit separator cannot appear at end of digit sequence}}
+ float p = 0'e1; // expected-error {{digit separator cannot appear at end of digit sequence}}
+ float q = 0'0e1;
+ float r = 0.'0e1; // expected-error {{digit separator cannot appear at start of digit sequence}}
+ float s = 0.0'e1; // expected-error {{digit separator cannot appear at end of digit sequence}}
+ float t = 0.0e'1; // expected-error {{digit separator cannot appear at start of digit sequence}}
}
#line 123'456
diff --git a/test/Lexer/has_feature_exceptions.cpp b/test/Lexer/has_feature_exceptions.cpp
index bb5dc0c133..242a015264 100644
--- a/test/Lexer/has_feature_exceptions.cpp
+++ b/test/Lexer/has_feature_exceptions.cpp
@@ -1,4 +1,10 @@
-// RUN: %clang_cc1 -E -fexceptions %s -o - | FileCheck --check-prefix=CHECK-EXCEPTIONS %s
+// RUN: %clang -E -fexceptions %s -o - | FileCheck --check-prefix=CHECK-EXCEPTIONS %s
+// RUN: %clang -E -fexceptions -fno-cxx-exceptions %s -o - | FileCheck --check-prefix=CHECK-NO-EXCEPTIONS %s
+// RUN: %clang -E -fno-exceptions %s -o - | FileCheck --check-prefix=CHECK-NO-EXCEPTIONS %s
+
+// RUN: %clang_cc1 -E -fcxx-exceptions %s -o - | FileCheck --check-prefix=CHECK-EXCEPTIONS %s
+// RUN: %clang_cc1 -E -fobjc-exceptions %s -o - | FileCheck --check-prefix=CHECK-NO-EXCEPTIONS %s
+// RUN: %clang_cc1 -E -fexceptions %s -o - | FileCheck --check-prefix=CHECK-NO-EXCEPTIONS %s
// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-EXCEPTIONS %s
#if __has_feature(cxx_exceptions)
diff --git a/test/Lexer/keywords_test.c b/test/Lexer/keywords_test.c
new file mode 100644
index 0000000000..4eb1700e9b
--- /dev/null
+++ b/test/Lexer/keywords_test.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=c99 -E %s -o - | FileCheck --check-prefix=CHECK-NONE %s
+
+// RUN: %clang_cc1 -std=gnu89 -E %s -o - \
+// RUN: | FileCheck --check-prefix=CHECK-GNU-KEYWORDS %s
+// RUN: %clang_cc1 -std=c99 -fgnu-keywords -E %s -o - \
+// RUN: | FileCheck --check-prefix=CHECK-GNU-KEYWORDS %s
+// RUN: %clang_cc1 -std=gnu89 -fno-gnu-keywords -E %s -o - \
+// RUN: | FileCheck --check-prefix=CHECK-NONE %s
+
+// RUN: %clang_cc1 -std=c99 -fms-extensions -E %s -o - \
+// RUN: | FileCheck --check-prefix=CHECK-MS-KEYWORDS %s
+
+void f() {
+// CHECK-NONE: int asm
+// CHECK-GNU-KEYWORDS: asm ("ret" : :)
+#if __is_identifier(asm)
+ int asm;
+#else
+ asm ("ret" : :);
+#endif
+}
+
+// CHECK-NONE: no_ms_wchar
+// CHECK-MS-KEYWORDS: has_ms_wchar
+#if __is_identifier(__wchar_t)
+void no_ms_wchar();
+#else
+void has_ms_wchar();
+#endif
diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
index 07a7fa5035..415e1986fc 100644
--- a/test/Misc/warning-flags.c
+++ b/test/Misc/warning-flags.c
@@ -18,7 +18,7 @@ This test serves two purposes:
The list of warnings below should NEVER grow. It should gradually shrink to 0.
-CHECK: Warnings without flags (106):
+CHECK: Warnings without flags (105):
CHECK-NEXT: ext_delete_void_ptr_operand
CHECK-NEXT: ext_expected_semi_decl_list
CHECK-NEXT: ext_explicit_specialization_storage_class
@@ -28,7 +28,6 @@ CHECK-NEXT: ext_missing_declspec
CHECK-NEXT: ext_missing_whitespace_after_macro_name
CHECK-NEXT: ext_new_paren_array_nonconst
CHECK-NEXT: ext_plain_complex
-CHECK-NEXT: ext_pp_macro_redef
CHECK-NEXT: ext_template_arg_extra_parens
CHECK-NEXT: ext_typecheck_comparison_of_pointer_integer
CHECK-NEXT: ext_typecheck_cond_incompatible_operands
diff --git a/test/Modules/Inputs/cxx-decls-imported.h b/test/Modules/Inputs/cxx-decls-imported.h
index b94368614d..959d3feaaf 100644
--- a/test/Modules/Inputs/cxx-decls-imported.h
+++ b/test/Modules/Inputs/cxx-decls-imported.h
@@ -3,3 +3,18 @@ class HasFriends {
friend void friend_2(HasFriends);
void private_thing();
};
+
+struct HasNontrivialDefaultConstructor {
+ HasNontrivialDefaultConstructor() = default;
+ HasNontrivialDefaultConstructor(int n = 0);
+
+ // Ensure this class is not POD but is still trivially-copyable.
+ // This is necessary to exercise the second static_assert below,
+ // because GCC's spec for __has_trivial_constructor is absurd.
+ int m;
+private:
+ int n;
+};
+
+static_assert(!__is_trivial(HasNontrivialDefaultConstructor), "");
+static_assert(!__has_trivial_constructor(HasNontrivialDefaultConstructor), "");
diff --git a/test/Modules/Inputs/cxx-irgen-left.h b/test/Modules/Inputs/cxx-irgen-left.h
index 970ac764fc..ceb50846bb 100644
--- a/test/Modules/Inputs/cxx-irgen-left.h
+++ b/test/Modules/Inputs/cxx-irgen-left.h
@@ -5,3 +5,7 @@ S<int> s;
inline int instantiate_min() {
return min(1, 2);
}
+
+inline int instantiate_CtorInit(CtorInit<int> i = CtorInit<int>()) {
+ return i.a;
+}
diff --git a/test/Modules/Inputs/cxx-irgen-top.h b/test/Modules/Inputs/cxx-irgen-top.h
index 8113e94def..8753d8daa3 100644
--- a/test/Modules/Inputs/cxx-irgen-top.h
+++ b/test/Modules/Inputs/cxx-irgen-top.h
@@ -8,3 +8,9 @@ extern template struct S<int>;
template<typename T> T min(T a, T b) { return a < b ? a : b; }
extern decltype(min(1, 2)) instantiate_min_decl;
+
+template<typename T> struct CtorInit {
+ static int f() { return 0; }
+ int a;
+ CtorInit() : a(f()) {}
+};
diff --git a/test/Modules/Inputs/exclude-header/module.map b/test/Modules/Inputs/exclude-header/module.map
new file mode 100644
index 0000000000..2563ef9dc9
--- /dev/null
+++ b/test/Modules/Inputs/exclude-header/module.map
@@ -0,0 +1,3 @@
+module x { umbrella "x" exclude header "x/bad.h" module * {} }
+module y { umbrella "y" module * {} }
+module bad { header "x/bad.h" }
diff --git a/test/Modules/Inputs/exclude-header/x/a.h b/test/Modules/Inputs/exclude-header/x/a.h
new file mode 100644
index 0000000000..389d285a45
--- /dev/null
+++ b/test/Modules/Inputs/exclude-header/x/a.h
@@ -0,0 +1 @@
+typedef int a;
diff --git a/test/Modules/Inputs/exclude-header/x/bad.h b/test/Modules/Inputs/exclude-header/x/bad.h
new file mode 100644
index 0000000000..179ef267be
--- /dev/null
+++ b/test/Modules/Inputs/exclude-header/x/bad.h
@@ -0,0 +1 @@
+#error bad
diff --git a/test/Modules/Inputs/exclude-header/y/b.h b/test/Modules/Inputs/exclude-header/y/b.h
new file mode 100644
index 0000000000..a16836aac7
--- /dev/null
+++ b/test/Modules/Inputs/exclude-header/y/b.h
@@ -0,0 +1 @@
+typedef int b;
diff --git a/test/Modules/Inputs/modules-with-same-name/DependsOnA/DependsOnA.h b/test/Modules/Inputs/modules-with-same-name/DependsOnA/DependsOnA.h
new file mode 100644
index 0000000000..9d0256bdff
--- /dev/null
+++ b/test/Modules/Inputs/modules-with-same-name/DependsOnA/DependsOnA.h
@@ -0,0 +1 @@
+@import A;
diff --git a/test/Modules/Inputs/modules-with-same-name/DependsOnA/module.modulemap b/test/Modules/Inputs/modules-with-same-name/DependsOnA/module.modulemap
new file mode 100644
index 0000000000..b2a027b55d
--- /dev/null
+++ b/test/Modules/Inputs/modules-with-same-name/DependsOnA/module.modulemap
@@ -0,0 +1,4 @@
+module DependsOnA {
+ header "DependsOnA.h"
+ export *
+}
diff --git a/test/Modules/Inputs/modules-with-same-name/path1/A/a.h b/test/Modules/Inputs/modules-with-same-name/path1/A/a.h
new file mode 100644
index 0000000000..0086e2a250
--- /dev/null
+++ b/test/Modules/Inputs/modules-with-same-name/path1/A/a.h
@@ -0,0 +1 @@
+#define FROM_PATH 1
diff --git a/test/Modules/Inputs/modules-with-same-name/path1/A/module.modulemap b/test/Modules/Inputs/modules-with-same-name/path1/A/module.modulemap
new file mode 100644
index 0000000000..76c3358335
--- /dev/null
+++ b/test/Modules/Inputs/modules-with-same-name/path1/A/module.modulemap
@@ -0,0 +1,5 @@
+// path1. This comment keeps this file from being identical to
+// path2/A/module.modulemap.
+module A {
+ header "a.h"
+}
diff --git a/test/Modules/Inputs/modules-with-same-name/path2/A/a.h b/test/Modules/Inputs/modules-with-same-name/path2/A/a.h
new file mode 100644
index 0000000000..184c190bcb
--- /dev/null
+++ b/test/Modules/Inputs/modules-with-same-name/path2/A/a.h
@@ -0,0 +1 @@
+#define FROM_PATH 2
diff --git a/test/Modules/Inputs/modules-with-same-name/path2/A/module.modulemap b/test/Modules/Inputs/modules-with-same-name/path2/A/module.modulemap
new file mode 100644
index 0000000000..2ff394378e
--- /dev/null
+++ b/test/Modules/Inputs/modules-with-same-name/path2/A/module.modulemap
@@ -0,0 +1,5 @@
+// path2. This comment keeps this file from being identical to
+// path1/A/module.modulemap.
+module A {
+ header "a.h"
+}
diff --git a/test/Modules/Inputs/submodules/module.map b/test/Modules/Inputs/submodules/module.map
index 15931031ab..1c1b76a089 100644
--- a/test/Modules/Inputs/submodules/module.map
+++ b/test/Modules/Inputs/submodules/module.map
@@ -15,3 +15,18 @@ module missing_headers {
module missing { header "missing.h" }
module not_missing { header "not_missing.h" }
}
+
+module missing_unavailable_headers {
+ module missing {
+ requires !objc
+ header "missing.h"
+ module also_missing { header "also_missing.h" }
+ }
+ module not_missing { }
+}
+
+module missing_umbrella_with_inferred_submodules {
+ umbrella header "missing_umbrella.h"
+ module * { export * }
+ export *
+}
diff --git a/test/Modules/Inputs/templates-left.h b/test/Modules/Inputs/templates-left.h
index e76598d6bd..076a1f43c2 100644
--- a/test/Modules/Inputs/templates-left.h
+++ b/test/Modules/Inputs/templates-left.h
@@ -33,3 +33,21 @@ void triggerPendingInstantiation() {
void redeclDefinitionEmit(){}
typedef Outer<int>::Inner OuterIntInner_left;
+
+int defineListDoubleLeft() {
+ List<double> ld;
+ ld.push_back(0.0);
+ return ld.size;
+}
+
+template<typename T> struct MergePatternDecl;
+
+extern template struct ExplicitInstantiation<false, false>;
+extern template struct ExplicitInstantiation<false, true>;
+extern template struct ExplicitInstantiation<true, false>;
+extern template struct ExplicitInstantiation<true, true>;
+
+void useExplicitInstantiation() {
+ ExplicitInstantiation<true, false>().f();
+ ExplicitInstantiation<true, true>().f();
+}
diff --git a/test/Modules/Inputs/templates-right.h b/test/Modules/Inputs/templates-right.h
index 16d0a714d9..c8056d6539 100644
--- a/test/Modules/Inputs/templates-right.h
+++ b/test/Modules/Inputs/templates-right.h
@@ -31,3 +31,11 @@ void triggerPendingInstantiationToo() {
void redeclDefinitionEmit(){}
typedef Outer<int>::Inner OuterIntInner_right;
+
+int defineListDoubleRight() {
+ List<double> ld;
+ ld.push_back(0.0);
+ return ld.size;
+}
+
+template<typename T> struct MergePatternDecl;
diff --git a/test/Modules/Inputs/templates-top.h b/test/Modules/Inputs/templates-top.h
index 87dcd8b7f4..144bfcd0ef 100644
--- a/test/Modules/Inputs/templates-top.h
+++ b/test/Modules/Inputs/templates-top.h
@@ -9,6 +9,8 @@ public:
unsigned size;
};
+extern List<double> *instantiateListDoubleDeclaration;
+
namespace A {
class Y {
template <typename T> friend class WhereAmI;
@@ -23,3 +25,7 @@ public:
template<typename T> struct Outer {
struct Inner {};
};
+
+template<bool, bool> struct ExplicitInstantiation {
+ void f() {}
+};
diff --git a/test/Modules/Inputs/undefined-type-fixit/module.map b/test/Modules/Inputs/undefined-type-fixit/module.map
new file mode 100644
index 0000000000..f5ce34b8fc
--- /dev/null
+++ b/test/Modules/Inputs/undefined-type-fixit/module.map
@@ -0,0 +1,9 @@
+module public1 {
+ header "public1.h"
+}
+module public2 {
+ header "public2.h"
+ module public2sub {
+ header "public2sub.h"
+ }
+}
diff --git a/test/Modules/Inputs/undefined-type-fixit/public1.h b/test/Modules/Inputs/undefined-type-fixit/public1.h
new file mode 100644
index 0000000000..bc98ca9e0e
--- /dev/null
+++ b/test/Modules/Inputs/undefined-type-fixit/public1.h
@@ -0,0 +1,6 @@
+#ifndef PUBLIC1_H
+#define PUBLIC1_H
+
+struct use_this1 { int field; };
+
+#endif
diff --git a/test/Modules/Inputs/undefined-type-fixit/public2.h b/test/Modules/Inputs/undefined-type-fixit/public2.h
new file mode 100644
index 0000000000..2aa3e9614c
--- /dev/null
+++ b/test/Modules/Inputs/undefined-type-fixit/public2.h
@@ -0,0 +1,6 @@
+#ifndef PUBLIC2_H
+#define PUBLIC2_H
+
+struct use_this2 { int field; };
+
+#endif
diff --git a/test/Modules/Inputs/undefined-type-fixit/public2sub.h b/test/Modules/Inputs/undefined-type-fixit/public2sub.h
new file mode 100644
index 0000000000..4c8c3cce03
--- /dev/null
+++ b/test/Modules/Inputs/undefined-type-fixit/public2sub.h
@@ -0,0 +1,6 @@
+#ifndef PUBLIC2SUB_H
+#define PUBLIC2SUB_H
+
+struct use_this2sub { int field; };
+
+#endif
diff --git a/test/Modules/cxx-decls.cpp b/test/Modules/cxx-decls.cpp
index ba3281aaec..d37594afb5 100644
--- a/test/Modules/cxx-decls.cpp
+++ b/test/Modules/cxx-decls.cpp
@@ -19,3 +19,6 @@ void test_friends(HasFriends s) {
friend_1(s);
friend_2(s);
}
+
+static_assert(!__is_trivial(HasNontrivialDefaultConstructor), "");
+static_assert(!__has_trivial_constructor(HasNontrivialDefaultConstructor), "");
diff --git a/test/Modules/cxx-irgen.cpp b/test/Modules/cxx-irgen.cpp
index 7a42cb6b8c..7c680f8211 100644
--- a/test/Modules/cxx-irgen.cpp
+++ b/test/Modules/cxx-irgen.cpp
@@ -3,16 +3,20 @@
// FIXME: When we have a syntax for modules in C++, use that.
@import cxx_irgen_top;
+
+// CHECK-DAG: call i32 @_ZN8CtorInitIiE1fEv(
+CtorInit<int> x;
+
@import cxx_irgen_left;
@import cxx_irgen_right;
-// CHECK-DAG: define available_externally hidden i32 @_ZN1SIiE1gEv({{.*}} #[[ALWAYS_INLINE:.*]] align
+// CHECK-DAG: define available_externally hidden {{signext i32|i32}} @_ZN1SIiE1gEv({{.*}} #[[ALWAYS_INLINE:.*]] align
int a = S<int>::g();
-// CHECK-DAG: define available_externally i32 @_ZN1SIiE1fEv({{.*}} #[[ALWAYS_INLINE]] align
+// CHECK-DAG: define available_externally {{signext i32|i32}} @_ZN1SIiE1fEv({{.*}} #[[ALWAYS_INLINE]] align
int b = h();
-// CHECK-DAG: define linkonce_odr i32 @_Z3minIiET_S0_S0_(i32
+// CHECK-DAG: define linkonce_odr {{signext i32|i32}} @_Z3minIiET_S0_S0_(i32
int c = min(1, 2);
// CHECK: attributes #[[ALWAYS_INLINE]] = {{.*}} alwaysinline
diff --git a/test/Modules/cxx-templates.cpp b/test/Modules/cxx-templates.cpp
index 291fabf0be..82ecca31b5 100644
--- a/test/Modules/cxx-templates.cpp
+++ b/test/Modules/cxx-templates.cpp
@@ -29,8 +29,8 @@ void g() {
N::f<double>(1.0);
N::f<int>();
N::f(); // expected-error {{no matching function}}
- // expected-note@Inputs/cxx-templates-b.h:6 {{couldn't infer template argument}}
- // expected-note@Inputs/cxx-templates-b.h:7 {{requires single argument 't'}}
+ // expected-note@Inputs/cxx-templates-a.h:6 {{couldn't infer template argument}}
+ // expected-note@Inputs/cxx-templates-a.h:7 {{requires 1 argument}}
template_param_kinds_1<0>(); // ok, from cxx-templates-a.h
template_param_kinds_1<int>(); // ok, from cxx-templates-b.h
@@ -126,20 +126,12 @@ namespace Std {
// expected-note@cxx-templates-common.h:21 {{previous}}
}
-// FIXME: We should only have two entries for each of these names (one for each
-// function template), but we don't attempt to deduplicate lookup results from
-// sibling modules yet.
-
// CHECK-GLOBAL: DeclarationName 'f'
// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
-// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
-// CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'
// CHECK-GLOBAL-NEXT: `-FunctionTemplate {{.*}} 'f'
// CHECK-NAMESPACE-N: DeclarationName 'f'
// CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f'
-// CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f'
-// CHECK-NAMESPACE-N-NEXT: |-FunctionTemplate {{.*}} 'f'
// CHECK-NAMESPACE-N-NEXT: `-FunctionTemplate {{.*}} 'f'
// CHECK-DUMP: ClassTemplateDecl {{.*}} <{{.*[/\\]}}cxx-templates-common.h:1:1, {{.*}}> col:{{.*}} in cxx_templates_common SomeTemplate
diff --git a/test/Modules/dependency-gen-pch.m b/test/Modules/dependency-gen-pch.m
index b0c75513d9..65e22d485d 100644
--- a/test/Modules/dependency-gen-pch.m
+++ b/test/Modules/dependency-gen-pch.m
@@ -1,7 +1,7 @@
// RUN: rm -rf %t-mcp
// RUN: mkdir -p %t-mcp
-// RUN: %clang_cc1 -isysroot %S/Inputs/System -triple x86_64-apple-darwin10 -module-file-deps -dependency-file %t.d -MT %s.o -I %S/Inputs -fmodules -fmodules-cache-path=%t-mcp -emit-pch -o %t.pch %s
+// RUN: %clang_cc1 -isysroot %S/Inputs/System -triple x86_64-apple-darwin10 -module-file-deps -dependency-file %t.d -MT %s.o -I %S/Inputs -fmodules -fdisable-module-hash -fmodules-cache-path=%t-mcp -emit-pch -o %t.pch %s
// RUN: FileCheck %s < %t.d
// CHECK: dependency-gen-pch.m.o
// CHECK-NEXT: dependency-gen-pch.m
diff --git a/test/Modules/diamond-pch.c b/test/Modules/diamond-pch.c
index 37a8cbe25d..f66ad877de 100644
--- a/test/Modules/diamond-pch.c
+++ b/test/Modules/diamond-pch.c
@@ -4,7 +4,7 @@
// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=diamond_right %S/Inputs/module.map
// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=diamond_bottom %S/Inputs/module.map
// RUN: %clang_cc1 -fmodules -x objective-c -emit-pch -fmodules-cache-path=%t -I %S/Inputs -o %t.pch %S/Inputs/diamond.h
-// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -include-pch %t.pch %s -verify
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -include-pch %t.pch %s -I %S/Inputs -verify
// FIXME: When we have a syntax for modules in C, use that.
void test_diamond(int i, float f, double d, char c) {
diff --git a/test/Modules/exclude-header.c b/test/Modules/exclude-header.c
new file mode 100644
index 0000000000..4134c82483
--- /dev/null
+++ b/test/Modules/exclude-header.c
@@ -0,0 +1,11 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c -fmodules -fmodules-cache-path=%t -I %S/Inputs/exclude-header %s -verify
+
+@import x;
+
+a var_a;
+b var_b1; // expected-error {{unknown type name 'b'}}
+
+@import y;
+
+b var_b2;
diff --git a/test/Modules/macro-undef-through-pch.m b/test/Modules/macro-undef-through-pch.m
index ff0736ca99..0e5e99fb8b 100644
--- a/test/Modules/macro-undef-through-pch.m
+++ b/test/Modules/macro-undef-through-pch.m
@@ -2,7 +2,9 @@
// RUN: %clang_cc1 -x objective-c-header -fmodules -fmodules-cache-path=%t \
// RUN: -I%S/Inputs/macro-undef-through-pch -emit-pch \
// RUN: %S/Inputs/macro-undef-through-pch/foo.h -o %t.pch
-// RUN: %clang_cc1 -x objective-c -fmodules -fmodules-cache-path=%t -include-pch %t.pch %s
+// RUN: %clang_cc1 -x objective-c -fmodules -fmodules-cache-path=%t \
+// RUN: -I%S/Inputs/macro-undef-through-pch -emit-pch \
+// RUN: -include-pch %t.pch %s
// PR19215
#undef AB
diff --git a/test/Modules/missing-header.m b/test/Modules/missing-header.m
new file mode 100644
index 0000000000..c2c1673ac5
--- /dev/null
+++ b/test/Modules/missing-header.m
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t
+// RUN: not %clang_cc1 -x objective-c -fmodules-cache-path=%t -fmodules -I %S/Inputs/submodules %s 2>&1 | FileCheck %s
+
+// FIXME: cannot use -verify, because the error from inside the module build has
+// a different source manager than the verifier.
+
+@import missing_unavailable_headers; // OK
+@import missing_unavailable_headers.not_missing; // OK
+// CHECK-NOT: missing_unavailable_headers
+
+@import missing_headers;
+// CHECK: module.map:15:27: error: header 'missing.h' not found
+// CHECK: could not build module 'missing_headers'
diff --git a/test/Modules/missing-submodule.m b/test/Modules/missing-submodule.m
new file mode 100644
index 0000000000..4f3553ce6c
--- /dev/null
+++ b/test/Modules/missing-submodule.m
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -F %S/Inputs %s -verify
+#include <Module/NotInModule.h> // expected-warning{{missing submodule 'Module.NotInModule'}}
+
+int getNotInModule() {
+ return not_in_module;
+}
diff --git a/test/Modules/module_file_info.m b/test/Modules/module_file_info.m
index f9a35babd0..9f1ff2221b 100644
--- a/test/Modules/module_file_info.m
+++ b/test/Modules/module_file_info.m
@@ -7,6 +7,9 @@
// CHECK: Generated by this Clang:
+// CHECK: Module name: DependsOnModule
+// CHECK: Module map file: {{.*}}DependsOnModule.framework{{[/\\]}}module.map
+
// CHECK: Language options:
// CHECK: C99: Yes
// CHECK: Objective-C 1: Yes
diff --git a/test/Modules/modules-with-same-name.m b/test/Modules/modules-with-same-name.m
new file mode 100644
index 0000000000..c90aa5d7d8
--- /dev/null
+++ b/test/Modules/modules-with-same-name.m
@@ -0,0 +1,35 @@
+// REQUIRES: shell
+// RUN: rm -rf %t
+
+// A from path 1
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodules-ignore-macro=EXPECTED_PATH -fmodules-ignore-macro=DIRECT -fsyntax-only %s -verify -I %S/Inputs/modules-with-same-name/path1/A -DDIRECT -DEXPECTED_PATH=1
+
+// A from path 2
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodules-ignore-macro=EXPECTED_PATH -fmodules-ignore-macro=DIRECT -fsyntax-only %s -verify -I %S/Inputs/modules-with-same-name/path2/A -DDIRECT -DEXPECTED_PATH=2
+
+// Confirm that we have two pcm files (one for each 'A').
+// RUN: find %t -name "A-*.pcm" | count 2
+
+// DependsOnA, using A from path 1
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodules-ignore-macro=EXPECTED_PATH -fmodules-ignore-macro=DIRECT -fsyntax-only %s -verify -I %S/Inputs/modules-with-same-name/DependsOnA -I %S/Inputs/modules-with-same-name/path1/A -DEXPECTED_PATH=1
+
+// Confirm that we have three pcm files (one for each 'A', and one for 'DependsOnA')
+// RUN: find %t -name "*.pcm" | count 3
+
+// DependsOnA, using A from path 2
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodules-ignore-macro=EXPECTED_PATH -fmodules-ignore-macro=DIRECT -fsyntax-only %s -verify -I %S/Inputs/modules-with-same-name/DependsOnA -I %S/Inputs/modules-with-same-name/path2/A -DEXPECTED_PATH=2
+
+// Confirm that we still have three pcm files, since DependsOnA will be rebuilt
+// RUN: find %t -name "*.pcm" | count 3
+
+#ifdef DIRECT
+@import A;
+#else
+@import DependsOnA;
+#endif
+
+#if FROM_PATH != EXPECTED_PATH
+#error "Got the wrong module!"
+#endif
+
+// expected-no-diagnostics
diff --git a/test/Modules/prune.m b/test/Modules/prune.m
index 8af7e6c395..7bc771f784 100644
--- a/test/Modules/prune.m
+++ b/test/Modules/prune.m
@@ -14,33 +14,33 @@
// RUN: %clang_cc1 -DIMPORT_DEPENDS_ON_MODULE -fmodules-ignore-macro=DIMPORT_DEPENDS_ON_MODULE -fmodules -F %S/Inputs -fmodules-cache-path=%t %s -verify
// RUN: %clang_cc1 -DIMPORT_DEPENDS_ON_MODULE -fmodules-ignore-macro=DIMPORT_DEPENDS_ON_MODULE -fmodules -F %S/Inputs -fmodules-cache-path=%t %s -verify
// RUN: ls %t | grep modules.timestamp
-// RUN: ls -R %t | grep ^Module.pcm
-// RUN: ls -R %t | grep DependsOnModule.pcm
+// RUN: ls -R %t | grep ^Module.*pcm
+// RUN: ls -R %t | grep DependsOnModule.*pcm
// Set the timestamp back more than two days. We should try to prune,
// but nothing gets pruned because the module files are new enough.
// RUN: touch -m -a -t 201101010000 %t/modules.timestamp
// RUN: %clang_cc1 -fmodules -F %S/Inputs -fmodules-cache-path=%t -fmodules -fmodules-prune-interval=172800 -fmodules-prune-after=345600 %s -verify
// RUN: ls %t | grep modules.timestamp
-// RUN: ls -R %t | grep ^Module.pcm
-// RUN: ls -R %t | grep DependsOnModule.pcm
+// RUN: ls -R %t | grep ^Module.*pcm
+// RUN: ls -R %t | grep DependsOnModule.*pcm
// Set the DependsOnModule access time back more than four days.
// This shouldn't prune anything, because the timestamp has been updated, so
// the pruning mechanism won't fire.
-// RUN: find %t -name DependsOnModule.pcm | xargs touch -a -t 201101010000
+// RUN: find %t -name DependsOnModule*.pcm | xargs touch -a -t 201101010000
// RUN: %clang_cc1 -fmodules -F %S/Inputs -fmodules-cache-path=%t -fmodules -fmodules-prune-interval=172800 -fmodules-prune-after=345600 %s -verify
// RUN: ls %t | grep modules.timestamp
-// RUN: ls -R %t | grep ^Module.pcm
-// RUN: ls -R %t | grep DependsOnModule.pcm
+// RUN: ls -R %t | grep ^Module.*pcm
+// RUN: ls -R %t | grep DependsOnModule.*pcm
// Set both timestamp and DependsOnModule.pcm back beyond the cutoff.
// This should trigger pruning, which will remove DependsOnModule but not Module.
// RUN: touch -m -a -t 201101010000 %t/modules.timestamp
-// RUN: find %t -name DependsOnModule.pcm | xargs touch -a -t 201101010000
+// RUN: find %t -name DependsOnModule*.pcm | xargs touch -a -t 201101010000
// RUN: %clang_cc1 -fmodules -F %S/Inputs -fmodules-cache-path=%t -fmodules -fmodules-prune-interval=172800 -fmodules-prune-after=345600 %s -verify
// RUN: ls %t | grep modules.timestamp
-// RUN: ls -R %t | grep ^Module.pcm
-// RUN: ls -R %t | not grep DependsOnModule.pcm
+// RUN: ls -R %t | grep ^Module.*pcm
+// RUN: ls -R %t | not grep DependsOnModule.*pcm
// expected-no-diagnostics
diff --git a/test/Modules/redecls/main.m b/test/Modules/redecls/main.m
index 8236092956..bf3788a96d 100644
--- a/test/Modules/redecls/main.m
+++ b/test/Modules/redecls/main.m
@@ -3,7 +3,7 @@
// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-name=b %S/module.map -fmodules-cache-path=%t.mcp
// RUN: %clang_cc1 -fmodules %s -emit-pch -o %t1.pch -fmodules-cache-path=%t.mcp -I %S
// RUN: %clang_cc1 -fmodules %s -emit-pch -o %t2.pch -include-pch %t1.pch -fmodules-cache-path=%t.mcp -I %S
-// RUN: %clang_cc1 -fmodules %s -fsyntax-only -include-pch %t2.pch -fmodules-cache-path=%t.mcp -verify
+// RUN: %clang_cc1 -fmodules %s -fsyntax-only -include-pch %t2.pch -I %S -fmodules-cache-path=%t.mcp -verify
#ifndef HEADER1
#define HEADER1
diff --git a/test/Modules/resolution-change.m b/test/Modules/resolution-change.m
new file mode 100644
index 0000000000..a69014c6ae
--- /dev/null
+++ b/test/Modules/resolution-change.m
@@ -0,0 +1,24 @@
+// RUN: rm -rf %t
+
+// Build PCH using A from path 1
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/modules-with-same-name/DependsOnA -I %S/Inputs/modules-with-same-name/path1/A -emit-pch -o %t-A.pch %s
+
+// Use the PCH with the same header search options; should be fine
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/modules-with-same-name/DependsOnA -I %S/Inputs/modules-with-same-name/path1/A -include-pch %t-A.pch %s -fsyntax-only -Werror
+
+// Use the PCH with no way to resolve DependsOnA
+// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -include-pch %t-A.pch %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CHECK-NODOA %s
+// CHECK-NODOA: module 'DependsOnA' imported by AST file '{{.*A.pch}}' not found
+
+// Use the PCH with no way to resolve A
+// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/modules-with-same-name/DependsOnA -include-pch %t-A.pch %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CHECK-NOA %s
+// CHECK-NOA: module 'A' imported by AST file '{{.*DependsOnA.*pcm}}' not found
+
+// Use the PCH and have it resolve the the other A
+// RUN: not %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/modules-with-same-name/DependsOnA -I %S/Inputs/modules-with-same-name/path2/A -include-pch %t-A.pch %s -fsyntax-only 2>&1 | FileCheck -check-prefix=CHECK-WRONGA %s
+// CHECK-WRONGA: module 'A' imported by AST file '{{.*DependsOnA.*pcm}}' found in a different module map file ({{.*path2.*}}) than when the importing AST file was built ({{.*path1.*}})
+
+#ifndef HEADER
+#define HEADER
+@import DependsOnA;
+#endif
diff --git a/test/Modules/strict-decluse.cpp b/test/Modules/strict-decluse.cpp
new file mode 100644
index 0000000000..fa6955aef0
--- /dev/null
+++ b/test/Modules/strict-decluse.cpp
@@ -0,0 +1,9 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodule-maps -fmodules-cache-path=%t -fmodules-strict-decluse -fmodule-name=XG -I %S/Inputs/declare-use %s -verify
+
+#include "g.h"
+#include "e.h"
+#include "f.h" // expected-error {{module XG does not depend on a module exporting 'f.h'}}
+#include "i.h" // expected-error {{module XG does not depend on a module exporting 'i.h'}}
+
+const int g2 = g1 + e + f + aux_i;
diff --git a/test/Modules/submodules.cpp b/test/Modules/submodules.cpp
index a18138c709..7ef785c936 100644
--- a/test/Modules/submodules.cpp
+++ b/test/Modules/submodules.cpp
@@ -32,8 +32,3 @@ extern MyTypeA import_self_test_a; // expected-error {{must be imported from mod
// expected-note@import-self-a.h:1 {{here}}
extern MyTypeC import_self_test_c;
extern MyTypeD import_self_test_d;
-
-// expected-error@Inputs/submodules/module.map:15{{header 'missing.h' not found}}
-@import missing_headers.missing;
-@import missing_headers.not_missing;
-void f() { NotMissingFunction(); };
diff --git a/test/Modules/system_version.m b/test/Modules/system_version.m
index 85b3263f72..bc82bf8bc1 100644
--- a/test/Modules/system_version.m
+++ b/test/Modules/system_version.m
@@ -11,21 +11,21 @@
// Run once with no system version file. We should end up with one module.
// RUN: %clang_cc1 -fmodules-cache-path=%t/cache -fmodules -isysroot %t -I %t/usr/include %s -verify
-// RUN: ls -R %t | grep -c ModA.pcm| grep 1
+// RUN: ls -R %t | grep -c "ModA.*pcm" | grep 1
// Add a system version file and run again. We should now have two
// module variants.
// RUN: mkdir -p %t/System/Library/CoreServices
// RUN: echo "hello" > %t/System/Library/CoreServices/SystemVersion.plist
// RUN: %clang_cc1 -fmodules-cache-path=%t/cache -fmodules -isysroot %t -I %t/usr/include %s -verify
-// RUN: ls -R %t | grep -c ModA.pcm| grep 2
+// RUN: ls -R %t | grep -c "ModA.*pcm" | grep 2
// Change the system version file and run again. We should now have three
// module variants.
// RUN: mkdir -p %t/System/Library/CoreServices
// RUN: echo "modules" > %t/System/Library/CoreServices/SystemVersion.plist
// RUN: %clang_cc1 -fmodules-cache-path=%t/cache -fmodules -isysroot %t -I %t/usr/include %s -verify
-// RUN: ls -R %t | grep -c ModA.pcm| grep 3
+// RUN: ls -R %t | grep -c "ModA.*pcm" | grep 3
// expected-no-diagnostics
@import ModA;
diff --git a/test/Modules/templates.mm b/test/Modules/templates.mm
index 080f9e7c66..feeae85cc1 100644
--- a/test/Modules/templates.mm
+++ b/test/Modules/templates.mm
@@ -20,6 +20,9 @@ void testTemplateClasses() {
N::Set<char> set_char;
set_char.insert('A');
+
+ List<double> list_double;
+ list_double.push_back(0.0);
}
void testPendingInstantiations() {
@@ -36,6 +39,11 @@ void testRedeclDefinition() {
redeclDefinitionEmit();
}
+// CHECK-NOT: @_ZN21ExplicitInstantiationILb0ELb0EE1fEv(
+// CHECK: declare {{.*}}@_ZN21ExplicitInstantiationILb1ELb0EE1fEv(
+// CHECK: define {{.*}}@_ZN21ExplicitInstantiationILb1ELb1EE1fEv(
+// CHECK-NOT: @_ZN21ExplicitInstantiationILb0ELb0EE1fEv(
+
// These three are all the same type.
typedef OuterIntInner_left OuterIntInner;
typedef OuterIntInner_right OuterIntInner;
@@ -67,3 +75,12 @@ unsigned testMixedStruct() {
// CHECK: load i32* bitcast (i8* getelementptr inbounds (i8* bitcast ({{.*}}* @list_right to i8*), i64 8) to i32*)
return list_left.*size_right + list_right.*size_left;
}
+
+template<typename T> struct MergePatternDecl {
+ typedef int Type;
+ void f(Type);
+};
+template<typename T> void MergePatternDecl<T>::f(Type type) {}
+// CHECK: define {{.*}}@_ZN21ExplicitInstantiationILb0ELb1EE1fEv(
+template struct ExplicitInstantiation<false, true>;
+template struct ExplicitInstantiation<true, true>;
diff --git a/test/Modules/undefined-type-fixit1.cpp b/test/Modules/undefined-type-fixit1.cpp
new file mode 100644
index 0000000000..78ce174f54
--- /dev/null
+++ b/test/Modules/undefined-type-fixit1.cpp
@@ -0,0 +1,12 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fmodules-search-all -I %S/Inputs/undefined-type-fixit %s -verify
+
+//#include "public1.h"
+#include "public2.h"
+#include "public2sub.h"
+
+use_this1 client_variable1; // expected-error{{declaration of 'use_this1' must be imported from module 'public1' before it is required}}
+use_this2 client_variable2;
+use_this2sub client_variable2sub;
+
+// expected-note@Inputs/undefined-type-fixit/public1.h:4 {{previous declaration is here}}
diff --git a/test/Modules/validate-system-headers.m b/test/Modules/validate-system-headers.m
index 9fb2bd2a63..48ea64c5a9 100644
--- a/test/Modules/validate-system-headers.m
+++ b/test/Modules/validate-system-headers.m
@@ -20,6 +20,24 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t/Inputs -fmodules -fmodules-validate-system-headers -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s
// RUN: not diff %t/ModuleCache/Foo.pcm %t/Foo.pcm.saved
+
+////
+// This should override -fmodules-validate-once-per-build-session
+// RUN: cp %t/ModuleCache/Foo.pcm %t/Foo.pcm.saved
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t/Inputs -fmodules -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session
+// RUN: diff %t/ModuleCache/Foo.pcm %t/Foo.pcm.saved
+
+// Modify the system header...
+// RUN: echo ' ' >> %t/Inputs/usr/include/foo.h
+
+// Don't recompile due to -fmodules-validate-once-per-build-session
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t/Inputs -fmodules -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session
+// RUN: diff %t/ModuleCache/Foo.pcm %t/Foo.pcm.saved
+
+// Now add -fmodules-validate-system-headers and rebuild
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -isysroot %t/Inputs -fmodules -fmodules-validate-system-headers -fmodules-cache-path=%t/ModuleCache -fdisable-module-hash -x objective-c-header -fsyntax-only %s -fbuild-session-timestamp=1390000000 -fmodules-validate-once-per-build-session
+// RUN: not diff %t/ModuleCache/Foo.pcm %t/Foo.pcm.saved
+
// REQUIRES: shell
@import Foo;
diff --git a/test/OpenMP/simd_ast_print.cpp b/test/OpenMP/simd_ast_print.cpp
index 4b1fccb92f..5e8cbecfbc 100644
--- a/test/OpenMP/simd_ast_print.cpp
+++ b/test/OpenMP/simd_ast_print.cpp
@@ -14,8 +14,8 @@ template<class T, class N> T reduct(T* arr, N num) {
N myind;
T sum = (T)0;
// CHECK: T sum = (T)0;
-#pragma omp simd private(myind, g_ind)
-// CHECK-NEXT: #pragma omp simd private(myind,g_ind)
+#pragma omp simd private(myind, g_ind), linear(ind)
+// CHECK-NEXT: #pragma omp simd private(myind,g_ind) linear(ind)
for (i = 0; i < num; ++i) {
myind = ind;
T cur = arr[myind];
@@ -31,13 +31,16 @@ template<class T> struct S {
T result(T *v) const {
T res;
T val;
+ T lin = 0;
// CHECK: T res;
// CHECK: T val;
- #pragma omp simd private(val) safelen(7)
-// CHECK-NEXT: #pragma omp simd private(val) safelen(7)
+// CHECK: T lin = 0;
+ #pragma omp simd private(val) safelen(7) linear(lin : -5)
+// CHECK-NEXT: #pragma omp simd private(val) safelen(7) linear(lin: -5)
for (T i = 7; i < m_a; ++i) {
val = v[i-7] + m_a;
res = val;
+ lin -= 5;
}
const T clen = 3;
// CHECK: T clen = 3;
@@ -58,9 +61,14 @@ template<class T> struct S {
template<int LEN> struct S2 {
static void func(int n, float *a, float *b, float *c) {
-#pragma omp simd safelen(LEN)
+ int k1 = 0, k2 = 0;
+#pragma omp simd safelen(LEN) linear(k1,k2:LEN)
for(int i = 0; i < n; i++) {
c[i] = a[i] + b[i];
+ c[k1] = a[k1] + b[k1];
+ c[k2] = a[k2] + b[k2];
+ k1 = k1 + LEN;
+ k2 = k2 + LEN;
}
}
};
@@ -68,9 +76,14 @@ template<int LEN> struct S2 {
// S2<4>::func is called below in main.
// CHECK: template <int LEN = 4> struct S2 {
// CHECK-NEXT: static void func(int n, float *a, float *b, float *c) {
-// CHECK-NEXT: #pragma omp simd safelen(4)
+// CHECK-NEXT: int k1 = 0, k2 = 0;
+// CHECK-NEXT: #pragma omp simd safelen(4) linear(k1,k2: 4)
// CHECK-NEXT: for (int i = 0; i < n; i++) {
// CHECK-NEXT: c[i] = a[i] + b[i];
+// CHECK-NEXT: c[k1] = a[k1] + b[k1];
+// CHECK-NEXT: c[k2] = a[k2] + b[k2];
+// CHECK-NEXT: k1 = k1 + 4;
+// CHECK-NEXT: k2 = k2 + 4;
// CHECK-NEXT: }
// CHECK-NEXT: }
@@ -99,8 +112,8 @@ int main (int argc, char **argv) {
// CHECK-NEXT: foo();
const int CLEN = 4;
// CHECK-NEXT: const int CLEN = 4;
- #pragma omp simd safelen(CLEN)
-// CHECK-NEXT: #pragma omp simd safelen(CLEN)
+ #pragma omp simd linear(a:CLEN) safelen(CLEN)
+// CHECK-NEXT: #pragma omp simd linear(a: CLEN) safelen(CLEN)
for (int i = 0; i < 10; ++i)foo();
// CHECK-NEXT: for (int i = 0; i < 10; ++i)
// CHECK-NEXT: foo();
diff --git a/test/OpenMP/simd_linear_messages.cpp b/test/OpenMP/simd_linear_messages.cpp
new file mode 100644
index 0000000000..e90bc69444
--- /dev/null
+++ b/test/OpenMP/simd_linear_messages.cpp
@@ -0,0 +1,205 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 %s
+
+namespace X {
+ int x;
+};
+
+struct B {
+ static int ib; // expected-note {{'B::ib' declared here}}
+ static int bfoo() { return 8; }
+};
+
+int bfoo() { return 4; }
+
+int z;
+const int C1 = 1;
+const int C2 = 2;
+void test_linear_colons()
+{
+ int B = 0;
+ #pragma omp simd linear(B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'}}
+ #pragma omp simd linear(B::ib:B:bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{use of undeclared identifier 'ib'; did you mean 'B::ib'}}
+ #pragma omp simd linear(B:ib)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{unexpected ':' in nested name specifier; did you mean '::'?}}
+ #pragma omp simd linear(z:B:ib)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp simd linear(B:B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp simd linear(X::x : ::z)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp simd linear(B,::z, X::x)
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp simd linear(::z)
+ for (int i = 0; i < 10; ++i) ;
+ // expected-error@+1 {{expected variable name}}
+ #pragma omp simd linear(B::bfoo())
+ for (int i = 0; i < 10; ++i) ;
+ #pragma omp simd linear(B::ib,B:C1+C2)
+ for (int i = 0; i < 10; ++i) ;
+}
+
+template<int L, class T, class N> T test_template(T* arr, N num) {
+ N i;
+ T sum = (T)0;
+ T ind2 = - num * L; // expected-note {{'ind2' defined here}}
+ // expected-error@+1 {{argument of a linear clause should be of integral or pointer type}}
+#pragma omp simd linear(ind2:L)
+ for (i = 0; i < num; ++i) {
+ T cur = arr[ind2];
+ ind2 += L;
+ sum += cur;
+ }
+}
+
+template<int LEN> int test_warn() {
+ int ind2 = 0;
+ // expected-warning@+1 {{zero linear step (ind2 should probably be const)}}
+ #pragma omp simd linear(ind2:LEN)
+ for (int i = 0; i < 100; i++) {
+ ind2 += LEN;
+ }
+ return ind2;
+}
+
+struct S1; // expected-note 2 {{declared here}} expected-note 2 {{forward declaration of 'S1'}}
+extern S1 a;
+class S2 {
+ mutable int a;
+public:
+ S2():a(0) { }
+};
+const S2 b; // expected-note 2 {{'b' defined here}}
+const S2 ba[5];
+class S3 {
+ int a;
+public:
+ S3():a(0) { }
+};
+const S3 ca[5];
+class S4 {
+ int a;
+ S4();
+public:
+ S4(int v):a(v) { }
+};
+class S5 {
+ int a;
+ S5():a(0) {}
+public:
+ S5(int v):a(v) { }
+};
+
+S3 h;
+#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
+
+template<class I, class C> int foomain(I argc, C **argv) {
+ I e(4);
+ I g(5);
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ #pragma omp simd linear // expected-error {{expected '(' after 'linear'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear () // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc : 5)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{linear variable with incomplete type 'S1'}}
+ // expected-error@+1 {{const-qualified variable cannot be linear}}
+ #pragma omp simd linear (a, b:B::ib)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear(e, g)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear(h) // expected-error {{threadprivate or thread local variable cannot be linear}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel
+ {
+ int v = 0;
+ int i;
+ #pragma omp simd linear(v:i)
+ for (int k = 0; k < argc; ++k) { i = k; v += i; }
+ }
+ #pragma omp simd linear(j) // expected-error {{arguments of OpenMP clause 'linear' cannot be of reference type}}
+ for (int k = 0; k < argc; ++k) ++k;
+ int v = 0;
+ #pragma omp simd linear(v:j)
+ for (int k = 0; k < argc; ++k) { ++k; v += j; }
+ #pragma omp simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ double darr[100];
+ // expected-note@+1 {{in instantiation of function template specialization 'test_template<-4, double, int>' requested here}}
+ test_template<-4>(darr, 4);
+ // expected-note@+1 {{in instantiation of function template specialization 'test_warn<0>' requested here}}
+ test_warn<0>();
+
+ S4 e(4); // expected-note {{'e' defined here}}
+ S5 g(5); // expected-note {{'g' defined here}}
+ int i;
+ int &j = i; // expected-note {{'j' defined here}}
+ #pragma omp simd linear // expected-error {{expected '(' after 'linear'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear () // expected-error {{expected expression}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argc)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (S1) // expected-error {{'S1' does not refer to a value}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{linear variable with incomplete type 'S1'}}
+ // expected-error@+1 {{const-qualified variable cannot be linear}}
+ #pragma omp simd linear (a, b)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear (argv[1]) // expected-error {{expected variable name}}
+ for (int k = 0; k < argc; ++k) ++k;
+ // expected-error@+2 {{argument of a linear clause should be of integral or pointer type, not 'S4'}}
+ // expected-error@+1 {{argument of a linear clause should be of integral or pointer type, not 'S5'}}
+ #pragma omp simd linear(e, g)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear(h) // expected-error {{threadprivate or thread local variable cannot be linear}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp parallel
+ {
+ int i;
+ #pragma omp simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear(i : 4)
+ for (int k = 0; k < argc; ++k) { ++k; i += 4; }
+ }
+ #pragma omp simd linear(j) // expected-error {{arguments of OpenMP clause 'linear' cannot be of reference type 'int &'}}
+ for (int k = 0; k < argc; ++k) ++k;
+ #pragma omp simd linear(i)
+ for (int k = 0; k < argc; ++k) ++k;
+
+ foomain<int,char>(argc,argv);
+ return 0;
+}
+
diff --git a/test/OpenMP/simd_misc_messages.c b/test/OpenMP/simd_misc_messages.c
index 0800d22988..6e2f81cee1 100644
--- a/test/OpenMP/simd_misc_messages.c
+++ b/test/OpenMP/simd_misc_messages.c
@@ -146,6 +146,80 @@ void test_safelen()
for (i = 0; i < 16; ++i);
}
+void test_linear()
+{
+ int i;
+ // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+ #pragma omp simd linear(
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+2 {{expected expression}}
+ // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+ #pragma omp simd linear(,
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+2 {{expected expression}}
+ // expected-error@+1 {{expected expression}}
+ #pragma omp simd linear(,)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected expression}}
+ #pragma omp simd linear()
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected expression}}
+ #pragma omp simd linear(int)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected variable name}}
+ #pragma omp simd linear(0)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{use of undeclared identifier 'x'}}
+ #pragma omp simd linear(x)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+2 {{use of undeclared identifier 'x'}}
+ // expected-error@+1 {{use of undeclared identifier 'y'}}
+ #pragma omp simd linear(x, y)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+3 {{use of undeclared identifier 'x'}}
+ // expected-error@+2 {{use of undeclared identifier 'y'}}
+ // expected-error@+1 {{use of undeclared identifier 'z'}}
+ #pragma omp simd linear(x, y, z)
+ for (i = 0; i < 16; ++i) ;
+
+ int x, y;
+ // expected-error@+1 {{expected expression}}
+ #pragma omp simd linear(x:)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected expression}} expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+ #pragma omp simd linear(x:,)
+ for (i = 0; i < 16; ++i) ;
+ #pragma omp simd linear(x:1)
+ for (i = 0; i < 16; ++i) ;
+ #pragma omp simd linear(x:2*2)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+ #pragma omp simd linear(x:1,y)
+ for (i = 0; i < 16; ++i) ;
+ // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
+ #pragma omp simd linear(x:1,y,z:1)
+ for (i = 0; i < 16; ++i) ;
+
+ // expected-note@+2 {{defined as linear}}
+ // expected-error@+1 {{linear variable cannot be linear}}
+ #pragma omp simd linear(x) linear(x)
+ for (i = 0; i < 16; ++i) ;
+
+ // expected-note@+2 {{defined as private}}
+ // expected-error@+1 {{private variable cannot be linear}}
+ #pragma omp simd private(x) linear(x)
+ for (i = 0; i < 16; ++i) ;
+
+ // expected-note@+2 {{defined as linear}}
+ // expected-error@+1 {{linear variable cannot be private}}
+ #pragma omp simd linear(x) private(x)
+ for (i = 0; i < 16; ++i) ;
+
+ // expected-warning@+1 {{zero linear step (x and other variables in clause should probably be const)}}
+ #pragma omp simd linear(x,y:0)
+ for (i = 0; i < 16; ++i) ;
+}
+
void test_private()
{
int i;
diff --git a/test/PCH/modified-module-dependency.m b/test/PCH/modified-module-dependency.m
index 650eaddacd..3db8f3d9c7 100644
--- a/test/PCH/modified-module-dependency.m
+++ b/test/PCH/modified-module-dependency.m
@@ -5,13 +5,13 @@
// RUN: cp %S/modified-module-dependency.module.map %t-dir/module.map
// Precompile prefix.pch.
-// RUN: %clang_cc1 -x objective-c -I %t-dir -fmodules -fmodules-cache-path=%t-dir/cache -emit-pch %t-dir/prefix.h -o %t-dir/prefix.pch
+// RUN: %clang_cc1 -x objective-c -I %t-dir -fmodules -fmodules-cache-path=%t-dir/cache -fdisable-module-hash -emit-pch %t-dir/prefix.h -o %t-dir/prefix.pch
// Modify the dependency.
// RUN: echo ' ' >> %t-dir/test.h
// Run and check the diagnostics.
-// RUN: not %clang_cc1 -x objective-c -include-pch %t-dir/prefix.pch -fmodules -fmodules-cache-path=%t-dir/cache -fsyntax-only %s 2> %t-dir/log
+// RUN: not %clang_cc1 -x objective-c -I %t-dir -include-pch %t-dir/prefix.pch -fmodules -fmodules-cache-path=%t-dir/cache -fdisable-module-hash -fsyntax-only %s 2> %t-dir/log
// RUN: FileCheck %s < %t-dir/log
// CHECK: file '[[TEST_H:.*[/\\]test\.h]]' has been modified since the precompiled header '[[PREFIX_PCH:.*/prefix\.pch]]' was built
diff --git a/test/PCH/single-token-macro.c b/test/PCH/single-token-macro.c
index 52873bfc24..aa02f65f78 100644
--- a/test/PCH/single-token-macro.c
+++ b/test/PCH/single-token-macro.c
@@ -12,6 +12,11 @@
#ifndef HEADER
#define HEADER
+#ifdef __stdcall
+// __stdcall is defined as __attribute__((__stdcall__)) for targeting mingw32.
+#undef __stdcall
+#endif
+
#define __stdcall
#define STDCALL __stdcall
diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c
index b9f531fb1e..badd2049f5 100644
--- a/test/Parser/MicrosoftExtensions.c
+++ b/test/Parser/MicrosoftExtensions.c
@@ -102,6 +102,12 @@ struct __declspec(frobble) S1 {}; /* expected-warning {{__declspec attribute 'fr
struct __declspec(12) S2 {}; /* expected-error {{__declspec attributes must be an identifier or string literal}} */
struct __declspec("testing") S3 {}; /* expected-warning {{__declspec attribute '"testing"' is not supported}} */
+/* declspecs with arguments cannot have an empty argument list, even if the
+ arguments are optional. */
+__declspec(deprecated()) void dep_func_test(void); /* expected-error {{parentheses must be omitted if 'deprecated' attribute's argument list is empty}} */
+__declspec(deprecated) void dep_func_test2(void);
+__declspec(deprecated("")) void dep_func_test3(void);
+
/* Ensure multiple declspec attributes are supported */
struct __declspec(align(8) deprecated) S4 {};
diff --git a/test/Parser/altivec.c b/test/Parser/altivec.c
index 0bdc3dcffe..436a3afd2d 100644
--- a/test/Parser/altivec.c
+++ b/test/Parser/altivec.c
@@ -103,8 +103,8 @@ void f() {
gccvector unsigned int gv = v;
gccvector int gvi = (gccvector int)v;
__attribute__((vector_size(8))) unsigned int gv8;
- gv8 = gccv; // expected-error {{assigning to '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int' from incompatible type '__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int'}}
- av = gv8; // expected-error {{assigning to '__vector unsigned int' from incompatible type '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int'}}
+ gv8 = gccv; // expected-error {{assigning to '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int' (vector of 2 'unsigned int' values) from incompatible type '__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int' (vector of 4 'unsigned int' values)}}
+ av = gv8; // expected-error {{assigning to '__vector unsigned int' (vector of 4 'unsigned int' values) from incompatible type '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int' (vector of 2 'unsigned int' values)}}
v = gccv;
__vector unsigned int tv = gccv;
diff --git a/test/Parser/arm-windows-calling-convention-handling.c b/test/Parser/arm-windows-calling-convention-handling.c
new file mode 100644
index 0000000000..7717aada53
--- /dev/null
+++ b/test/Parser/arm-windows-calling-convention-handling.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple thumbv7-windows -fms-compatibility -fsyntax-only -verify %s
+
+int __cdecl cdecl(int a, int b, int c, int d) { // expected-warning {{calling convention '__cdecl' ignored for this target}}
+ return a + b + c + d;
+}
+
+float __stdcall stdcall(float a, float b, float c, float d) { // expected-warning {{calling convention '__stdcall' ignored for this target}}
+ return a + b + c + d;
+}
+
diff --git a/test/Parser/attributes.c b/test/Parser/attributes.c
index 8d7e5fe503..3d69c72c32 100644
--- a/test/Parser/attributes.c
+++ b/test/Parser/attributes.c
@@ -94,5 +94,4 @@ void testFundef5() __attribute__(()) { }
__attribute__((pure)) int testFundef6(int a) { return a; }
-
-
+void deprecatedTestFun(void) __attribute__((deprecated()));
diff --git a/test/Parser/check-objc2-syntax-1.m b/test/Parser/check-objc2-syntax-1.m
index 6c30096cdd..364f826776 100644
--- a/test/Parser/check-objc2-syntax-1.m
+++ b/test/Parser/check-objc2-syntax-1.m
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// rdar://15505492
-@import Foundation; // expected-error {{use of '@import' when modules are disabled, add -fmodules}}
+@import Foundation; // expected-error {{use of '@import' when modules are disabled}}
@interface Subclass
+ (int)magicNumber;
diff --git a/test/Parser/cxx-altivec.cpp b/test/Parser/cxx-altivec.cpp
index be00e494fd..27cab2c9c4 100644
--- a/test/Parser/cxx-altivec.cpp
+++ b/test/Parser/cxx-altivec.cpp
@@ -93,8 +93,8 @@ void f() {
gccvector unsigned int gv = v;
gccvector int gvi = (gccvector int)v;
__attribute__((vector_size(8))) unsigned int gv8;
- gv8 = gccv; // expected-error {{assigning to '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int' from incompatible type '__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int'}}
- av = gv8; // expected-error {{assigning to '__vector unsigned int' from incompatible type '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int'}}
+ gv8 = gccv; // expected-error {{assigning to '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int' (vector of 2 'unsigned int' values) from incompatible type '__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int' (vector of 4 'unsigned int' values)}}
+ av = gv8; // expected-error {{assigning to '__vector unsigned int' (vector of 4 'unsigned int' values) from incompatible type '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int' (vector of 2 'unsigned int' values)}}
v = gccv;
__vector unsigned int tv = gccv;
diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
index 1b9e477004..f8abc76fb2 100644
--- a/test/Parser/cxx0x-attributes.cpp
+++ b/test/Parser/cxx0x-attributes.cpp
@@ -322,3 +322,10 @@ namespace GccASan {
[[gnu::no_address_safety_analysis]] void f3();
[[gnu::no_sanitize_address]] void f4();
}
+
+namespace {
+ [[deprecated]] void bar();
+ [[deprecated("hello")]] void baz();
+ [[deprecated()]] void foo(); // expected-error {{parentheses must be omitted if 'deprecated' attribute's argument list is empty}}
+ [[gnu::deprecated()]] void quux();
+}
diff --git a/test/Parser/cxx0x-lambda-expressions.cpp b/test/Parser/cxx0x-lambda-expressions.cpp
index 53ea05ea86..8cfe7f3b02 100644
--- a/test/Parser/cxx0x-lambda-expressions.cpp
+++ b/test/Parser/cxx0x-lambda-expressions.cpp
@@ -2,6 +2,8 @@
enum E { e };
+constexpr int id(int n) { return n; }
+
class C {
int f() {
@@ -34,12 +36,18 @@ class C {
typedef int T;
const int b = 0;
const int c = 1;
+ int d;
int a1[1] = {[b] (T()) {}}; // expected-error{{no viable conversion from '(lambda}}
int a2[1] = {[b] = 1 };
- int a3[1] = {[b,c] = 1 }; // expected-error{{expected body of lambda expression}}
+ int a3[1] = {[b,c] = 1 }; // expected-error{{expected ']'}} expected-note {{to match}}
int a4[1] = {[&b] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'const int *'}}
int a5[3] = { []{return 0;}() };
int a6[1] = {[this] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'C *'}}
+ int a7[1] = {[d(0)] { return d; } ()}; // expected-warning{{extension}}
+ int a8[1] = {[d = 0] { return d; } ()}; // expected-warning{{extension}}
+ int a9[1] = {[d = 0] = 1}; // expected-error{{is not an integral constant expression}}
+ int a10[1] = {[id(0)] { return id; } ()}; // expected-warning{{extension}}
+ int a11[1] = {[id(0)] = 1};
}
void delete_lambda(int *p) {
diff --git a/test/Parser/opencl-astype.cl b/test/Parser/opencl-astype.cl
index d4c547e5cb..72f98a4ace 100644
--- a/test/Parser/opencl-astype.cl
+++ b/test/Parser/opencl-astype.cl
@@ -11,7 +11,7 @@ void test_astype() {
typedef __attribute__(( ext_vector_type(4) )) double double4;
float4 f4;
- double4 d4 = __builtin_astype(f4, double4); // expected-error{{invalid reinterpretation: sizes of 'double4' and 'float4' must match}}
+ double4 d4 = __builtin_astype(f4, double4); // expected-error{{invalid reinterpretation: sizes of 'double4' (vector of 4 'double' values) and 'float4' (vector of 4 'float' values) must match}}
// Verify int4->float3, float3->int4 works.
int4 i4;
diff --git a/test/Parser/recovery.cpp b/test/Parser/recovery.cpp
index cb1979f9ff..5608b50468 100644
--- a/test/Parser/recovery.cpp
+++ b/test/Parser/recovery.cpp
@@ -135,3 +135,70 @@ enum class EnumID {};
template <typename> struct TempID;
template <> struct TempID<BadType> : BadType, EnumID::Garbage; // expected-error{{use of undeclared identifier 'BadType'}}
}
+
+namespace pr15133 {
+ namespace ns {
+ const int V1 = 1; // expected-note {{declared here}}
+ }
+ struct C1 {
+ enum E1 { V2 = 2 }; // expected-note {{declared here}}
+ static const int V3 = 3; // expected-note {{declared here}}
+ };
+ enum E2 {
+ V4 = 4, // expected-note {{declared here}}
+ V6 // expected-note {{declared here}}
+ };
+ enum class EC3 { V0 = 0, V5 = 5 }; // expected-note {{declared here}}
+ void func_3();
+
+ void func_1(int x) {
+ switch(x) {
+ case 0: break;
+ case ns::V1:: break; // expected-error{{'V1' cannot appear before '::' because it is not a class, namespace, or scoped enumeration; did you mean ':'?}}
+ case C1::V2:: break; // expected-error{{'V2' cannot appear before '::' because it is not a class, namespace, or scoped enumeration; did you mean ':'?}}
+ case C1::V3:: break; // expected-error{{'V3' cannot appear before '::' because it is not a class, namespace, or scoped enumeration; did you mean ':'?}}
+ case V4:: break; // expected-error{{'V4' cannot appear before '::' because it is not a class, namespace, or scoped enumeration; did you mean ':'?}}
+ case V6:: func_3(); // expected-error{{'V6' cannot appear before '::' because it is not a class, namespace, or scoped enumeration; did you mean ':'?}}
+ }
+ }
+ void func_2(EC3 x) {
+ switch(x) {
+ case EC3::V0: break;
+ case EC3::V5:: break; // expected-error{{'V5' cannot appear before '::' because it is not a class, namespace, or scoped enumeration; did you mean ':'?}}
+ }
+ }
+
+ template<class T> struct TS1 {
+ typedef int A;
+ };
+ template<class T> void func(int x) {
+ switch(x) {
+ case TS1<T>::A:: break; // expected-error{{expected unqualified-id}}
+ }
+ };
+ void mainf() {
+ func<int>(1);
+ }
+
+ struct S {
+ static int n; // expected-note{{declared here}}
+ int nn; // expected-note 2 {{declared here}}
+ };
+
+ int func_3(int x) {
+ return x ? S::n :: 0; // expected-error{{'n' cannot appear before '::' because it is not a class, namespace, or scoped enumeration; did you mean ':'?}}
+ }
+ int func_4(int x, S &s) {
+ return x ? s.nn :: x; // expected-error{{'nn' cannot appear before '::' because it is not a class, namespace, or scoped enumeration; did you mean ':'?}}
+ }
+ int func_5(int x, S &s) {
+ return x ? s.nn :: S::n; // expected-error{{'nn' cannot appear before '::' because it is not a class, namespace, or scoped enumeration; did you mean ':'?}}
+ }
+
+ struct S2 {
+ struct S3;
+ };
+
+ struct S2 :: S3 :: public S2 { // expected-error{{'public' cannot be a part of nested name specifier; did you mean ':'?}}
+ };
+}
diff --git a/test/Preprocessor/aarch64-target-features.c b/test/Preprocessor/aarch64-target-features.c
index e487667ca5..b51556f6fa 100644
--- a/test/Preprocessor/aarch64-target-features.c
+++ b/test/Preprocessor/aarch64-target-features.c
@@ -1,4 +1,5 @@
// RUN: %clang -target aarch64-none-linux-gnu -x c -E -dM %s -o - | FileCheck %s
+// RUN: %clang -target arm64-none-linux-gnu -x c -E -dM %s -o - | FileCheck %s
// CHECK: __AARCH64EL__ 1
// CHECK: __ARM_64BIT_STATE 1
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index 8f57d298c3..4fc4bfa47d 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -213,6 +213,7 @@
// Other definitions vary from platform to platform
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=aarch64-none-none < /dev/null | FileCheck -check-prefix AARCH64 %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm64-none-none < /dev/null | FileCheck -check-prefix AARCH64 %s
//
// AARCH64:#define _LP64 1
// AARCH64-NOT:#define __AARCH64EB__ 1
@@ -315,6 +316,7 @@
// AARCH64:#define __aarch64__ 1
//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=aarch64_be-none-none < /dev/null | FileCheck -check-prefix AARCH64-BE %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm64_be-none-none < /dev/null | FileCheck -check-prefix AARCH64-BE %s
//
// AARCH64-BE:#define _LP64 1
// AARCH64-BE:#define __AARCH64EB__ 1
diff --git a/test/Preprocessor/macro-multiline.c b/test/Preprocessor/macro-multiline.c
new file mode 100644
index 0000000000..526192860c
--- /dev/null
+++ b/test/Preprocessor/macro-multiline.c
@@ -0,0 +1,7 @@
+// RUN: printf -- "-DX=A\nTHIS_SHOULD_NOT_EXIST_IN_THE_OUTPUT" | xargs -0 %clang -E %s | FileCheck -strict-whitespace %s
+// REQUIRES: shell
+
+// Per GCC -D semantics, \n and anything that follows is ignored.
+
+// CHECK: {{^START A END$}}
+START X END
diff --git a/test/Preprocessor/macro-multiline.c.ignoreme b/test/Preprocessor/macro-multiline.c.ignoreme
deleted file mode 100644
index df7c40a954..0000000000
--- a/test/Preprocessor/macro-multiline.c.ignoreme
+++ /dev/null
@@ -1,8 +0,0 @@
-// RUN: %clang -E %s "-DX=A
-// RUN: THIS_SHOULD_NOT_EXIST_IN_THE_OUTPUT" > %t
-// RUN: grep "GOOD: A" %t
-// RUN: not grep THIS_SHOULD_NOT_EXIST_IN_THE_OUTPUT %t
-// rdar://6762183
-
-GOOD: X
-
diff --git a/test/Preprocessor/macro_redefined.c b/test/Preprocessor/macro_redefined.c
new file mode 100644
index 0000000000..f7d3d6db00
--- /dev/null
+++ b/test/Preprocessor/macro_redefined.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 %s -Eonly -verify -Wno-all -Wmacro-redefined -DCLI_MACRO=1 -DWMACRO_REDEFINED
+// RUN: %clang_cc1 %s -Eonly -verify -Wno-all -Wno-macro-redefined -DCLI_MACRO=1
+
+#ifndef WMACRO_REDEFINED
+// expected-no-diagnostics
+#endif
+
+#ifdef WMACRO_REDEFINED
+// expected-note@1 {{previous definition is here}}
+// expected-warning@+2 {{macro redefined}}
+#endif
+#define CLI_MACRO
+
+#ifdef WMACRO_REDEFINED
+// expected-note@+3 {{previous definition is here}}
+// expected-warning@+3 {{macro redefined}}
+#endif
+#define REGULAR_MACRO
+#define REGULAR_MACRO 1
diff --git a/test/Preprocessor/woa-defaults.c b/test/Preprocessor/woa-defaults.c
new file mode 100644
index 0000000000..6eab3b96f4
--- /dev/null
+++ b/test/Preprocessor/woa-defaults.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -dM -triple armv7-windows -E %s | FileCheck %s
+// RUN: %clang_cc1 -dM -fno-signed-char -triple armv7-windows -E %s \
+// RUN: | FileCheck %s -check-prefix CHECK-UNSIGNED-CHAR
+
+// CHECK: #define _INTEGRAL_MAX_BITS 64
+// CHECK: #define _M_ARM 7
+// CHECK: #define _M_ARMT _M_ARM
+// CHECK: #define _M_ARM_FP 31
+// CHECK: #define _M_ARM_NT 1
+// CHECK: #define _M_THUMB _M_ARM
+// CHECK: #define _WIN32 1
+
+// CHECK: #define __ARM_PCS 1
+// CHECK: #define __ARM_PCS_VFP 1
+// CHECK: #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
+// CHECK: #define __SIZEOF_DOUBLE__ 8
+// CHECK: #define __SIZEOF_FLOAT__ 4
+// CHECK: #define __SIZEOF_INT__ 4
+// CHECK: #define __SIZEOF_LONG_DOUBLE__ 8
+// CHECK: #define __SIZEOF_LONG_LONG__ 8
+// CHECK: #define __SIZEOF_LONG__ 4
+// CHECK: #define __SIZEOF_POINTER__ 4
+// CHECK: #define __SIZEOF_PTRDIFF_T__ 4
+// CHECK: #define __SIZEOF_SHORT__ 2
+// CHECK: #define __SIZEOF_SIZE_T__ 4
+// CHECK: #define __SIZEOF_WCHAR_T__ 2
+// CHECK: #define __SIZEOF_WINT_T__ 4
+
+// CHECK-NOT: __THUMB_INTERWORK__
+// CHECK-NOT: __ARM_EABI__
+// CHECK-NOT: _CHAR_UNSIGNED
+
+// CHECK-UNSIGNED-CHAR: #define _CHAR_UNSIGNED 1
diff --git a/test/Profile/Inputs/c-attributes.profdata b/test/Profile/Inputs/c-attributes.proftext
index 97e682480d..e4d4694a8d 100644
--- a/test/Profile/Inputs/c-attributes.profdata
+++ b/test/Profile/Inputs/c-attributes.proftext
@@ -23,7 +23,7 @@ cold_func
124750
main
-6
+219169028
6
1
0
diff --git a/test/Profile/Inputs/c-captured.proftext b/test/Profile/Inputs/c-captured.proftext
new file mode 100644
index 0000000000..c1baefc894
--- /dev/null
+++ b/test/Profile/Inputs/c-captured.proftext
@@ -0,0 +1,25 @@
+c-captured.c:__captured_stmt
+10
+2
+1
+1
+
+c-captured.c:__captured_stmt1
+266
+3
+1
+10
+1
+
+main
+0
+1
+1
+
+debug_captured
+650
+3
+1
+1
+1
+
diff --git a/test/Profile/Inputs/c-counter-overflows.profdata b/test/Profile/Inputs/c-counter-overflows.proftext
index 24863780ef..5a3633ecfc 100644
--- a/test/Profile/Inputs/c-counter-overflows.profdata
+++ b/test/Profile/Inputs/c-counter-overflows.proftext
@@ -1,5 +1,5 @@
main
-8
+285734896137
8
1
68719476720
diff --git a/test/Profile/Inputs/c-general.profdata b/test/Profile/Inputs/c-general.proftext
index a1d56104a2..19e5bd3db4 100644
--- a/test/Profile/Inputs/c-general.profdata
+++ b/test/Profile/Inputs/c-general.proftext
@@ -1,5 +1,5 @@
simple_loops
-4
+16515
4
1
100
@@ -7,7 +7,7 @@ simple_loops
75
conditionals
-11
+74917022372782735
11
1
100
@@ -22,7 +22,7 @@ conditionals
100
early_exits
-9
+44128811889290
9
1
0
@@ -35,7 +35,7 @@ early_exits
0
jumps
-22
+2016037664281362839
22
1
1
@@ -61,7 +61,7 @@ jumps
9
switches
-19
+2745195701975551402
19
1
1
@@ -84,7 +84,7 @@ switches
0
big_switch
-17
+10218718452081869619
17
1
32
@@ -105,7 +105,7 @@ big_switch
2
boolean_operators
-8
+291222909838
8
1
100
@@ -117,7 +117,7 @@ boolean_operators
50
boolop_loops
-9
+9760565944591
9
1
50
@@ -129,8 +129,15 @@ boolop_loops
50
26
+conditional_operator
+848
+3
+1
+0
+1
+
do_fallthrough
-4
+16586
4
1
10
@@ -138,12 +145,12 @@ do_fallthrough
8
main
-1
+0
1
1
c-general.c:static_func
-2
+4
2
1
10
diff --git a/test/Profile/Inputs/c-outdated-data.profdata b/test/Profile/Inputs/c-outdated-data.proftext
index 27015be82d..d57a6e9d06 100644
--- a/test/Profile/Inputs/c-outdated-data.profdata
+++ b/test/Profile/Inputs/c-outdated-data.proftext
@@ -1,12 +1,12 @@
no_usable_data
-3
+650
3
1
0
0
main
-1
+0
1
1
diff --git a/test/Profile/Inputs/c-unprofiled-blocks.proftext b/test/Profile/Inputs/c-unprofiled-blocks.proftext
new file mode 100644
index 0000000000..87b48e13fb
--- /dev/null
+++ b/test/Profile/Inputs/c-unprofiled-blocks.proftext
@@ -0,0 +1,32 @@
+never_called
+44257542701577
+9
+0
+0
+0
+0
+0
+0
+0
+0
+0
+
+main
+1
+1
+1
+
+dead_code
+2859007309808137
+10
+1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+
diff --git a/test/Profile/Inputs/cxx-class.profdata b/test/Profile/Inputs/cxx-class.proftext
index 756640d2f3..b4645edf93 100644
--- a/test/Profile/Inputs/cxx-class.profdata
+++ b/test/Profile/Inputs/cxx-class.proftext
@@ -1,40 +1,40 @@
_Z14simple_wrapperv
-2
+4
2
1
100
main
-1
+0
1
1
_ZN6SimpleD1Ev
-2
+10
2
0
0
_ZN6SimpleD2Ev
-2
+10
2
100
99
_ZN6Simple6methodEv
-2
+10
2
100
99
_ZN6SimpleC1Ei
-2
+10
2
0
0
_ZN6SimpleC2Ei
-2
+10
2
100
99
diff --git a/test/Profile/Inputs/cxx-lambda.proftext b/test/Profile/Inputs/cxx-lambda.proftext
new file mode 100644
index 0000000000..36646b5ab3
--- /dev/null
+++ b/test/Profile/Inputs/cxx-lambda.proftext
@@ -0,0 +1,20 @@
+cxx-lambda.cpp:_ZZ7lambdasvENK3$_0clEi
+654
+3
+10
+9
+9
+
+main
+0
+1
+1
+
+_Z7lambdasv
+41226
+4
+1
+1
+10
+1
+
diff --git a/test/Profile/Inputs/cxx-templates.proftext b/test/Profile/Inputs/cxx-templates.proftext
new file mode 100644
index 0000000000..5ea840038d
--- /dev/null
+++ b/test/Profile/Inputs/cxx-templates.proftext
@@ -0,0 +1,17 @@
+main
+0
+1
+1
+
+_Z4loopILj0EEvv
+4
+2
+1
+0
+
+_Z4loopILj100EEvv
+4
+2
+1
+100
+
diff --git a/test/Profile/Inputs/cxx-throws.profdata b/test/Profile/Inputs/cxx-throws.proftext
index 01e6c3c286..4016eca2ac 100644
--- a/test/Profile/Inputs/cxx-throws.profdata
+++ b/test/Profile/Inputs/cxx-throws.proftext
@@ -1,5 +1,5 @@
_Z6throwsv
-9
+18359008150154
9
1
100
@@ -12,7 +12,7 @@ _Z6throwsv
100
main
-1
+0
1
1
diff --git a/test/Profile/Inputs/objc-general.profdata b/test/Profile/Inputs/objc-general.proftext
index 8841e908c9..8d6771f9b3 100644
--- a/test/Profile/Inputs/objc-general.profdata
+++ b/test/Profile/Inputs/objc-general.proftext
@@ -1,17 +1,17 @@
objc-general.m:__13+[A foreach:]_block_invoke
-2
+10
2
2
1
objc-general.m:+[A foreach:]
-2
+6
2
1
2
main
-1
+0
1
1
diff --git a/test/Profile/c-attributes.c b/test/Profile/c-attributes.c
index 81809551fd..2dcc180624 100644
--- a/test/Profile/c-attributes.c
+++ b/test/Profile/c-attributes.c
@@ -1,6 +1,7 @@
// Test that instrumentation based profiling sets function attributes correctly.
-// RUN: %clang %s -o - -mllvm -disable-llvm-optzns -emit-llvm -S -fprofile-instr-use=%S/Inputs/c-attributes.profdata | FileCheck %s
+// RUN: llvm-profdata merge %S/Inputs/c-attributes.proftext -o %t.profdata
+// RUN: %clang %s -o - -mllvm -disable-llvm-optzns -emit-llvm -S -fprofile-instr-use=%t.profdata | FileCheck %s
extern int atoi(const char *);
diff --git a/test/Profile/c-captured.c b/test/Profile/c-captured.c
new file mode 100644
index 0000000000..47b1bbc7b7
--- /dev/null
+++ b/test/Profile/c-captured.c
@@ -0,0 +1,59 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-captured.c %s -o - -emit-llvm -fprofile-instr-generate | FileCheck -check-prefix=PGOGEN -check-prefix=PGOALL %s
+
+// RUN: llvm-profdata merge %S/Inputs/c-captured.proftext -o %t.profdata
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-captured.c %s -o - -emit-llvm -fprofile-instr-use=%t.profdata | FileCheck -check-prefix=PGOUSE -check-prefix=PGOALL %s
+
+// PGOGEN: @[[DCC:__llvm_profile_counters_debug_captured]] = global [3 x i64] zeroinitializer
+// PGOGEN: @[[CSC:__llvm_profile_counters___captured_stmt]] = internal global [2 x i64] zeroinitializer
+// PGOGEN: @[[C1C:__llvm_profile_counters___captured_stmt1]] = internal global [3 x i64] zeroinitializer
+
+// PGOALL-LABEL: define void @debug_captured()
+// PGOGEN: store {{.*}} @[[DCC]], i64 0, i64 0
+void debug_captured() {
+ int x = 10;
+
+ // Check both debug_captured counters, so we can do this all in one pass
+ // PGOGEN: store {{.*}} @[[DCC]], i64 0, i64 1
+ // PGOUSE: br {{.*}} !prof ![[DC1:[0-9]+]]
+ // PGOGEN: store {{.*}} @[[DCC]], i64 0, i64 2
+ // PGOUSE: br {{.*}} !prof ![[DC2:[0-9]+]]
+ // PGOALL: ret
+
+ // PGOALL-LABEL: define internal void @__captured_stmt(
+ // PGOGEN: store {{.*}} @[[CSC]], i64 0, i64 0
+ #pragma clang __debug captured
+ {
+ // PGOGEN: store {{.*}} @[[CSC]], i64 0, i64 1
+ // PGOUSE: br {{.*}} !prof ![[CS1:[0-9]+]]
+ if (x) {}
+ // PGOALL: ret
+ }
+
+ if (x) {} // This is DC1. Checked above.
+
+ // PGOALL-LABEL: define internal void @__captured_stmt1(
+ // PGOGEN: store {{.*}} @[[C1C]], i64 0, i64 0
+ #pragma clang __debug captured
+ {
+ // PGOGEN: store {{.*}} @[[C1C]], i64 0, i64 1
+ // PGOUSE: br {{.*}} !prof ![[C11:[0-9]+]]
+ for (int i = 0; i < x; ++i) {}
+ // PGOGEN: store {{.*}} @[[C1C]], i64 0, i64 2
+ // PGOUSE: br {{.*}} !prof ![[C12:[0-9]+]]
+ if (x) {}
+ // PGOALL: ret
+ }
+
+ if (x) {} // This is DC2. Checked above.
+}
+
+// PGOUSE-DAG: ![[DC1]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
+// PGOUSE-DAG: ![[DC2]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
+// PGOUSE-DAG: ![[CS1]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
+// PGOUSE-DAG: ![[C11]] = metadata !{metadata !"branch_weights", i32 11, i32 2}
+// PGOUSE-DAG: ![[C12]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
+
+int main(int argc, const char *argv[]) {
+ debug_captured();
+ return 0;
+}
diff --git a/test/Profile/c-counter-overflows.c b/test/Profile/c-counter-overflows.c
index 7cbe9bba86..f6f8f73fd9 100644
--- a/test/Profile/c-counter-overflows.c
+++ b/test/Profile/c-counter-overflows.c
@@ -1,7 +1,8 @@
// Test that big branch weights get scaled down to 32-bits, rather than just
// truncated.
-// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-counter-overflows.c %s -o - -emit-llvm -fprofile-instr-use=%S/Inputs/c-counter-overflows.profdata | FileCheck %s
+// RUN: llvm-profdata merge %S/Inputs/c-counter-overflows.proftext -o %t.profdata
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-counter-overflows.c %s -o - -emit-llvm -fprofile-instr-use=%t.profdata | FileCheck %s
typedef unsigned long long uint64_t;
diff --git a/test/Profile/c-general.c b/test/Profile/c-general.c
index 2475f26692..21ba005894 100644
--- a/test/Profile/c-general.c
+++ b/test/Profile/c-general.c
@@ -1,7 +1,9 @@
// Test instrumentation of general constructs in C.
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instr-generate | FileCheck -check-prefix=PGOGEN %s
-// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instr-use=%S/Inputs/c-general.profdata | FileCheck -check-prefix=PGOUSE %s
+
+// RUN: llvm-profdata merge %S/Inputs/c-general.proftext -o %t.profdata
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instr-use=%t.profdata | FileCheck -check-prefix=PGOUSE %s
// PGOGEN: @[[SLC:__llvm_profile_counters_simple_loops]] = global [4 x i64] zeroinitializer
// PGOGEN: @[[IFC:__llvm_profile_counters_conditionals]] = global [11 x i64] zeroinitializer
@@ -11,6 +13,7 @@
// PGOGEN: @[[BSC:__llvm_profile_counters_big_switch]] = global [17 x i64] zeroinitializer
// PGOGEN: @[[BOC:__llvm_profile_counters_boolean_operators]] = global [8 x i64] zeroinitializer
// PGOGEN: @[[BLC:__llvm_profile_counters_boolop_loops]] = global [9 x i64] zeroinitializer
+// PGOGEN: @[[COC:__llvm_profile_counters_conditional_operator]] = global [3 x i64] zeroinitializer
// PGOGEN: @[[MAC:__llvm_profile_counters_main]] = global [1 x i64] zeroinitializer
// PGOGEN: @[[STC:__llvm_profile_counters_static_func]] = internal global [2 x i64] zeroinitializer
@@ -412,6 +415,24 @@ void boolop_loops() {
// PGOUSE-NOT: br {{.*}} !prof ![0-9]+
}
+// PGOGEN-LABEL: @conditional_operator()
+// PGOUSE-LABEL: @conditional_operator()
+// PGOGEN: store {{.*}} @[[COC]], i64 0, i64 0
+void conditional_operator() {
+ int i = 100;
+
+ // PGOGEN: store {{.*}} @[[COC]], i64 0, i64 1
+ // PGOUSE: br {{.*}} !prof ![[CO1:[0-9]+]]
+ int j = i < 50 ? i : 1;
+
+ // PGOGEN: store {{.*}} @[[COC]], i64 0, i64 2
+ // PGOUSE: br {{.*}} !prof ![[CO2:[0-9]+]]
+ int k = i ?: 0;
+
+ // PGOGEN-NOT: store {{.*}} @[[COC]],
+ // PGOUSE-NOT: br {{.*}} !prof ![0-9]+
+}
+
void do_fallthrough() {
for (int i = 0; i < 10; ++i) {
int j = 0;
@@ -503,6 +524,8 @@ static void static_func() {
// PGOUSE-DAG: ![[BL6]] = metadata !{metadata !"branch_weights", i32 51, i32 2}
// PGOUSE-DAG: ![[BL7]] = metadata !{metadata !"branch_weights", i32 26, i32 27}
// PGOUSE-DAG: ![[BL8]] = metadata !{metadata !"branch_weights", i32 51, i32 2}
+// PGOUSE-DAG: ![[CO1]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
+// PGOUSE-DAG: ![[CO2]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
// PGOUSE-DAG: ![[ST1]] = metadata !{metadata !"branch_weights", i32 11, i32 2}
int main(int argc, const char *argv[]) {
@@ -514,6 +537,7 @@ int main(int argc, const char *argv[]) {
big_switch();
boolean_operators();
boolop_loops();
+ conditional_operator();
do_fallthrough();
static_func();
return 0;
diff --git a/test/Profile/c-linkage-available_externally.c b/test/Profile/c-linkage-available_externally.c
index cbdf306c82..adc1e6eee5 100644
--- a/test/Profile/c-linkage-available_externally.c
+++ b/test/Profile/c-linkage-available_externally.c
@@ -4,7 +4,7 @@
// CHECK: @__llvm_profile_counters_foo = linkonce_odr global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
// CHECK: @__llvm_profile_name_foo = linkonce_odr constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1
-// CHECK: @__llvm_profile_data_foo = linkonce_odr constant { i32, i32, i64, i8*, i64* } { i32 3, i32 1, i64 1, i8* getelementptr inbounds ([3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_foo, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
+// CHECK: @__llvm_profile_data_foo = linkonce_odr constant { i32, i32, i64, i8*, i64* } { i32 3, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_foo, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
inline int foo(void) { return 1; }
int main(void) {
diff --git a/test/Profile/c-linkage.c b/test/Profile/c-linkage.c
index 72eae1f0f3..482e8da900 100644
--- a/test/Profile/c-linkage.c
+++ b/test/Profile/c-linkage.c
@@ -4,18 +4,18 @@
// CHECK: @__llvm_profile_runtime = external global i32
// CHECK: @__llvm_profile_counters_foo = global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
// CHECK: @__llvm_profile_name_foo = constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1
-// CHECK: @__llvm_profile_data_foo = constant { i32, i32, i64, i8*, i64* } { i32 3, i32 1, i64 1, i8* getelementptr inbounds ([3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_foo, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
+// CHECK: @__llvm_profile_data_foo = constant { i32, i32, i64, i8*, i64* } { i32 3, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_foo, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
void foo(void) { }
// CHECK: @__llvm_profile_counters_foo_weak = weak global [5 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
// CHECK: @__llvm_profile_name_foo_weak = weak constant [8 x i8] c"foo_weak", section "__DATA,__llvm_prf_names", align 1
-// CHECK: @__llvm_profile_data_foo_weak = weak constant { i32, i32, i64, i8*, i64* } { i32 8, i32 5, i64 5, i8* getelementptr inbounds ([8 x i8]* @__llvm_profile_name_foo_weak, i32 0, i32 0), i64* getelementptr inbounds ([5 x i64]* @__llvm_profile_counters_foo_weak, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
+// CHECK: @__llvm_profile_data_foo_weak = weak constant { i32, i32, i64, i8*, i64* } { i32 8, i32 5, i64 {{[0-9]+}}, i8* getelementptr inbounds ([8 x i8]* @__llvm_profile_name_foo_weak, i32 0, i32 0), i64* getelementptr inbounds ([5 x i64]* @__llvm_profile_counters_foo_weak, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
void foo_weak(void) __attribute__((weak));
void foo_weak(void) { if (0){} if (0){} if (0){} if (0){} }
// CHECK: @__llvm_profile_counters_main = global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
// CHECK: @__llvm_profile_name_main = constant [4 x i8] c"main", section "__DATA,__llvm_prf_names", align 1
-// CHECK: @__llvm_profile_data_main = constant { i32, i32, i64, i8*, i64* } { i32 4, i32 1, i64 1, i8* getelementptr inbounds ([4 x i8]* @__llvm_profile_name_main, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_main, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
+// CHECK: @__llvm_profile_data_main = constant { i32, i32, i64, i8*, i64* } { i32 4, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([4 x i8]* @__llvm_profile_name_main, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_main, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
static void foo_internal(void);
int main(void) {
foo();
@@ -26,7 +26,7 @@ int main(void) {
// CHECK: @__llvm_profile_counters_foo_internal = internal global [3 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
// CHECK: @__llvm_profile_name_foo_internal = internal constant [24 x i8] c"c-linkage.c:foo_internal", section "__DATA,__llvm_prf_names", align 1
-// CHECK: @__llvm_profile_data_foo_internal = internal constant { i32, i32, i64, i8*, i64* } { i32 24, i32 3, i64 3, i8* getelementptr inbounds ([24 x i8]* @__llvm_profile_name_foo_internal, i32 0, i32 0), i64* getelementptr inbounds ([3 x i64]* @__llvm_profile_counters_foo_internal, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
+// CHECK: @__llvm_profile_data_foo_internal = internal constant { i32, i32, i64, i8*, i64* } { i32 24, i32 3, i64 {{[0-9]+}}, i8* getelementptr inbounds ([24 x i8]* @__llvm_profile_name_foo_internal, i32 0, i32 0), i64* getelementptr inbounds ([3 x i64]* @__llvm_profile_counters_foo_internal, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
static void foo_internal(void) { if (0){} if (0){} }
// CHECK: @llvm.used = appending global [5 x i8*] [i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo_weak to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_main to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo_internal to i8*)], section "llvm.metadata"
diff --git a/test/Profile/c-outdated-data.c b/test/Profile/c-outdated-data.c
index fe5a5c75cc..d0503acdb6 100644
--- a/test/Profile/c-outdated-data.c
+++ b/test/Profile/c-outdated-data.c
@@ -1,11 +1,12 @@
// Test that outdated data is ignored.
-// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o - -emit-llvm -fprofile-instr-use=%S/Inputs/c-outdated-data.profdata | FileCheck -check-prefix=PGOUSE %s
+// FIXME: It would be nice to use -verify here instead of FileCheck, but -verify
+// doesn't play well with warnings that have no line number.
-// TODO: We should have a warning or a remark that tells us the profile data was
-// discarded, rather than just checking that we fail to add metadata.
+// RUN: llvm-profdata merge %S/Inputs/c-outdated-data.proftext -o %t.profdata
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -fprofile-instr-use=%t.profdata -Wprofile-instr-dropped 2>&1 | FileCheck %s
+// CHECK: warning: profile data may be out of date: of 3 functions, 1 has no data and 1 has mismatched data that will be ignored
-// PGOUSE-LABEL: @no_usable_data()
void no_usable_data() {
int i = 0;
@@ -14,9 +15,12 @@ void no_usable_data() {
#ifdef GENERATE_OUTDATED_DATA
if (i) {}
#endif
+}
- // PGOUSE-NOT: br {{.*}} !prof ![0-9]+
+#ifndef GENERATE_OUTDATED_DATA
+void no_data() {
}
+#endif
int main(int argc, const char *argv[]) {
no_usable_data();
diff --git a/test/Profile/c-unprofiled-blocks.c b/test/Profile/c-unprofiled-blocks.c
new file mode 100644
index 0000000000..58bef9e296
--- /dev/null
+++ b/test/Profile/c-unprofiled-blocks.c
@@ -0,0 +1,69 @@
+// Blocks that we have no profile data for (ie, it was never reached in training
+// runs) shouldn't have any branch weight metadata added.
+
+// RUN: llvm-profdata merge %S/Inputs/c-unprofiled-blocks.proftext -o %t.profdata
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-unprofiled-blocks.c %s -o - -emit-llvm -fprofile-instr-use=%t.profdata | FileCheck -check-prefix=PGOUSE %s
+
+// PGOUSE-LABEL: @never_called(i32 %i)
+int never_called(int i) {
+ // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}}
+ if (i) {}
+
+ // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}}
+ for (i = 0; i < 100; ++i) {
+ }
+
+ // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}}
+ while (--i) {}
+
+ // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}}
+ do {} while (i++ < 75);
+
+ // PGOUSE: switch {{.*}} [
+ // PGOUSE-NEXT: i32 12
+ // PGOUSE-NEXT: i32 82
+ // PGOUSE-NEXT: ]{{$}}
+ switch (i) {
+ case 12: return 3;
+ case 82: return 0;
+ default: return 89;
+ }
+}
+
+// PGOUSE-LABEL: @dead_code(i32 %i)
+int dead_code(int i) {
+ // PGOUSE: br {{.*}}, !prof !{{[0-9]+}}
+ if (i) {
+ // This branch is never reached.
+
+ // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}}
+ if (!i) {}
+
+ // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}}
+ for (i = 0; i < 100; ++i) {
+ }
+
+ // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}}
+ while (--i) {}
+
+ // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}}
+ do {} while (i++ < 75);
+
+ // PGOUSE: switch {{.*}} [
+ // PGOUSE-NEXT: i32 12
+ // PGOUSE-NEXT: i32 82
+ // PGOUSE-NEXT: ]{{$}}
+ switch (i) {
+ case 12: return 3;
+ case 82: return 0;
+ default: return 89;
+ }
+ }
+ return 2;
+}
+
+// PGOUSE-LABEL: @main(i32 %argc, i8** %argv)
+int main(int argc, const char *argv[]) {
+ dead_code(0);
+ return 0;
+}
diff --git a/test/Profile/cxx-class.cpp b/test/Profile/cxx-class.cpp
index 7cbbc09610..1a0c84bdcc 100644
--- a/test/Profile/cxx-class.cpp
+++ b/test/Profile/cxx-class.cpp
@@ -6,7 +6,8 @@
// RUN: FileCheck --input-file=%tgen -check-prefix=MTHGEN %s
// RUN: FileCheck --input-file=%tgen -check-prefix=WRPGEN %s
-// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-use=%S/Inputs/cxx-class.profdata -fno-exceptions -target %itanium_abi_triple > %tuse
+// RUN: llvm-profdata merge %S/Inputs/cxx-class.proftext -o %t.profdata
+// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-use=%t.profdata -fno-exceptions -target %itanium_abi_triple > %tuse
// RUN: FileCheck --input-file=%tuse -check-prefix=CTRUSE %s
// RUN: FileCheck --input-file=%tuse -check-prefix=DTRUSE %s
// RUN: FileCheck --input-file=%tuse -check-prefix=MTHUSE %s
diff --git a/test/Profile/cxx-implicit.cpp b/test/Profile/cxx-implicit.cpp
new file mode 100644
index 0000000000..79840ad938
--- /dev/null
+++ b/test/Profile/cxx-implicit.cpp
@@ -0,0 +1,17 @@
+// Ensure that implicit methods aren't instrumented.
+
+// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-implicit.cpp -o - -emit-llvm -fprofile-instr-generate | FileCheck %s
+
+// An implicit constructor is generated for Base. We should not emit counters
+// for it.
+// CHECK-NOT: @__llvm_profile_counters__ZN4BaseC2Ev =
+
+struct Base {
+ virtual void foo();
+};
+
+struct Derived : public Base {
+ Derived();
+};
+
+Derived::Derived() {}
diff --git a/test/Profile/cxx-lambda.cpp b/test/Profile/cxx-lambda.cpp
new file mode 100644
index 0000000000..923a432464
--- /dev/null
+++ b/test/Profile/cxx-lambda.cpp
@@ -0,0 +1,58 @@
+// Tests for instrumentation of C++11 lambdas
+
+// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-lambda.cpp -std=c++11 -o - -emit-llvm -fprofile-instr-generate > %tgen
+// RUN: FileCheck --input-file=%tgen -check-prefix=PGOGEN %s
+// RUN: FileCheck --input-file=%tgen -check-prefix=LMBGEN %s
+
+// RUN: llvm-profdata merge %S/Inputs/cxx-lambda.proftext -o %t.profdata
+// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-lambda.cpp -std=c++11 -o - -emit-llvm -fprofile-instr-use=%t.profdata > %tuse
+// RUN: FileCheck --input-file=%tuse -check-prefix=PGOUSE %s
+// RUN: FileCheck --input-file=%tuse -check-prefix=LMBUSE %s
+
+// PGOGEN: @[[LWC:__llvm_profile_counters__Z7lambdasv]] = global [4 x i64] zeroinitializer
+// PGOGEN: @[[MAC:__llvm_profile_counters_main]] = global [1 x i64] zeroinitializer
+// LMBGEN: @[[LFC:"__llvm_profile_counters__ZZ7lambdasvENK3\$_0clEi"]] = internal global [3 x i64] zeroinitializer
+
+// PGOGEN-LABEL: define void @_Z7lambdasv()
+// PGOUSE-LABEL: define void @_Z7lambdasv()
+// PGOGEN: store {{.*}} @[[LWC]], i64 0, i64 0
+void lambdas() {
+ int i = 1;
+
+ // LMBGEN-LABEL: define internal{{( zeroext)?}} i1 @"_ZZ7lambdasvENK3$_0clEi"(
+ // LMBUSE-LABEL: define internal{{( zeroext)?}} i1 @"_ZZ7lambdasvENK3$_0clEi"(
+ // LMBGEN: store {{.*}} @[[LFC]], i64 0, i64 0
+ auto f = [&i](int k) {
+ // LMBGEN: store {{.*}} @[[LFC]], i64 0, i64 1
+ // LMBUSE: br {{.*}} !prof ![[LF1:[0-9]+]]
+ if (i > 0) {}
+ // LMBGEN: store {{.*}} @[[LFC]], i64 0, i64 2
+ // LMBUSE: br {{.*}} !prof ![[LF2:[0-9]+]]
+ return k && i;
+ };
+
+ // PGOGEN: store {{.*}} @[[LWC]], i64 0, i64 1
+ // PGOUSE: br {{.*}} !prof ![[LW1:[0-9]+]]
+ if (i) {}
+
+ // PGOGEN: store {{.*}} @[[LWC]], i64 0, i64 2
+ // PGOUSE: br {{.*}} !prof ![[LW2:[0-9]+]]
+ for (i = 0; i < 10; ++i)
+ f(9 - i);
+
+ // PGOGEN: store {{.*}} @[[LWC]], i64 0, i64 3
+ // PGOUSE: br {{.*}} !prof ![[LW3:[0-9]+]]
+ if (i) {}
+}
+
+// PGOUSE-DAG: ![[LW1]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
+// PGOUSE-DAG: ![[LW2]] = metadata !{metadata !"branch_weights", i32 11, i32 2}
+// PGOUSE-DAG: ![[LW3]] = metadata !{metadata !"branch_weights", i32 2, i32 1}
+
+// LMBUSE-DAG: ![[LF1]] = metadata !{metadata !"branch_weights", i32 10, i32 2}
+// LMBUSE-DAG: ![[LF2]] = metadata !{metadata !"branch_weights", i32 10, i32 2}
+
+int main(int argc, const char *argv[]) {
+ lambdas();
+ return 0;
+}
diff --git a/test/Profile/cxx-linkage.cpp b/test/Profile/cxx-linkage.cpp
index 44c1983c84..92dfed9882 100644
--- a/test/Profile/cxx-linkage.cpp
+++ b/test/Profile/cxx-linkage.cpp
@@ -3,18 +3,18 @@
// CHECK: @__llvm_profile_runtime = external global i32
// CHECK: @__llvm_profile_counters__Z3foov = global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
// CHECK: @__llvm_profile_name__Z3foov = constant [7 x i8] c"_Z3foov", section "__DATA,__llvm_prf_names", align 1
-// CHECK: @__llvm_profile_data__Z3foov = constant { i32, i32, i64, i8*, i64* } { i32 7, i32 1, i64 1, i8* getelementptr inbounds ([7 x i8]* @__llvm_profile_name__Z3foov, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters__Z3foov, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
+// CHECK: @__llvm_profile_data__Z3foov = constant { i32, i32, i64, i8*, i64* } { i32 7, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([7 x i8]* @__llvm_profile_name__Z3foov, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters__Z3foov, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
void foo(void) { }
// CHECK: @__llvm_profile_counters__Z8foo_weakv = weak global [5 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
// CHECK: @__llvm_profile_name__Z8foo_weakv = weak constant [12 x i8] c"_Z8foo_weakv", section "__DATA,__llvm_prf_names", align 1
-// CHECK: @__llvm_profile_data__Z8foo_weakv = weak constant { i32, i32, i64, i8*, i64* } { i32 12, i32 5, i64 5, i8* getelementptr inbounds ([12 x i8]* @__llvm_profile_name__Z8foo_weakv, i32 0, i32 0), i64* getelementptr inbounds ([5 x i64]* @__llvm_profile_counters__Z8foo_weakv, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
+// CHECK: @__llvm_profile_data__Z8foo_weakv = weak constant { i32, i32, i64, i8*, i64* } { i32 12, i32 5, i64 {{[0-9]+}}, i8* getelementptr inbounds ([12 x i8]* @__llvm_profile_name__Z8foo_weakv, i32 0, i32 0), i64* getelementptr inbounds ([5 x i64]* @__llvm_profile_counters__Z8foo_weakv, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
void foo_weak(void) __attribute__((weak));
void foo_weak(void) { if (0){} if (0){} if (0){} if (0){} }
// CHECK: @__llvm_profile_counters_main = global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
// CHECK: @__llvm_profile_name_main = constant [4 x i8] c"main", section "__DATA,__llvm_prf_names", align 1
-// CHECK: @__llvm_profile_data_main = constant { i32, i32, i64, i8*, i64* } { i32 4, i32 1, i64 1, i8* getelementptr inbounds ([4 x i8]* @__llvm_profile_name_main, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_main, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
+// CHECK: @__llvm_profile_data_main = constant { i32, i32, i64, i8*, i64* } { i32 4, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([4 x i8]* @__llvm_profile_name_main, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_main, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
inline void foo_inline(void);
int main(void) {
foo();
@@ -25,7 +25,7 @@ int main(void) {
// CHECK: @__llvm_profile_counters__Z10foo_inlinev = linkonce_odr global [7 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8
// CHECK: @__llvm_profile_name__Z10foo_inlinev = linkonce_odr constant [15 x i8] c"_Z10foo_inlinev", section "__DATA,__llvm_prf_names", align 1
-// CHECK: @__llvm_profile_data__Z10foo_inlinev = linkonce_odr constant { i32, i32, i64, i8*, i64* } { i32 15, i32 7, i64 7, i8* getelementptr inbounds ([15 x i8]* @__llvm_profile_name__Z10foo_inlinev, i32 0, i32 0), i64* getelementptr inbounds ([7 x i64]* @__llvm_profile_counters__Z10foo_inlinev, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
+// CHECK: @__llvm_profile_data__Z10foo_inlinev = linkonce_odr constant { i32, i32, i64, i8*, i64* } { i32 15, i32 7, i64 {{[0-9]+}}, i8* getelementptr inbounds ([15 x i8]* @__llvm_profile_name__Z10foo_inlinev, i32 0, i32 0), i64* getelementptr inbounds ([7 x i64]* @__llvm_profile_counters__Z10foo_inlinev, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8
inline void foo_inline(void) { if (0){} if (0){} if (0){} if (0){} if (0){} if (0){}}
// CHECK: @llvm.used = appending global [5 x i8*] [i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z3foov to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z8foo_weakv to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_main to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z10foo_inlinev to i8*)], section "llvm.metadata"
diff --git a/test/Profile/cxx-templates.cpp b/test/Profile/cxx-templates.cpp
new file mode 100644
index 0000000000..5f99b999b8
--- /dev/null
+++ b/test/Profile/cxx-templates.cpp
@@ -0,0 +1,42 @@
+// Tests for instrumentation of templated code. Each instantiation of a template
+// should be instrumented separately.
+
+// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-templates.cpp -std=c++11 -o - -emit-llvm -fprofile-instr-generate > %tgen
+// RUN: FileCheck --input-file=%tgen -check-prefix=T0GEN -check-prefix=ALL %s
+// RUN: FileCheck --input-file=%tgen -check-prefix=T100GEN -check-prefix=ALL %s
+
+// RUN: llvm-profdata merge %S/Inputs/cxx-templates.proftext -o %t.profdata
+// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-templates.cpp -std=c++11 -o - -emit-llvm -fprofile-instr-use=%t.profdata > %tuse
+// RUN: FileCheck --input-file=%tuse -check-prefix=T0USE -check-prefix=ALL %s
+// RUN: FileCheck --input-file=%tuse -check-prefix=T100USE -check-prefix=ALL %s
+
+// T0GEN: @[[T0C:__llvm_profile_counters__Z4loopILj0EEvv]] = linkonce_odr global [2 x i64] zeroinitializer
+// T100GEN: @[[T100C:__llvm_profile_counters__Z4loopILj100EEvv]] = linkonce_odr global [2 x i64] zeroinitializer
+
+// T0GEN-LABEL: define linkonce_odr void @_Z4loopILj0EEvv()
+// T0USE-LABEL: define linkonce_odr void @_Z4loopILj0EEvv()
+// T100GEN-LABEL: define linkonce_odr void @_Z4loopILj100EEvv()
+// T100USE-LABEL: define linkonce_odr void @_Z4loopILj100EEvv()
+template <unsigned N> void loop() {
+ // ALL-NOT: ret
+ // T0GEN: store {{.*}} @[[T0C]], i64 0, i64 0
+ // T100GEN: store {{.*}} @[[T100C]], i64 0, i64 0
+
+ // ALL-NOT: ret
+ // T0GEN: store {{.*}} @[[T0C]], i64 0, i64 1
+ // T0USE: br {{.*}} !prof ![[T01:[0-9]+]]
+ // T100GEN: store {{.*}} @[[T100C]], i64 0, i64 1
+ // T100USE: br {{.*}} !prof ![[T1001:[0-9]+]]
+ for (unsigned I = 0; I < N; ++I) {}
+
+ // ALL: ret
+}
+
+// T0USE-DAG: ![[T01]] = metadata !{metadata !"branch_weights", i32 1, i32 2}
+// T100USE-DAG: ![[T1001]] = metadata !{metadata !"branch_weights", i32 101, i32 2}
+
+int main(int argc, const char *argv[]) {
+ loop<0>();
+ loop<100>();
+ return 0;
+}
diff --git a/test/Profile/cxx-throws.cpp b/test/Profile/cxx-throws.cpp
index cdcf53a14b..e5017bc22b 100644
--- a/test/Profile/cxx-throws.cpp
+++ b/test/Profile/cxx-throws.cpp
@@ -6,8 +6,9 @@
// RUN: %clangxx %s -o - -emit-llvm -S -fprofile-instr-generate -target %itanium_abi_triple | FileCheck -check-prefix=PGOGEN %s
// RUN: %clangxx %s -o - -emit-llvm -S -fprofile-instr-generate -target %itanium_abi_triple | FileCheck -check-prefix=PGOGEN-EXC %s
-// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-use=%S/Inputs/cxx-throws.profdata -target %itanium_abi_triple | FileCheck -check-prefix=PGOUSE %s
-// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-use=%S/Inputs/cxx-throws.profdata -target %itanium_abi_triple | FileCheck -check-prefix=PGOUSE-EXC %s
+// RUN: llvm-profdata merge %S/Inputs/cxx-throws.proftext -o %t.profdata
+// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-use=%t.profdata -target %itanium_abi_triple | FileCheck -check-prefix=PGOUSE %s
+// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-use=%t.profdata -target %itanium_abi_triple | FileCheck -check-prefix=PGOUSE-EXC %s
// PGOGEN: @[[THC:__llvm_profile_counters__Z6throwsv]] = global [9 x i64] zeroinitializer
// PGOGEN-EXC: @[[THC:__llvm_profile_counters__Z6throwsv]] = global [9 x i64] zeroinitializer
diff --git a/test/Profile/objc-general.m b/test/Profile/objc-general.m
index 568e5e4182..dc746189a8 100644
--- a/test/Profile/objc-general.m
+++ b/test/Profile/objc-general.m
@@ -1,7 +1,9 @@
// Test instrumentation of general constructs in objective C.
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instr-generate | FileCheck -check-prefix=PGOGEN %s
-// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instr-use=%S/Inputs/objc-general.profdata | FileCheck -check-prefix=PGOUSE %s
+
+// RUN: llvm-profdata merge %S/Inputs/objc-general.proftext -o %t.profdata
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instr-use=%t.profdata | FileCheck -check-prefix=PGOUSE %s
#ifdef HAVE_FOUNDATION
diff --git a/test/Sema/aarch64-neon-ranges.c b/test/Sema/aarch64-neon-ranges.c
index bcc9c50b0a..3a170b8f4c 100644
--- a/test/Sema/aarch64-neon-ranges.c
+++ b/test/Sema/aarch64-neon-ranges.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple aarch64-linux-gnu -target-feature +neon -ffreestanding -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple arm64-linux-gnu -target-feature +neon -ffreestanding -fsyntax-only -verify %s
#include <arm_neon.h>
diff --git a/test/Sema/aarch64-neon-vector-types.c b/test/Sema/aarch64-neon-vector-types.c
index b733e3c276..4cc1e2c292 100644
--- a/test/Sema/aarch64-neon-vector-types.c
+++ b/test/Sema/aarch64-neon-vector-types.c
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 %s -triple aarch64-none-linux-gnu -target-feature +neon -fsyntax-only -verify
// RUN: %clang_cc1 %s -triple aarch64-none-linux-gnu -target-feature +neon -DUSE_LONG -fsyntax-only -verify
+// RUN: %clang_cc1 %s -triple arm64-none-linux-gnu -target-feature +neon -fsyntax-only -verify
+// RUN: %clang_cc1 %s -triple arm64-none-linux-gnu -target-feature +neon -DUSE_LONG -fsyntax-only -verify
typedef float float32_t;
typedef unsigned char poly8_t;
diff --git a/test/Sema/arm64-inline-asm.c b/test/Sema/arm64-inline-asm.c
index 2d936214be..08eb669265 100644
--- a/test/Sema/arm64-inline-asm.c
+++ b/test/Sema/arm64-inline-asm.c
@@ -1,8 +1,9 @@
// RUN: %clang_cc1 -triple arm64-apple-ios7.1 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
void foo() {
asm volatile("USE(%0)" :: "z"(0LL));
asm volatile("USE(%x0)" :: "z"(0LL));
asm volatile("USE(%w0)" :: "z"(0));
- asm volatile("USE(%0)" :: "z"(0)); // expected-warning {{value size does not match register size specified by the constraint and modifier}}
}
diff --git a/test/Sema/arm64-neon-args.c b/test/Sema/arm64-neon-args.c
index 5ee653ddd2..a36df030fb 100644
--- a/test/Sema/arm64-neon-args.c
+++ b/test/Sema/arm64-neon-args.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple arm64-apple-darwin -fsyntax-only -ffreestanding -verify %s
+// RUN: %clang_cc1 -triple arm64-apple-darwin -target-feature +neon -fsyntax-only -ffreestanding -verify %s
#include <arm_neon.h>
diff --git a/test/Sema/attr-aligned.c b/test/Sema/attr-aligned.c
index ad59357658..0a2698ec91 100644
--- a/test/Sema/attr-aligned.c
+++ b/test/Sema/attr-aligned.c
@@ -43,3 +43,14 @@ struct E { int member __attribute__((aligned(2))); } __attribute__((packed));
struct E e;
char e1[__alignof__(e) == 2 ?: -1] = {0};
char e2[__alignof__(e.member) == 2 ?: -1] = {0};
+
+typedef char overaligned_char __attribute__((aligned(16)));
+typedef overaligned_char array_with_overaligned_char[11];
+typedef char array_with_align_attr[11] __attribute__((aligned(16)));
+
+char f0[__alignof__(array_with_overaligned_char) == 16 ? 1 : -1] = { 0 };
+char f1[__alignof__(array_with_align_attr) == 16 ? 1 : -1] = { 0 };
+array_with_overaligned_char F2;
+char f2[__alignof__(F2) == 16 ? 1 : -1] = { 0 };
+array_with_align_attr F3;
+char f3[__alignof__(F3) == 16 ? 1 : -1] = { 0 };
diff --git a/test/Sema/attr-capabilities.c b/test/Sema/attr-capabilities.c
index e6f123f25a..cdbd2f3b2d 100644
--- a/test/Sema/attr-capabilities.c
+++ b/test/Sema/attr-capabilities.c
@@ -50,4 +50,13 @@ void Func23(void) __attribute__((try_acquire_capability(1, GUI))) {}
void Func24(void) __attribute__((try_acquire_shared_capability(1, GUI))) {}
void Func25(void) __attribute__((try_acquire_capability())) {} // expected-error {{'try_acquire_capability' attribute takes at least 1 argument}}
-void Func26(void) __attribute__((try_acquire_shared_capability())) {} // expected-error {{'try_acquire_shared_capability' attribute takes at least 1 argument}} \ No newline at end of file
+void Func26(void) __attribute__((try_acquire_shared_capability())) {} // expected-error {{'try_acquire_shared_capability' attribute takes at least 1 argument}}
+
+// Test that boolean logic works with capability attributes
+void Func27(void) __attribute__((requires_capability(!GUI)));
+void Func28(void) __attribute__((requires_capability(GUI && Worker)));
+void Func29(void) __attribute__((requires_capability(GUI || Worker)));
+void Func30(void) __attribute__((requires_capability((Worker || Worker) && !GUI)));
+
+int AlsoNotACapability;
+void Func31(void) __attribute__((requires_capability(GUI && AlsoNotACapability))); // expected-warning {{'requires_capability' attribute requires arguments whose type is annotated with 'capability' attribute; type here is 'int'}}
diff --git a/test/Sema/bool-compare.c b/test/Sema/bool-compare.c
new file mode 100644
index 0000000000..3f1f286a2a
--- /dev/null
+++ b/test/Sema/bool-compare.c
@@ -0,0 +1,162 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+
+void f(int x, int y, int z) {
+ int a,b;
+
+
+ if ((a > 2) > 1) {} // expected-warning {{comparison of constant 1 with boolean expression is always false}}
+
+ if (a > b) {} // no warning
+ if (a < b) {} // no warning
+ if (a >= b) {} // no warning
+ if (a <= b) {} // no warning
+ if (a == b) {} // no warning
+ if (a != b) {} // no warning
+
+ if (a > 0) {} // no warning
+ if (a > 1) {} // no warning
+ if (a > 2) {} // no warning
+
+ if (a >= 0) {} // no warning
+ if (a >= 1) {} // no warning
+ if (a >= 2) {} // no warning
+ if (a >= -1) {} // no warning
+
+ if (a <= 0) {} // no warning
+ if (a <= 1) {} // no warning
+ if (a <= 2) {} // no warning
+ if (a <= -1) {} // no warning
+
+
+ if (!a > 0) {} // no warning
+ if (!a > 1) {} // expected-warning {{comparison of constant 1 with boolean expression is always false}}
+ if (!a > 2) {} // expected-warning {{comparison of constant 2 with boolean expression is always false}}
+ if (!a > y) {} // no warning
+ if (!a > b) {} // no warning
+ if (!a > -1) {} // expected-warning {{comparison of constant -1 with boolean expression is always true}}
+
+ if (!a < 0) {} // expected-warning {{comparison of constant 0 with boolean expression is always false}}
+ if (!a < 1) {} // no warning
+ if (!a < 2) {} // expected-warning {{comparison of constant 2 with boolean expression is always true}}
+ if (!a < y) {} // no warning
+ if (!a < b) {} // no warning
+ if (!a < -1) {} // expected-warning {{comparison of constant -1 with boolean expression is always false}}
+
+ if (!a >= 0) {} // expected-warning {{comparison of constant 0 with boolean expression is always true}}
+ if (!a >= 1) {} // no warning
+ if (!a >= 2) {} // expected-warning {{comparison of constant 2 with boolean expression is always false}}
+ if (!a >= y) {} // no warning
+ if (!a >= b) {} // no warning
+ if (!a >= -1) {} // expected-warning {{comparison of constant -1 with boolean expression is always true}}
+
+ if (!a <= 0) {} // no warning
+ if (!a <= 1) {} // expected-warning {{comparison of constant 1 with boolean expression is always true}}
+ if (!a <= 2) {} // expected-warning {{comparison of constant 2 with boolean expression is always true}}
+ if (!a <= y) {} // no warning
+ if (!a <= b) {} // no warning
+ if (!a <= -1) {} // expected-warning {{comparison of constant -1 with boolean expression is always false}}
+
+ if ((a||b) > 0) {} // no warning
+ if ((a||b) > 1) {} // expected-warning {{comparison of constant 1 with boolean expression is always false}}
+ if ((a||b) > 4) {} // expected-warning {{comparison of constant 4 with boolean expression is always false}}
+ if ((a||b) > -1) {}// expected-warning {{comparison of constant -1 with boolean expression is always true}}
+
+ if ((a&&b) > 0) {} // no warning
+ if ((a&&b) > 1) {} // expected-warning {{comparison of constant 1 with boolean expression is always false}}
+ if ((a&&b) > 4) {} // expected-warning {{comparison of constant 4 with boolean expression is always false}}
+
+ if ((a<y) > 0) {} // no warning
+ if ((a<y) > 1) {} // expected-warning {{comparison of constant 1 with boolean expression is always false}}
+ if ((a<y) > 4) {} // expected-warning {{comparison of constant 4 with boolean expression is always false}}
+ if ((a<y) > z) {} // no warning
+ if ((a<y) > -1) {} // expected-warning {{comparison of constant -1 with boolean expression is always true}}
+
+ if ((a<y) == 0) {} // no warning
+ if ((a<y) == 1) {} // no warning
+ if ((a<y) == 2) {} // expected-warning {{comparison of constant 2 with boolean expression is always false}}
+ if ((a<y) == z) {} // no warning
+ if ((a<y) == -1) {}// expected-warning {{comparison of constant -1 with boolean expression is always false}}
+
+ if ((a<y) != 0) {} // no warning
+ if ((a<y) != 1) {} // no warning
+ if ((a<y) != 2) {} // expected-warning {{comparison of constant 2 with boolean expression is always true}}
+ if ((a<y) != z) {} // no warning
+ if ((a<y) != -1) {}// expected-warning {{comparison of constant -1 with boolean expression is always true}}
+
+ if ((a<y) == z) {} // no warning
+ if (a>y<z) {} // no warning
+ if ((a<y) > z) {} // no warning
+ if((a<y)>(z<y)) {} // no warning
+ if((a<y)==(z<y)){} // no warning
+ if((a<y)!=(z<y)){} // no warning
+ if((z==x)<(y==z)){}// no warning
+ if((a<y)!=((z==x)<(y==z))){} //no warning
+
+
+ if (0 > !a) {} // expected-warning {{comparison of constant 0 with boolean expression is always false}}
+ if (1 > !a) {} // no warning
+ if (2 > !a) {} // expected-warning {{comparison of constant 2 with boolean expression is always true}}
+ if (y > !a) {} // no warning
+ if (-1 > !a) {} // expected-warning {{comparison of constant -1 with boolean expression is always false}}
+
+ if (0 < !a) {} // no warning
+ if (1 < !a) {} // expected-warning {{comparison of constant 1 with boolean expression is always false}}
+ if (2 < !a) {} // expected-warning {{comparison of constant 2 with boolean expression is always false}}
+ if (y < !a) {} // no warning
+ if (-1 < !a) {} // expected-warning {{comparison of constant -1 with boolean expression is always true}}
+
+ if (0 >= !a) {} // no warning
+ if (1 >= !a) {} // expected-warning {{comparison of constant 1 with boolean expression is always true}}
+ if (2 >= !a) {} // expected-warning {{comparison of constant 2 with boolean expression is always true}}
+ if (y >= !a) {} // no warning
+ if (-1 >= !a) {} // expected-warning {{comparison of constant -1 with boolean expression is always false}}
+
+ if (0 <= !a) {} // expected-warning {{comparison of constant 0 with boolean expression is always true}}
+ if (1 <= !a) {} // no warning
+ if (2 <= !a) {} // expected-warning {{comparison of constant 2 with boolean expression is always false}}
+ if (y <= !a) {} // no warning
+ if (-1 <= !a) {} // expected-warning {{comparison of constant -1 with boolean expression is always true}}
+
+ if (0 > (a||b)) {} // expected-warning {{comparison of constant 0 with boolean expression is always false}}
+ if (1 > (a||b)) {} // no warning
+ if (4 > (a||b)) {} // expected-warning {{comparison of constant 4 with boolean expression is always true}}
+
+ if (0 > (a&&b)) {} // expected-warning {{comparison of constant 0 with boolean expression is always false}}
+ if (1 > (a&&b)) {} // no warning
+ if (4 > (a&&b)) {} // expected-warning {{comparison of constant 4 with boolean expression is always true}}
+
+ if (0 > (a<y)) {} // expected-warning {{comparison of constant 0 with boolean expression is always false}}
+ if (1 > (a<y)) {} // no warning
+ if (4 > (a<y)) {} // expected-warning {{comparison of constant 4 with boolean expression is always true}}
+ if (z > (a<y)) {} // no warning
+ if (-1 > (a<y)) {} // expected-warning {{comparison of constant -1 with boolean expression is always false}}
+
+ if (0 == (a<y)) {} // no warning
+ if (1 == (a<y)) {} // no warning
+ if (2 == (a<y)) {} // expected-warning {{comparison of constant 2 with boolean expression is always false}}
+ if (z == (a<y)) {} // no warning
+ if (-1 == (a<y)){} // expected-warning {{comparison of constant -1 with boolean expression is always false}}
+
+ if (0 !=(a<y)) {} // no warning
+ if (1 !=(a<y)) {} // no warning
+ if (2 !=(a<y)) {} // expected-warning {{comparison of constant 2 with boolean expression is always true}}
+ if (z !=(a<y)) {} // no warning
+ if (-1 !=(a<y)) {} // expected-warning {{comparison of constant -1 with boolean expression is always true}}
+
+ if (z ==(a<y)) {} // no warning
+ if (z<a>y) {} // no warning
+ if (z > (a<y)) {} // no warning
+ if((z<y)>(a<y)) {} // no warning
+ if((z<y)==(a<y)){} // no warning
+ if((z<y)!=(a<y)){} // no warning
+ if((y==z)<(z==x)){} // no warning
+ if(((z==x)<(y==z))!=(a<y)){} // no warning
+
+ if(((z==x)<(-1==z))!=(a<y)){} // no warning
+ if(((z==x)<(z==-1))!=(a<y)){} // no warning
+ if(((z==x)<-1)!=(a<y)){} // expected-warning {{comparison of constant -1 with boolean expression is always false}}
+ if(((z==x)< 2)!=(a<y)){} // expected-warning {{comparison of constant 2 with boolean expression is always true}}
+ if(((z==x)<(z>2))!=(a<y)){} // no warning
+
+}
diff --git a/test/Sema/builtin-clear_cache.c b/test/Sema/builtin-clear_cache.c
index e21aad79d1..3193f3124d 100644
--- a/test/Sema/builtin-clear_cache.c
+++ b/test/Sema/builtin-clear_cache.c
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -triple armv7-none-linux-gnu -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -fsyntax-only -verify %s
// expected-no-diagnostics
void __clear_cache(void *a, void *b) {}
diff --git a/test/Sema/builtins-aarch64.c b/test/Sema/builtins-aarch64.c
index b0557532fa..b4d8aaef63 100644
--- a/test/Sema/builtins-aarch64.c
+++ b/test/Sema/builtins-aarch64.c
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -DTEST1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple arm64-none-linux-gnu -DTEST1 -fsyntax-only -verify %s
#ifdef TEST1
void __clear_cache(void *start, void *end);
diff --git a/test/Sema/builtins-gnu-mode.c b/test/Sema/builtins-gnu-mode.c
index 718803eabe..d93b6fdef0 100644
--- a/test/Sema/builtins-gnu-mode.c
+++ b/test/Sema/builtins-gnu-mode.c
@@ -13,14 +13,6 @@ int bzero;
int strcasecmp;
int strncasecmp;
int _exit;
-int vfork;
-int _setjmp;
-int __sigsetjmp;
-int sigsetjmp;
-int setjmp_syscall;
-int savectx;
-int qsetjmp;
-int getcontext;
int _longjmp;
int siglongjmp;
int strlcpy;
diff --git a/test/Sema/conversion.c b/test/Sema/conversion.c
index a591ac0eef..89c34c6a22 100644
--- a/test/Sema/conversion.c
+++ b/test/Sema/conversion.c
@@ -417,3 +417,15 @@ void test26(int si, long sl) {
si = si / sl;
si = sl / si; // expected-warning {{implicit conversion loses integer precision: 'long' to 'int'}}
}
+
+// rdar://16502418
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef __attribute__ ((ext_vector_type(16),__aligned__(32))) uint16_t ushort16;
+typedef __attribute__ ((ext_vector_type( 8),__aligned__( 32))) uint32_t uint8;
+
+void test27(ushort16 constants) {
+ uint8 pairedConstants = (uint8) constants;
+ ushort16 crCbScale = pairedConstants.s4; // expected-warning {{implicit conversion loses integer precision: 'uint32_t' (aka 'unsigned int') to 'ushort16'}}
+ ushort16 brBias = pairedConstants.s6; // expected-warning {{implicit conversion loses integer precision: 'uint32_t' (aka 'unsigned int') to 'ushort16'}}
+}
diff --git a/test/Sema/ext_vector_casts.c b/test/Sema/ext_vector_casts.c
index d60bc3c65c..949d67311b 100644
--- a/test/Sema/ext_vector_casts.c
+++ b/test/Sema/ext_vector_casts.c
@@ -32,30 +32,30 @@ static void test() {
ivec4 = (int4)5;
ivec4 = (int4)vec4_3;
- i = (int)ivec4; // expected-error {{invalid conversion between vector type 'int4' and integer type 'int' of different size}}
- i = ivec4; // expected-error {{assigning to 'int' from incompatible type 'int4'}}
+ i = (int)ivec4; // expected-error {{invalid conversion between vector type 'int4' (vector of 4 'int' values) and integer type 'int' of different size}}
+ i = ivec4; // expected-error {{assigning to 'int' from incompatible type 'int4' (vector of 4 'int' values)}}
- ivec4 = (int4)ptr; // expected-error {{invalid conversion between vector type 'int4' and scalar type 'int *'}}
+ ivec4 = (int4)ptr; // expected-error {{invalid conversion between vector type 'int4' (vector of 4 'int' values) and scalar type 'int *'}}
- vec4 = (float4)vec2; // expected-error {{invalid conversion between ext-vector type 'float4' and 'float2'}}
+ vec4 = (float4)vec2; // expected-error {{invalid conversion between ext-vector type 'float4' (vector of 4 'float' values) and 'float2' (vector of 2 'float' values)}}
ish8 += 5;
ivec4 *= 5;
vec4 /= 5.2f;
- vec4 %= 4; // expected-error {{invalid operands to binary expression ('float4' and 'int')}}
+ vec4 %= 4; // expected-error {{invalid operands to binary expression ('float4' (vector of 4 'float' values) and 'int')}}
ivec4 %= 4;
- ivec4 += vec4; // expected-error {{can't convert between vector values of different size ('int4' and 'float4')}}
+ ivec4 += vec4; // expected-error {{can't convert between vector values of different size ('int4' (vector of 4 'int' values) and 'float4' (vector of 4 'float' values))}}
ivec4 += (int4)vec4;
ivec4 -= ivec4;
ivec4 |= ivec4;
- ivec4 += ptr; // expected-error {{can't convert between vector and non-scalar values ('int4' and 'int *')}}
+ ivec4 += ptr; // expected-error {{can't convert between vector and non-scalar values ('int4' (vector of 4 'int' values) and 'int *')}}
}
-typedef __attribute__(( ext_vector_type(2) )) float2 vecfloat2; // expected-error{{invalid vector element type 'float2'}}
+typedef __attribute__(( ext_vector_type(2) )) float2 vecfloat2; // expected-error{{invalid vector element type 'float2' (vector of 2 'float' values)}}
void inc(float2 f2) {
- f2++; // expected-error{{cannot increment value of type 'float2'}}
- __real f2; // expected-error{{invalid type 'float2' to __real operator}}
+ f2++; // expected-error{{cannot increment value of type 'float2' (vector of 2 'float' values)}}
+ __real f2; // expected-error{{invalid type 'float2' (vector of 2 'float' values) to __real operator}}
}
typedef enum
@@ -86,7 +86,7 @@ typedef float C3DVector3 __attribute__((ext_vector_type(3)));
extern float32x4_t vabsq_f32(float32x4_t __a);
C3DVector3 Func(const C3DVector3 a) {
- return (C3DVector3)vabsq_f32((float32x4_t)a); // expected-error {{invalid conversion between ext-vector type 'float32x4_t' and 'C3DVector3'}}
+ return (C3DVector3)vabsq_f32((float32x4_t)a); // expected-error {{invalid conversion between ext-vector type 'float32x4_t' (vector of 4 'float' values) and 'C3DVector3' (vector of 3 'float' values)}}
}
// rdar://16350802
@@ -99,7 +99,7 @@ static void splats(int i, long l, __uint128_t t, float f, double d) {
float2 vf = f;
double2 vd = d;
- vs = 65536 + vs; // expected-warning {{implicit conversion from 'int' to 'short8' changes value from 65536 to 0}}
+ vs = 65536 + vs; // expected-warning {{implicit conversion from 'int' to 'short8' (vector of 8 'short' values) changes value from 65536 to 0}}
vs = vs + i; // expected-warning {{implicit conversion loses integer precision}}
vs = vs + 1;
vs = vs + 1.f; // expected-error {{can't convert between vector values of different size}}
diff --git a/test/Sema/inline-asm-validate.c b/test/Sema/inline-asm-validate.c
index cfe4972d5a..c32dedb65e 100644
--- a/test/Sema/inline-asm-validate.c
+++ b/test/Sema/inline-asm-validate.c
@@ -1,8 +1,9 @@
// RUN: %clang_cc1 -triple arm64-apple-macosx10.8.0 -fsyntax-only -verify %s
+// expected-no-diagnostics
unsigned t, r, *p;
int foo (void) {
- __asm__ __volatile__( "stxr %w[_t], %[_r], [%[_p]]" : [_t] "=&r" (t) : [_p] "p" (p), [_r] "r" (r) : "memory"); // expected-warning {{value size does not match register size specified by the constraint and modifier}}
+ __asm__ __volatile__( "stxr %w[_t], %[_r], [%[_p]]" : [_t] "=&r" (t) : [_p] "p" (p), [_r] "r" (r) : "memory");
return 1;
}
diff --git a/test/Sema/ms_bitfield_layout.c b/test/Sema/ms_bitfield_layout.c
index f2010c1622..8444f469d5 100644
--- a/test/Sema/ms_bitfield_layout.c
+++ b/test/Sema/ms_bitfield_layout.c
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts %s 2>/dev/null \
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple i686-pc-win32 -fms-extensions -fdump-record-layouts %s 2>/dev/null \
// RUN: | FileCheck %s
-// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fdump-record-layouts %s 2>/dev/null \
+// RUN: %clang_cc1 -fno-rtti -emit-llvm-only -triple x86_64-pc-win32 -fms-extensions -fdump-record-layouts %s 2>/dev/null \
// RUN: | FileCheck %s
typedef struct A {
@@ -111,6 +111,16 @@ typedef struct H {
// CHECK: Alignment:16
// CHECK: FieldOffsets: [0, 16, 16, 16]>
+typedef struct I {
+ short : 8;
+ __declspec(align(16)) short : 8;
+} I;
+
+// CHECK: Type: struct I
+// CHECK: Size:16
+// CHECK: Alignment:16
+// CHECK: FieldOffsets: [0, 8]
+
#pragma pack(push, 1)
typedef struct A1 {
@@ -221,6 +231,16 @@ typedef struct H1 {
// CHECK: Alignment:8
// CHECK: FieldOffsets: [0, 32, 32, 32]>
+typedef struct I1 {
+ short : 8;
+ __declspec(align(16)) short : 8;
+} I1;
+
+// CHECK: Type: struct I1
+// CHECK: Size:16
+// CHECK: Alignment:8
+// CHECK: FieldOffsets: [0, 8]
+
#pragma pack(pop)
int x[
@@ -232,6 +252,7 @@ sizeof(E ) +
sizeof(F ) +
sizeof(G ) +
sizeof(H ) +
+sizeof(I ) +
sizeof(A1) +
sizeof(B1) +
sizeof(C1) +
@@ -240,4 +261,5 @@ sizeof(E1) +
sizeof(F1) +
sizeof(G1) +
sizeof(H1) +
+sizeof(I1) +
0];
diff --git a/test/Sema/pragma-section.c b/test/Sema/pragma-section.c
new file mode 100644
index 0000000000..02f3e77112
--- /dev/null
+++ b/test/Sema/pragma-section.c
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s -triple x86_64-pc-win32
+
+#pragma const_seg(".my_const") // expected-note 2 {{#pragma entered here}}
+extern const int a;
+const int a = 1; // expected-note 2 {{declared here}}
+#pragma data_seg(".my_const") // expected-note {{#pragma entered here}}
+int b = 1; // expected-error {{'b' causes a section type conflict with 'a'}}
+#pragma data_seg()
+int c = 1;
+__declspec(allocate(".my_const")) int d = 1; // expected-error {{'d' causes a section type conflict with 'a'}}
+
+#pragma section(".my_seg", execute) // expected-note 2 {{#pragma entered her}}
+__declspec(allocate(".my_seg")) int int_my_seg;
+#pragma code_seg(".my_seg")
+void fn_my_seg(void){}
+
+__declspec(allocate(".bad_seg")) int int_bad_seg = 1; // expected-note {{declared here}}
+#pragma code_seg(".bad_seg") // expected-note {{#pragma entered here}}
+void fn_bad_seg(void){} // expected-error {{'fn_bad_seg' causes a section type conflict with 'int_bad_seg'}}
+
+#pragma bss_seg // expected-warning {{missing '(' after '#pragma bss_seg' - ignoring}}
+#pragma bss_seg(L".my_seg") // expected-warning {{expected push, pop or a string literal for the section name in '#pragma bss_seg' - ignored}}
+#pragma bss_seg(1) // expected-warning {{expected push, pop or a string literal for the section name in '#pragma bss_seg' - ignored}}
+#pragma bss_seg(push)
+#pragma bss_seg(push, ".my_seg")
+#pragma bss_seg(push, 1) // expected-warning {{expected a stack label or a string literal for the section name in '#pragma bss_seg'}}
+#pragma bss_seg ".my_seg" // expected-warning {{missing '(' after '#pragma bss_seg' - ignoring}}
+#pragma bss_seg(push, my_label, 1) // expected-warning {{expected a string literal for the section name in '#pragma bss_seg' - ignored}}
+#pragma bss_seg(".my_seg", 1) // expected-warning {{missing ')' after '#pragma bss_seg' - ignoring}}
+#pragma bss_seg(".my_seg" // expected-warning {{missing ')' after '#pragma bss_seg' - ignoring}}
+
+#pragma section // expected-warning {{missing '(' after '#pragma section' - ignoring}}
+#pragma section( // expected-warning {{expected a string literal for the section name in '#pragma section' - ignored}}
+#pragma section(L".my_seg") // expected-warning {{expected a string literal for the section name in '#pragma section' - ignored}}
+#pragma section(".my_seg" // expected-warning {{missing ')' after '#pragma section' - ignoring}}
+#pragma section(".my_seg" 1 // expected-warning {{missing ')' after '#pragma section' - ignoring}}
+#pragma section(".my_seg", // expected-warning {{expected action or ')' in '#pragma section' - ignored}}
+#pragma section(".my_seg", read) // expected-error {{this causes a section type conflict with a prior #pragma section}}
+#pragma section(".my_seg", bogus) // expected-warning {{unknown action 'bogus' for '#pragma section' - ignored}}
+#pragma section(".my_seg", nopage) // expected-warning {{known but unsupported action 'nopage' for '#pragma section' - ignored}}
+#pragma section(".my_seg", read, write) // expected-error {{this causes a section type conflict with a prior #pragma section}}
+#pragma section(".my_seg", read, write, 1) // expected-warning {{expected action or ')' in '#pragma section' - ignored}}
diff --git a/test/Sema/return-noreturn.c b/test/Sema/return-noreturn.c
index 6d521eb017..2aa0b91115 100644
--- a/test/Sema/return-noreturn.c
+++ b/test/Sema/return-noreturn.c
@@ -2,7 +2,7 @@
int j;
void test1() { // expected-warning {{function 'test1' could be declared with attribute 'noreturn'}}
- ^ (void) { while (1) { } }(); // expected-warning {{block could be declared with attribute 'noreturn'}}
+ ^ (void) { while (1) { } }();
^ (void) { if (j) while (1) { } }();
while (1) { }
}
@@ -40,3 +40,13 @@ test4() {
_Noreturn void test5() {
test2_positive();
}
+
+// rdar://16274746
+void test6()
+{
+ (void)^{
+ for(;;)
+ ;
+ };
+}
+
diff --git a/test/Sema/transparent-union.c b/test/Sema/transparent-union.c
index eff7df67b9..8ef70bb1c7 100644
--- a/test/Sema/transparent-union.c
+++ b/test/Sema/transparent-union.c
@@ -67,7 +67,7 @@ typedef union { } TU4 __attribute__((transparent_union)); // expected-warning{{f
typedef int int4 __attribute__((ext_vector_type(4)));
typedef union {
- int4 vec; // expected-warning{{first field of a transparent union cannot have vector type 'int4'; transparent_union attribute ignored}}
+ int4 vec; // expected-warning{{first field of a transparent union cannot have vector type 'int4' (vector of 4 'int' values); transparent_union attribute ignored}}
} TU5 __attribute__((transparent_union));
union pr15134 {
diff --git a/test/Sema/typedef-retain.c b/test/Sema/typedef-retain.c
index a7173b7877..d216466360 100644
--- a/test/Sema/typedef-retain.c
+++ b/test/Sema/typedef-retain.c
@@ -5,11 +5,11 @@ typedef int int4 __attribute__((vector_size(16)));
typedef int4* int4p;
void test1(float4 a, int4 *result, int i) {
- result[i] = a; // expected-error {{assigning to 'int4' from incompatible type 'float4'}}
+ result[i] = a; // expected-error {{assigning to 'int4' (vector of 4 'int' values) from incompatible type 'float4' (vector of 4 'float' values)}}
}
void test2(float4 a, int4p result, int i) {
- result[i] = a; // expected-error {{assigning to 'int4' from incompatible type 'float4'}}
+ result[i] = a; // expected-error {{assigning to 'int4' (vector of 4 'int' values) from incompatible type 'float4' (vector of 4 'float' values)}}
}
// PR2039
diff --git a/test/Sema/types.c b/test/Sema/types.c
index 339788eb9d..778a5fe9f7 100644
--- a/test/Sema/types.c
+++ b/test/Sema/types.c
@@ -73,3 +73,11 @@ typedef int __attribute__ ((ext_vector_type(8192))) x2; // expected-error {{vect
enum { e_2 } x3 __attribute__((vector_size(64))); // expected-error {{invalid vector element type}}
int x4 __attribute__((ext_vector_type(64))); // expected-error {{'ext_vector_type' attribute only applies to types}}
+
+// rdar://16492792
+typedef __attribute__ ((ext_vector_type(32),__aligned__(32))) unsigned char uchar32;
+
+void convert() {
+ uchar32 r = 0;
+ r.s[ 1234 ] = 1; // expected-error {{illegal vector component name 's'}}
+}
diff --git a/test/Sema/vector-assign.c b/test/Sema/vector-assign.c
index f01eb456a1..ad3406e304 100644
--- a/test/Sema/vector-assign.c
+++ b/test/Sema/vector-assign.c
@@ -12,30 +12,30 @@ void test1() {
v2f v4;
v4ss v5;
- v1 = v2; // expected-warning {{incompatible vector types assigning to 'v2s' from 'v2u'}}
- v1 = v3; // expected-error {{assigning to 'v2s' from incompatible type 'v1s'}}
- v1 = v4; // expected-warning {{incompatible vector types assigning to 'v2s' from 'v2f'}}
- v1 = v5; // expected-warning {{incompatible vector types assigning to 'v2s' from 'v4ss'}}
+ v1 = v2; // expected-warning {{incompatible vector types assigning to 'v2s' (vector of 2 'int' values) from 'v2u' (vector of 2 'unsigned int' values)}}
+ v1 = v3; // expected-error {{assigning to 'v2s' (vector of 2 'int' values) from incompatible type 'v1s' (vector of 1 'int' value)}}
+ v1 = v4; // expected-warning {{incompatible vector types assigning to 'v2s' (vector of 2 'int' values) from 'v2f' (vector of 2 'float' values)}}
+ v1 = v5; // expected-warning {{incompatible vector types assigning to 'v2s' (vector of 2 'int' values) from 'v4ss' (vector of 4 'short' values)}}
- v2 = v1; // expected-warning {{incompatible vector types assigning to 'v2u' from 'v2s'}}
- v2 = v3; // expected-error {{assigning to 'v2u' from incompatible type 'v1s'}}
- v2 = v4; // expected-warning {{incompatible vector types assigning to 'v2u' from 'v2f'}}
- v2 = v5; // expected-warning {{incompatible vector types assigning to 'v2u' from 'v4ss'}}
+ v2 = v1; // expected-warning {{incompatible vector types assigning to 'v2u' (vector of 2 'unsigned int' values) from 'v2s' (vector of 2 'int' values)}}
+ v2 = v3; // expected-error {{assigning to 'v2u' (vector of 2 'unsigned int' values) from incompatible type 'v1s' (vector of 1 'int' value)}}
+ v2 = v4; // expected-warning {{incompatible vector types assigning to 'v2u' (vector of 2 'unsigned int' values) from 'v2f' (vector of 2 'float' values)}}
+ v2 = v5; // expected-warning {{incompatible vector types assigning to 'v2u' (vector of 2 'unsigned int' values) from 'v4ss' (vector of 4 'short' values)}}
- v3 = v1; // expected-error {{assigning to 'v1s' from incompatible type 'v2s'}}
- v3 = v2; // expected-error {{assigning to 'v1s' from incompatible type 'v2u'}}
- v3 = v4; // expected-error {{assigning to 'v1s' from incompatible type 'v2f'}}
- v3 = v5; // expected-error {{assigning to 'v1s' from incompatible type 'v4ss'}}
+ v3 = v1; // expected-error {{assigning to 'v1s' (vector of 1 'int' value) from incompatible type 'v2s' (vector of 2 'int' values)}}
+ v3 = v2; // expected-error {{assigning to 'v1s' (vector of 1 'int' value) from incompatible type 'v2u' (vector of 2 'unsigned int' values)}}
+ v3 = v4; // expected-error {{assigning to 'v1s' (vector of 1 'int' value) from incompatible type 'v2f' (vector of 2 'float' values)}}
+ v3 = v5; // expected-error {{assigning to 'v1s' (vector of 1 'int' value) from incompatible type 'v4ss'}}
- v4 = v1; // expected-warning {{incompatible vector types assigning to 'v2f' from 'v2s'}}
- v4 = v2; // expected-warning {{incompatible vector types assigning to 'v2f' from 'v2u'}}
- v4 = v3; // expected-error {{assigning to 'v2f' from incompatible type 'v1s'}}
- v4 = v5; // expected-warning {{incompatible vector types assigning to 'v2f' from 'v4ss'}}
+ v4 = v1; // expected-warning {{incompatible vector types assigning to 'v2f' (vector of 2 'float' values) from 'v2s' (vector of 2 'int' values)}}
+ v4 = v2; // expected-warning {{incompatible vector types assigning to 'v2f' (vector of 2 'float' values) from 'v2u' (vector of 2 'unsigned int' values)}}
+ v4 = v3; // expected-error {{assigning to 'v2f' (vector of 2 'float' values) from incompatible type 'v1s' (vector of 1 'int' value)}}
+ v4 = v5; // expected-warning {{incompatible vector types assigning to 'v2f' (vector of 2 'float' values) from 'v4ss' (vector of 4 'short' values)}}
- v5 = v1; // expected-warning {{incompatible vector types assigning to 'v4ss' from 'v2s'}}
- v5 = v2; // expected-warning {{incompatible vector types assigning to 'v4ss' from 'v2u'}}
- v5 = v3; // expected-error {{assigning to 'v4ss' from incompatible type 'v1s'}}
- v5 = v4; // expected-warning {{incompatible vector types assigning to 'v4ss' from 'v2f'}}
+ v5 = v1; // expected-warning {{incompatible vector types assigning to 'v4ss' (vector of 4 'short' values) from 'v2s' (vector of 2 'int' values)}}
+ v5 = v2; // expected-warning {{incompatible vector types assigning to 'v4ss' (vector of 4 'short' values) from 'v2u' (vector of 2 'unsigned int' values)}}
+ v5 = v3; // expected-error {{assigning to 'v4ss' (vector of 4 'short' values) from incompatible type 'v1s' (vector of 1 'int' value)}}
+ v5 = v4; // expected-warning {{incompatible vector types assigning to 'v4ss' (vector of 4 'short' values) from 'v2f'}}
}
// PR2263
diff --git a/test/Sema/vector-cast.c b/test/Sema/vector-cast.c
index bfc731e7b0..0415c13990 100644
--- a/test/Sema/vector-cast.c
+++ b/test/Sema/vector-cast.c
@@ -11,29 +11,29 @@ void f()
t3 v3;
v2 = (t2)v1; // expected-error {{invalid conversion between vector type \
-'t2' and 't1' of different size}}
+'t2' (vector of 16 'char' values) and 't1' (vector of 1 'long long' value) of different size}}
v1 = (t1)v2; // expected-error {{invalid conversion between vector type \
-'t1' and 't2' of different size}}
+'t1' (vector of 1 'long long' value) and 't2' (vector of 16 'char' values) of different size}}
v3 = (t3)v2;
v1 = (t1)(char *)10; // expected-error {{invalid conversion between vector \
-type 't1' and scalar type 'char *'}}
+type 't1' (vector of 1 'long long' value) and scalar type 'char *'}}
v1 = (t1)(long long)10;
v1 = (t1)(short)10; // expected-error {{invalid conversion between vector \
-type 't1' and integer type 'short' of different size}}
+type 't1' (vector of 1 'long long' value) and integer type 'short' of different size}}
long long r1 = (long long)v1;
short r2 = (short)v1; // expected-error {{invalid conversion between vector \
-type 't1' and integer type 'short' of different size}}
+type 't1' (vector of 1 'long long' value) and integer type 'short' of different size}}
char *r3 = (char *)v1; // expected-error {{invalid conversion between vector\
- type 't1' and scalar type 'char *'}}
+ type 't1' (vector of 1 'long long' value) and scalar type 'char *'}}
}
void f2(t2 X); // expected-note{{passing argument to parameter 'X' here}}
void f3(t3 Y) {
- f2(Y); // expected-warning {{incompatible vector types passing 't3' to parameter of type 't2'}}
+ f2(Y); // expected-warning {{incompatible vector types passing 't3' (vector of 4 'float' values) to parameter of type 't2' (vector of 16 'char' values)}}
}
typedef float float2 __attribute__ ((vector_size (8)));
@@ -51,6 +51,6 @@ typedef short short_sizeof_pointer __attribute__((vector_size(sizeof(void*))));
void f5() {
short_sizeof_pointer v;
void *ptr;
- v = ptr; // expected-error {{assigning to 'short_sizeof_pointer' from incompatible type 'void *'}}
+ v = ptr; // expected-error-re {{assigning to 'short_sizeof_pointer' (vector of {{[0-9]+}} 'short' values) from incompatible type 'void *'}}
ptr = v; // expected-error {{assigning to 'void *' from incompatible type 'short_sizeof_pointer'}}
}
diff --git a/test/Sema/vector-init.c b/test/Sema/vector-init.c
index 5be040ae6c..9f27bb882e 100644
--- a/test/Sema/vector-init.c
+++ b/test/Sema/vector-init.c
@@ -40,5 +40,5 @@ typedef short __attribute__((vector_size(8))) short4;
void test3() {
extern short8 test3_helper(void);
longlong2 arr1[2] = { test3_helper(), test3_helper() };
- short4 arr2[2] = { test3_helper(), test3_helper() }; // expected-error 2 {{initializing 'short4' with an expression of incompatible type 'short8'}}
+ short4 arr2[2] = { test3_helper(), test3_helper() }; // expected-error 2 {{initializing 'short4' (vector of 4 'short' values) with an expression of incompatible type 'short8' (vector of 8 'short' values)}}
}
diff --git a/test/Sema/vector-ops.c b/test/Sema/vector-ops.c
index 652a076c78..f2953417f5 100644
--- a/test/Sema/vector-ops.c
+++ b/test/Sema/vector-ops.c
@@ -10,14 +10,14 @@ void test1(v2u v2ua, v2s v2sa, v2f v2fa) {
// Unary operators
(void)(~v2ua);
- (void)(~v2fa); // expected-error{{invalid argument type 'v2f' to unary}}
+ (void)(~v2fa); // expected-error{{invalid argument type 'v2f' (vector of 2 'float' values) to unary}}
// Comparison operators
- v2ua = (v2ua==v2sa); // expected-warning{{incompatible vector types assigning to 'v2u' from 'int __attribute__((ext_vector_type(2)))'}}
+ v2ua = (v2ua==v2sa); // expected-warning{{incompatible vector types assigning to 'v2u' (vector of 2 'unsigned int' values) from 'int __attribute__((ext_vector_type(2)))' (vector of 2 'int' values)}}
v2sa = (v2ua==v2sa);
// Arrays
- int array1[v2ua]; // expected-error{{size of array has non-integer type 'v2u'}}
+ int array1[v2ua]; // expected-error{{size of array has non-integer type 'v2u' (vector of 2 'unsigned int' values)}}
int array2[17];
// FIXME: error message below needs type!
(void)(array2[v2ua]); // expected-error{{array subscript is not an integer}}
diff --git a/test/Sema/warn-documentation.cpp b/test/Sema/warn-documentation.cpp
index ed25d949f5..4375cfcf56 100644
--- a/test/Sema/warn-documentation.cpp
+++ b/test/Sema/warn-documentation.cpp
@@ -4,35 +4,43 @@
// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng %s | FileCheck %s -check-prefix=WRONG
// WRONG-NOT: CommentXMLInvalid
+// expected-warning@+2 {{HTML tag 'a' requires an end tag}}
// expected-warning@+1 {{expected quoted string after equals sign}}
/// <a href=>
int test_html1(int);
+// expected-warning@+2 {{HTML tag 'a' requires an end tag}}
// expected-warning@+1 {{expected quoted string after equals sign}}
/// <a href==>
int test_html2(int);
+// expected-warning@+3 {{HTML tag 'a' requires an end tag}}
// expected-warning@+2 {{expected quoted string after equals sign}}
// expected-warning@+1 {{HTML start tag prematurely ended, expected attribute name or '>'}}
/// <a href= blah
int test_html3(int);
+// expected-warning@+2 {{HTML tag 'a' requires an end tag}}
// expected-warning@+1 {{HTML start tag prematurely ended, expected attribute name or '>'}}
/// <a =>
int test_html4(int);
+// expected-warning@+2 {{HTML tag 'a' requires an end tag}}
// expected-warning@+1 {{HTML start tag prematurely ended, expected attribute name or '>'}}
/// <a "aaa">
int test_html5(int);
+// expected-warning@+2 {{HTML tag 'a' requires an end tag}}
// expected-warning@+1 {{HTML start tag prematurely ended, expected attribute name or '>'}}
/// <a a="b" =>
int test_html6(int);
+// expected-warning@+2 {{HTML tag 'a' requires an end tag}}
// expected-warning@+1 {{HTML start tag prematurely ended, expected attribute name or '>'}}
/// <a a="b" "aaa">
int test_html7(int);
+// expected-warning@+2 {{HTML tag 'a' requires an end tag}}
// expected-warning@+1 {{HTML start tag prematurely ended, expected attribute name or '>'}}
/// <a a="b" =
int test_html8(int);
@@ -67,6 +75,8 @@ int test_html_nesting3(int);
/// Bbb</p>
int test_html_nesting4(int);
+// expected-warning@+3 {{HTML tag 'b' requires an end tag}}
+// expected-warning@+2 {{HTML tag 'i' requires an end tag}}
// expected-warning@+1 {{HTML end tag does not match any start tag}}
/// <b><i>Meow</a>
int test_html_nesting5(int);
@@ -81,6 +91,9 @@ int test_html_nesting6(int);
/// <b><i>Meow</b></i>
int test_html_nesting7(int);
+// expected-warning@+1 {{HTML tag 'b' requires an end tag}}
+/// <b>Meow
+int test_html_nesting8(int);
// expected-warning@+1 {{empty paragraph passed to '\brief' command}}
/// \brief\returns Aaa
diff --git a/test/Sema/warn-overlap.c b/test/Sema/warn-overlap.c
new file mode 100644
index 0000000000..44d6ad5efa
--- /dev/null
+++ b/test/Sema/warn-overlap.c
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wtautological-overlap-compare %s
+
+#define mydefine 2
+
+void f(int x) {
+ int y = 0;
+
+ // > || <
+ if (x > 2 || x < 1) { }
+ if (x > 2 || x < 2) { }
+ if (x != 2 || x != 3) { } // expected-warning {{overlapping comparisons always evaluate to true}}
+ if (x > 2 || x < 3) { } // expected-warning {{overlapping comparisons always evaluate to true}}
+ if (x > 0 || x < 0) { }
+
+ if (x > 2 || x <= 1) { }
+ if (x > 2 || x <= 2) { } // expected-warning {{overlapping comparisons always evaluate to true}}
+ if (x > 2 || x <= 3) { } // expected-warning {{overlapping comparisons always evaluate to true}}
+
+ if (x >= 2 || x < 1) { }
+ if (x >= 2 || x < 2) { } // expected-warning {{overlapping comparisons always evaluate to true}}
+ if (x >= 2 || x < 3) { } // expected-warning {{overlapping comparisons always evaluate to true}}
+
+ if (x >= 2 || x <= 1) { } // expected-warning {{overlapping comparisons always evaluate to true}}
+ if (x >= 2 || x <= 2) { } // expected-warning {{overlapping comparisons always evaluate to true}}
+ if (x >= 2 || x <= 3) { } // expected-warning {{overlapping comparisons always evaluate to true}}
+ if (x >= 0 || x <= 0) { } // expected-warning {{overlapping comparisons always evaluate to true}}
+
+ // > && <
+ if (x > 2 && x < 1) { } // expected-warning {{overlapping comparisons always evaluate to false}}
+ if (x > 2 && x < 2) { } // expected-warning {{overlapping comparisons always evaluate to false}}
+ if (x > 2 && x < 3) { } // expected-warning {{overlapping comparisons always evaluate to false}}
+ if (x > 0 && x < 1) { } // expected-warning {{overlapping comparisons always evaluate to false}}
+
+ if (x > 2 && x <= 1) { } // expected-warning {{overlapping comparisons always evaluate to false}}
+ if (x > 2 && x <= 2) { } // expected-warning {{overlapping comparisons always evaluate to false}}
+ if (x > 2 && x <= 3) { }
+
+ if (x >= 2 && x < 1) { } // expected-warning {{overlapping comparisons always evaluate to false}}
+ if (x >= 2 && x < 2) { } // expected-warning {{overlapping comparisons always evaluate to false}}
+ if (x >= 2 && x < 3) { }
+ if (x >= 0 && x < 0) { } // expected-warning {{overlapping comparisons always evaluate to false}}
+
+ if (x >= 2 && x <= 1) { } // expected-warning {{overlapping comparisons always evaluate to false}}
+ if (x >= 2 && x <= 2) { }
+ if (x >= 2 && x <= 3) { }
+
+ // !=, ==, ..
+ if (x != 2 || x != 3) { } // expected-warning {{overlapping comparisons always evaluate to true}}
+ if (x != 2 || x < 3) { } // expected-warning {{overlapping comparisons always evaluate to true}}
+ if (x == 2 && x == 3) { } // expected-warning {{overlapping comparisons always evaluate to false}}
+ if (x == 2 && x > 3) { } // expected-warning {{overlapping comparisons always evaluate to false}}
+ if (x == 3 && x < 0) { } // expected-warning {{overlapping comparisons always evaluate to false}}
+ if (3 == x && x < 0) { } // expected-warning {{overlapping comparisons always evaluate to false}}
+
+ if (x == mydefine && x > 3) { }
+ if (x == (mydefine + 1) && x > 3) { }
+}
+
+// Don't generate a warning here.
+void array_out_of_bounds() {
+ int x;
+ int buffer[4];
+ x = (-7 > 0) ? (buffer[-7]) : 0;
+}
diff --git a/test/SemaCUDA/lit.local.cfg b/test/SemaCUDA/lit.local.cfg
new file mode 100644
index 0000000000..f4ef5d2fa0
--- /dev/null
+++ b/test/SemaCUDA/lit.local.cfg
@@ -0,0 +1,4 @@
+config.substitutions = list(config.substitutions)
+config.substitutions.insert(0,
+ (r'%clang\b',
+ """*** Do not use the driver in Sema tests. ***""") )
diff --git a/test/SemaCXX/addr-of-overloaded-function-casting.cpp b/test/SemaCXX/addr-of-overloaded-function-casting.cpp
index 784c8a0007..edf4c138a8 100644
--- a/test/SemaCXX/addr-of-overloaded-function-casting.cpp
+++ b/test/SemaCXX/addr-of-overloaded-function-casting.cpp
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
void g();
-void f(); // expected-note 9{{candidate function}}
-void f(int); // expected-note 9{{candidate function}}
+void f(); // expected-note 11{{candidate function}}
+void f(int); // expected-note 11{{candidate function}}
template <class T>
void t(T); // expected-note 3{{candidate function}} \
@@ -58,4 +58,13 @@ int main()
{ bool b = static_cast<int (&)(char)>(t); } // expected-error{{does not match required}}
{ bool b = static_cast<void (&)(char)>(f); } // expected-error{{does not match}}
+
+ {
+ // The error should be reported when casting overloaded function to the
+ // compatible function type (not to be confused with function pointer or
+ // function reference type.)
+ typedef void (FnType)(int);
+ FnType a = static_cast<FnType>(f); // expected-error{{address of overloaded function}}
+ FnType b = (FnType)(f); // expected-error{{address of overloaded function}}
+ }
}
diff --git a/test/SemaCXX/bool-compare.cpp b/test/SemaCXX/bool-compare.cpp
new file mode 100644
index 0000000000..fe47633bb2
--- /dev/null
+++ b/test/SemaCXX/bool-compare.cpp
@@ -0,0 +1,207 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+
+void f(int x, int y, int z) {
+
+ bool a,b;
+
+ if(b > true) {} // expected-warning {{comparison of true with expression of type 'bool' is always false}}
+ if(b < true) {} // no warning
+ if(b >= true) {} // no warning
+ if(b <= true) {} // expected-warning {{comparison of true with expression of type 'bool' is always true}}
+ if(b == true) {} // no warning
+ if(b != true) {} // no warning
+
+ if(b > false) {} // no warning
+ if(b < false) {} // expected-warning {{comparison of false with expression of type 'bool' is always false}}
+ if(b >= false) {} // expected-warning {{comparison of false with expression of type 'bool' is always true}}
+ if(b <= false) {} // no warning
+ if(b == false) {} // no warning
+ if(b != false) {} // no warning
+
+ if(b > 1U){} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always false}}
+
+ if (a > b) {} // no warning
+ if (a < b) {} // no warning
+ if (a >= b) {} // no warning
+ if (a <= b) {} // no warning
+ if (a == b) {} // no warning
+ if (a != b) {} // no warning
+
+ if (a > 0) {} // no warning
+ if (a > 1) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always false}}
+ if (a > 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always false}}
+
+ if (a >= 0) {} // expected-warning {{comparison of constant 0 with expression of type 'bool' is always true}}
+ if (a >= 1) {} // no warning
+ if (a >= 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always false}}
+ if (a >= -1) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}}
+
+ if (a <= 0) {} // no warning
+ if (a <= 1) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always true}}
+ if (a <= 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always true}}
+ if (a <= -1) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always false}}
+
+ if (!a > 0) {} // no warning
+ if (!a > 1) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always false}}
+ if (!a > 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always false}}
+ if (!a > y) {} // no warning
+ if (!a > b) {} // no warning
+ if (!a > -1) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}}
+
+ if (!a < 0) {} // expected-warning {{comparison of constant 0 with expression of type 'bool' is always false}}
+ if (!a < 1) {} // no warning
+ if (!a < 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always true}}
+ if (!a < y) {} // no warning
+ if (!a < b) {} // no warning
+ if (!a < -1) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always false}}
+
+ if (!a >= 0) {} // expected-warning {{comparison of constant 0 with expression of type 'bool' is always true}}
+ if (!a >= 1) {} // no warning
+ if (!a >= 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always false}}
+ if (!a >= y) {} // no warning
+ if (!a >= b) {} // no warning
+ if (!a >= -1) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}}
+
+ if (!a <= 0) {} // no warning
+ if (!a <= 1) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always true}}
+ if (!a <= 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always true}}
+ if (!a <= y) {} // no warning
+ if (!a <= b) {} // no warning
+ if (!a <= -1) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always false}}
+
+ if ((a||b) > 0) {} // no warning
+ if ((a||b) > 1) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always false}}
+ if ((a||b) > 4) {} // expected-warning {{comparison of constant 4 with expression of type 'bool' is always false}}
+ if ((a||b) > -1) {}// expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}}
+
+ if ((a&&b) > 0) {} // no warning
+ if ((a&&b) > 1) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always false}}
+ if ((a&&b) > 4) {} // expected-warning {{comparison of constant 4 with expression of type 'bool' is always false}}
+
+ if ((a<y) > 0) {} // no warning
+ if ((a<y) > 1) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always false}}
+ if ((a<y) > 4) {} // expected-warning {{comparison of constant 4 with expression of type 'bool' is always false}}
+ if ((a<y) > z) {} // no warning
+ if ((a<y) > -1) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}}
+
+ if ((a<y) == 0) {} // no warning
+ if ((a<y) == 1) {} // no warning
+ if ((a<y) == 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always false}}
+ if ((a<y) == z) {} // no warning
+ if ((a<y) == -1) {}// expected-warning {{comparison of constant -1 with expression of type 'bool' is always false}}
+
+ if ((a<y) != 0) {} // no warning
+ if ((a<y) != 1) {} // no warning
+ if ((a<y) != 2) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always true}}
+ if ((a<y) != z) {} // no warning
+ if ((a<y) != -1) {}// expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}}
+
+ if ((a<y) == z) {} // no warning
+ if (a>y<z) {} // no warning
+ if ((a<y) > z) {} // no warning
+ if((a<y)>(z<y)) {} // no warning
+ if((a<y)==(z<y)){} // no warning
+ if((a<y)!=(z<y)){} // no warning
+ if((z==x)<(y==z)){} // no warning
+ if((a<y)!=((z==x)<(y==z))){} // no warning
+
+
+ if (0 > !a) {} // expected-warning {{comparison of constant 0 with expression of type 'bool' is always false}}
+ if (1 > !a) {} // no warning
+ if (2 > !a) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always true}}
+ if (y > !a) {} // no warning
+ if (-1 > !a) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always false}}
+
+ if (0 < !a) {} // no warning
+ if (1 < !a) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always false}}
+ if (2 < !a) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always false}}
+ if (y < !a) {} // no warning
+ if (-1 < !a) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}}
+
+
+ if (0 >= !a) {} // no warning
+ if (1 >= !a) {} // expected-warning {{comparison of constant 1 with expression of type 'bool' is always true}}
+ if (2 >= !a) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always true}}
+ if (y >= !a) {} // no warning
+ if (-1 >= !a) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always false}}
+
+ if (0 <= !a) {} // expected-warning {{comparison of constant 0 with expression of type 'bool' is always true}}
+ if (1 <= !a) {} // no warning
+ if (2 <= !a) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always false}}
+ if (y <= !a) {} //
+ if (-1 <= !a) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}}
+
+ if (0 > (a||b)) {} // expected-warning {{comparison of constant 0 with expression of type 'bool' is always false}}
+ if (1 > (a||b)) {} // no warning
+ if (4 > (a||b)) {} // expected-warning {{comparison of constant 4 with expression of type 'bool' is always true}}
+
+ if (0 > (a&&b)) {} // expected-warning {{comparison of constant 0 with expression of type 'bool' is always false}}
+ if (1 > (a&&b)) {} // no warning
+ if (4 > (a&&b)) {} // expected-warning {{comparison of constant 4 with expression of type 'bool' is always true}}
+
+ if (0 > (a<y)) {} // expected-warning {{comparison of constant 0 with expression of type 'bool' is always false}}
+ if (1 > (a<y)) {} // no warning
+ if (4 > (a<y)) {} // expected-warning {{comparison of constant 4 with expression of type 'bool' is always true}}
+ if (z > (a<y)) {} //
+ if (-1 > (a<y)) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always false}}
+
+ if (0 == (a<y)) {} // no warning
+ if (1 == (a<y)) {} // no warning
+ if (2 == (a<y)) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always false}}
+ if (z == (a<y)) {} // no warning
+ if (-1 == (a<y)){} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always false}}
+
+ if (0 !=(a<y)) {} // no warning
+ if (1 !=(a<y)) {} // no warning
+ if (2 !=(a<y)) {} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always true}}
+ if (z !=(a<y)) {} // no warning
+ if (-1 !=(a<y)) {} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always true}}
+
+ if (z ==(a<y)) {} // no warning
+ if (z<a>y) {} // no warning
+ if (z > (a<y)) {} // no warning
+ if((z<y)>(a<y)) {} // no warning
+ if((z<y)==(a<y)){} // no warning
+ if((z<y)!=(a<y)){} // no warning
+ if((y==z)<(z==x)){} // no warning
+ if(((z==x)<(y==z))!=(a<y)){} // no warning
+
+ if(((z==x)<(-1==z))!=(a<y)){} // no warning
+ if(((z==x)<(z==-1))!=(a<y)){} // no warning
+ if(((z==x)<-1)!=(a<y)){} // expected-warning {{comparison of constant -1 with expression of type 'bool' is always false}}
+ if(((z==x)< 2)!=(a<y)){} // expected-warning {{comparison of constant 2 with expression of type 'bool' is always true}}
+ if(((z==x)<(z>2))!=(a<y)){} // no warning
+
+}
+
+
+template<typename T, typename U, typename V> struct X6 {
+ U f(T t, U u, V v) {
+ // IfStmt
+ if (t > 0)
+ return u;
+ else {
+ if (t < 0)
+ return v; // expected-error{{cannot initialize return object of type}}
+ }
+ bool r;
+ // FIXME: We should warn here, DiagRuntimeBehavior does currently not detect this.
+ if(r<0){}
+
+ if (T x = t) {
+ t = x;
+ }
+ return v; // expected-error{{cannot initialize return object of type}}
+ }
+};
+
+struct ConvertibleToInt {
+ operator int() const;
+};
+
+template struct X6<ConvertibleToInt, float, char>;
+template struct X6<bool, int, int*>; // expected-note{{instantiation}}
+
+
+
diff --git a/test/SemaCXX/cxx1y-deduced-return-type.cpp b/test/SemaCXX/cxx1y-deduced-return-type.cpp
index d3308b3fd5..6086416595 100644
--- a/test/SemaCXX/cxx1y-deduced-return-type.cpp
+++ b/test/SemaCXX/cxx1y-deduced-return-type.cpp
@@ -261,6 +261,13 @@ namespace DefaultedMethods {
namespace Constexpr {
constexpr auto f1(int n) { return n; }
+ template<typename T> struct X { constexpr auto f() {} }; // PR18746
+ template<typename T> struct Y { constexpr T f() {} }; // expected-note {{control reached end of constexpr function}}
+ void f() {
+ X<int>().f();
+ Y<void>().f();
+ constexpr int q = Y<int>().f(); // expected-error {{must be initialized by a constant expression}} expected-note {{in call to '&Y<int>()->f()'}}
+ }
struct NonLiteral { ~NonLiteral(); } nl; // expected-note {{user-provided destructor}}
constexpr auto f2(int n) { return nl; } // expected-error {{return type 'Constexpr::NonLiteral' is not a literal type}}
}
diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp
index 8c1efc9672..96af95425a 100644
--- a/test/SemaCXX/cxx98-compat.cpp
+++ b/test/SemaCXX/cxx98-compat.cpp
@@ -379,38 +379,22 @@ template<typename T> T var = T(10);
// expected-warning@-4 {{variable templates are a C++1y extension}}
#endif
+// No diagnostic for specializations of variable templates; we will have
+// diagnosed the primary template.
template<typename T> T* var<T*> = new T();
-#ifdef CXX1YCOMPAT
-// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
-#else
-// expected-warning@-4 {{variable templates are a C++1y extension}}
-#endif
-
template<> int var<int> = 10;
-#ifdef CXX1YCOMPAT
-// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
-#else
-// expected-warning@-4 {{variable templates are a C++1y extension}}
-#endif
-
template int var<int>;
float fvar = var<float>;
-class A {
+class A {
template<typename T> static T var = T(10);
#ifdef CXX1YCOMPAT
// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
#else
// expected-warning@-4 {{variable templates are a C++1y extension}}
#endif
-
- template<typename T> static T* var<T*> = new T();
-#ifdef CXX1YCOMPAT
-// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
-#else
-// expected-warning@-4 {{variable templates are a C++1y extension}}
-#endif
+ template<typename T> static T* var<T*> = new T();
};
struct B { template<typename T> static T v; };
@@ -428,19 +412,7 @@ template<typename T> T B::v = T();
#endif
template<typename T> T* B::v<T*> = new T();
-#ifdef CXX1YCOMPAT
-// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
-#else
-// expected-warning@-4 {{variable templates are a C++1y extension}}
-#endif
-
template<> int B::v<int> = 10;
-#ifdef CXX1YCOMPAT
-// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}}
-#else
-// expected-warning@-4 {{variable templates are a C++1y extension}}
-#endif
-
template int B::v<int>;
float fsvar = B::v<float>;
diff --git a/test/SemaCXX/decl-microsoft-call-conv.cpp b/test/SemaCXX/decl-microsoft-call-conv.cpp
index 4282047278..eb6c8507ed 100644
--- a/test/SemaCXX/decl-microsoft-call-conv.cpp
+++ b/test/SemaCXX/decl-microsoft-call-conv.cpp
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -triple i686-pc-win32 -fms-extensions -verify %s
+// RUN: %clang_cc1 -triple i686-pc-mingw32 -verify %s
+// RUN: %clang_cc1 -triple i686-pc-mingw32 -fms-extensions -verify %s
typedef void void_fun_t();
typedef void __cdecl cdecl_fun_t();
diff --git a/test/SemaCXX/decltype.cpp b/test/SemaCXX/decltype.cpp
index 8de5a9c3ba..f1900b2b83 100644
--- a/test/SemaCXX/decltype.cpp
+++ b/test/SemaCXX/decltype.cpp
@@ -16,6 +16,27 @@ void test_f2() {
float &fr = f2(AC().a);
}
+template <class T>
+struct Future {
+ explicit Future(T v);
+
+ template <class F>
+ auto call(F&& fn) -> decltype(fn(T())) {
+ return fn(T());
+ }
+
+ template <class B, class F>
+ auto then(F&& fn) -> decltype(call(fn))
+ {
+ return fn(T());
+ }
+};
+
+void rdar16527205() {
+ Future<int> f1(42);
+ f1.call([](int){ return Future<float>(0); });
+}
+
namespace pr10154 {
class A{
A(decltype(nullptr) param);
diff --git a/test/SemaCXX/expressions.cpp b/test/SemaCXX/expressions.cpp
index 25a9c84172..1a50c99c59 100644
--- a/test/SemaCXX/expressions.cpp
+++ b/test/SemaCXX/expressions.cpp
@@ -125,3 +125,13 @@ namespace pr16992 {
return (sizeof T());
}
}
+
+void test4() {
+ #define X 0
+ #define Y 1
+ bool r1 = X || Y;
+
+ #define Y2 2
+ bool r2 = X || Y2; // expected-warning {{use of logical '||' with constant operand}} \
+ // expected-note {{use '|' for a bitwise operation}}
+}
diff --git a/test/SemaCXX/funcdname.cpp b/test/SemaCXX/funcdname.cpp
new file mode 100644
index 0000000000..d63d3f54c3
--- /dev/null
+++ b/test/SemaCXX/funcdname.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -std=c++1y -triple i386-pc-win32 -fms-compatibility -fms-extensions -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+int foo() {
+ static_assert(sizeof(__FUNCDNAME__) == 12, "?foo@@YAHXZ");
+ return 0;
+}
+
+// Within templates.
+template <typename T>
+int baz() {
+ static_assert(sizeof(__FUNCDNAME__) == 16, "??$baz@H@@YAHXZ");
+
+ return 0;
+}
+
+struct A {
+ A() {
+ static_assert(sizeof(__FUNCDNAME__) == 13, "??0A@@QAE@XZ");
+ }
+ ~A() {
+ static_assert(sizeof(__FUNCDNAME__) == 13, "??1A@@QAE@XZ");
+ }
+};
+
+int main() {
+ static_assert(sizeof(__FUNCDNAME__) == 5, "main");
+
+ baz<int>();
+
+ return 0;
+}
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index 8587e70158..bfbf9c4135 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -8,13 +8,12 @@ namespace A {
static int Ag1();
static int Ag2();
};
- int ax;
+ int ax; // expected-note {{'ax' declared here}}
void Af();
}
A:: ; // expected-error {{expected unqualified-id}}
-// FIXME: there is a member 'ax'; it's just not a class.
-::A::ax::undef ex3; // expected-error {{no member named 'ax'}}
+::A::ax::undef ex3; // expected-error {{'ax' is not a class, namespace, or scoped enumeration}}
A::undef1::undef2 ex4; // expected-error {{no member named 'undef1'}}
int A::C::Ag1() { return 0; }
diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
index 28fb8dc749..3b94ef0951 100644
--- a/test/SemaCXX/type-traits.cpp
+++ b/test/SemaCXX/type-traits.cpp
@@ -1964,6 +1964,10 @@ void constructible_checks() {
{ int arr[T(__is_constructible(NonPOD, int))]; }
{ int arr[F(__is_nothrow_constructible(NonPOD, int))]; }
+
+ // PR19178
+ { int arr[F(__is_constructible(Abstract))]; }
+ { int arr[F(__is_nothrow_constructible(Abstract))]; }
}
// Instantiation of __is_trivially_constructible
@@ -1991,6 +1995,7 @@ void is_trivially_constructible_test() {
{ int arr[F((is_trivially_constructible<int, int*>::value))]; }
{ int arr[F((is_trivially_constructible<NonTrivialDefault>::value))]; }
{ int arr[F((is_trivially_constructible<ThreeArgCtor, int*, char*, int&>::value))]; }
+ { int arr[F((is_trivially_constructible<Abstract>::value))]; } // PR19178
}
void array_rank() {
diff --git a/test/SemaCXX/typo-correction-pt2.cpp b/test/SemaCXX/typo-correction-pt2.cpp
index 9943dd21f5..2fab22a204 100644
--- a/test/SemaCXX/typo-correction-pt2.cpp
+++ b/test/SemaCXX/typo-correction-pt2.cpp
@@ -242,6 +242,28 @@ void func() {
};
bar(); // expected-error-re {{use of undeclared identifier 'bar'{{$}}}}
}
+
+class Thread {
+ public:
+ void Start();
+ static void Stop(); // expected-note {{'Thread::Stop' declared here}}
+};
+
+class Manager {
+ public:
+ void Start(int); // expected-note {{'Start' declared here}}
+ void Stop(int); // expected-note {{'Stop' declared here}}
+};
+
+void test(Manager *m) {
+ // Don't suggest Thread::Start as a correction just because it has the same
+ // (unqualified) name and accepts the right number of args; this is a method
+ // call on an object in an unrelated class.
+ m->Start(); // expected-error-re {{too few arguments to function call, expected 1, have 0{{$}}}}
+ m->Stop(); // expected-error-re {{too few arguments to function call, expected 1, have 0{{$}}}}
+ Stop(); // expected-error {{use of undeclared identifier 'Stop'; did you mean 'Thread::Stop'?}}
+}
+
}
namespace std {
diff --git a/test/SemaCXX/using-decl-1.cpp b/test/SemaCXX/using-decl-1.cpp
index 24d92f175c..21aa107e21 100644
--- a/test/SemaCXX/using-decl-1.cpp
+++ b/test/SemaCXX/using-decl-1.cpp
@@ -160,3 +160,37 @@ namespace M { }
}
using N::M::FFF; // expected-error {{no member named 'FFF' in namespace 'using_suggestion_val_dropped_nested_specifier::N::M'; did you mean 'N::FFF'?}}
}
+
+namespace UsingDeclVsHiddenName {
+ namespace A {
+ enum HiddenTag1 {}; // expected-note {{previous use is here}}
+ enum HiddenTag2 {}; // expected-note {{target}}
+ int HiddenFn1; // expected-note {{target}}
+ int HiddenFn2; // expected-note {{target}}
+ int HiddenLocalExtern1;
+ int HiddenLocalExtern2;
+ }
+
+ namespace B {
+ using A::HiddenTag1;
+ using A::HiddenFn1; // expected-note {{using declaration}}
+ using A::HiddenLocalExtern1;
+
+ struct S {
+ friend struct HiddenTag1; // expected-error {{tag type that does not match previous}}
+ friend struct HiddenTag2; // expected-note {{conflicting declaration}}
+ friend void HiddenFn1(); // expected-error {{cannot befriend target of using declaration}}
+ friend void HiddenFn2(); // expected-note {{conflicting declaration}}
+ void f() {
+ // OK, these are not in the scope of namespace B, even though they're
+ // members of the namespace.
+ void HiddenLocalExtern1();
+ void HiddenLocalExtern2();
+ }
+ };
+
+ using A::HiddenTag2; // expected-error {{conflicts with declaration already in scope}}
+ using A::HiddenFn2; // expected-error {{conflicts with declaration already in scope}}
+ using A::HiddenLocalExtern2;
+ }
+}
diff --git a/test/SemaCXX/vector-casts.cpp b/test/SemaCXX/vector-casts.cpp
index 3aa097b652..2ccd5979c7 100644
--- a/test/SemaCXX/vector-casts.cpp
+++ b/test/SemaCXX/vector-casts.cpp
@@ -23,19 +23,19 @@ void f() {
(void)reinterpret_cast<__v2si>(ll);
(void)(__v2si)(ll);
- (void)reinterpret_cast<S>(v2si); // expected-error {{reinterpret_cast from '__v2si' to 'S' is not allowed}}
- (void)(S)v2si; // expected-error {{no matching conversion for C-style cast from '__v2si' to 'S'}}
- (void)reinterpret_cast<__v2si>(s); // expected-error {{reinterpret_cast from 'S' to '__v2si' is not allowed}}
- (void)(__v2si)s; // expected-error {{cannot convert 'S' to '__v2si' without a conversion operator}}
+ (void)reinterpret_cast<S>(v2si); // expected-error {{reinterpret_cast from '__v2si' (vector of 2 'int' values) to 'S' is not allowed}}
+ (void)(S)v2si; // expected-error {{no matching conversion for C-style cast from '__v2si' (vector of 2 'int' values) to 'S'}}
+ (void)reinterpret_cast<__v2si>(s); // expected-error {{reinterpret_cast from 'S' to '__v2si' (vector of 2 'int' values) is not allowed}}
+ (void)(__v2si)s; // expected-error {{cannot convert 'S' to '__v2si' (vector of 2 'int' values) without a conversion operator}}
- (void)reinterpret_cast<unsigned char>(v2si); // expected-error {{reinterpret_cast from vector '__v2si' to scalar 'unsigned char' of different size}}
- (void)(unsigned char)v2si; // expected-error {{C-style cast from vector '__v2si' to scalar 'unsigned char' of different size}}
- (void)reinterpret_cast<__v2si>(c); // expected-error {{reinterpret_cast from scalar 'unsigned char' to vector '__v2si' of different size}}
+ (void)reinterpret_cast<unsigned char>(v2si); // expected-error {{reinterpret_cast from vector '__v2si' (vector of 2 'int' values) to scalar 'unsigned char' of different size}}
+ (void)(unsigned char)v2si; // expected-error {{C-style cast from vector '__v2si' (vector of 2 'int' values) to scalar 'unsigned char' of different size}}
+ (void)reinterpret_cast<__v2si>(c); // expected-error {{reinterpret_cast from scalar 'unsigned char' to vector '__v2si' (vector of 2 'int' values) of different size}}
- (void)reinterpret_cast<__v8hi>(v4hi); // expected-error {{reinterpret_cast from vector '__v4hi' to vector '__v8hi' of different size}}
- (void)(__v8hi)v4hi; // expected-error {{C-style cast from vector '__v4hi' to vector '__v8hi' of different size}}
- (void)reinterpret_cast<__v4hi>(v8hi); // expected-error {{reinterpret_cast from vector '__v8hi' to vector '__v4hi' of different size}}
- (void)(__v4hi)v8hi; // expected-error {{C-style cast from vector '__v8hi' to vector '__v4hi' of different size}}
+ (void)reinterpret_cast<__v8hi>(v4hi); // expected-error {{reinterpret_cast from vector '__v4hi' (vector of 4 'short' values) to vector '__v8hi' (vector of 8 'short' values) of different size}}
+ (void)(__v8hi)v4hi; // expected-error {{C-style cast from vector '__v4hi' (vector of 4 'short' values) to vector '__v8hi' (vector of 8 'short' values) of different size}}
+ (void)reinterpret_cast<__v4hi>(v8hi); // expected-error {{reinterpret_cast from vector '__v8hi' (vector of 8 'short' values) to vector '__v4hi' (vector of 4 'short' values) of different size}}
+ (void)(__v4hi)v8hi; // expected-error {{C-style cast from vector '__v8hi' (vector of 8 'short' values) to vector '__v4hi' (vector of 4 'short' values) of different size}}
}
struct testvec {
diff --git a/test/SemaCXX/vector.cpp b/test/SemaCXX/vector.cpp
index 7957c23e3e..bcd7fedb4d 100644
--- a/test/SemaCXX/vector.cpp
+++ b/test/SemaCXX/vector.cpp
@@ -24,8 +24,8 @@ void f1_test(char16 c16, longlong16 ll16, char16_e c16e, longlong16_e ll16e) {
f1(ll16e); // expected-error{{call to 'f1' is ambiguous}}
}
-void f2(char16_e); // expected-note{{no known conversion from 'longlong16_e' to 'char16_e' for 1st argument}} \
- // expected-note{{candidate function not viable: no known conversion from 'convertible_to<longlong16_e>' to 'char16_e' for 1st argument}}
+void f2(char16_e); // expected-note{{no known conversion from 'longlong16_e' (vector of 2 'long long' values) to 'char16_e' (vector of 16 'char' values) for 1st argument}} \
+ // expected-note{{candidate function not viable: no known conversion from 'convertible_to<longlong16_e>' to 'char16_e' (vector of 16 'char' values) for 1st argument}}
void f2_test(char16 c16, longlong16 ll16, char16_e c16e, longlong16_e ll16e) {
f2(c16);
@@ -85,7 +85,7 @@ void casts(longlong16 ll16, longlong16_e ll16e) {
(void)static_cast<longlong16>(ll16);
(void)static_cast<longlong16_e>(ll16);
(void)static_cast<char16>(ll16e);
- (void)static_cast<char16_e>(ll16e); // expected-error{{static_cast from 'longlong16_e' to 'char16_e' is not allowed}}
+ (void)static_cast<char16_e>(ll16e); // expected-error{{static_cast from 'longlong16_e' (vector of 2 'long long' values) to 'char16_e' (vector of 16 'char' values) is not allowed}}
(void)static_cast<longlong16>(ll16e);
(void)static_cast<longlong16_e>(ll16e);
@@ -194,11 +194,11 @@ typedef float fltx4 __attribute__((__vector_size__(16)));
typedef double dblx2 __attribute__((__vector_size__(16)));
typedef double dblx4 __attribute__((__vector_size__(32)));
-void accept_fltx2(fltx2); // expected-note{{candidate function not viable: no known conversion from 'double' to 'fltx2' for 1st argument}}
+void accept_fltx2(fltx2); // expected-note{{candidate function not viable: no known conversion from 'double' to 'fltx2' (vector of 2 'float' values) for 1st argument}}
void accept_fltx4(fltx4);
void accept_dblx2(dblx2);
void accept_dblx4(dblx4);
-void accept_bool(bool); // expected-note{{candidate function not viable: no known conversion from 'fltx2' to 'bool' for 1st argument}}
+void accept_bool(bool); // expected-note{{candidate function not viable: no known conversion from 'fltx2' (vector of 2 'float' values) to 'bool' for 1st argument}}
void test(fltx2 fltx2_val, fltx4 fltx4_val, dblx2 dblx2_val, dblx4 dblx4_val) {
// Exact matches
diff --git a/test/SemaCXX/warn-absolute-value-header.cpp b/test/SemaCXX/warn-absolute-value-header.cpp
index 01aaabcc00..96e6a31540 100644
--- a/test/SemaCXX/warn-absolute-value-header.cpp
+++ b/test/SemaCXX/warn-absolute-value-header.cpp
@@ -1,37 +1,53 @@
// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -verify %s -Wabsolute-value
// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only %s -Wabsolute-value -fdiagnostics-parseable-fixits 2>&1 | FileCheck %s
-extern "C" int abs(int);
+extern "C" {
+ int abs(int);
+ float fabsf(float);
+}
-// Wrong signature
-int fabsf(int);
+namespace std {
+ int abs(int);
+ float abs(float);
+}
-void test_int(int i, unsigned u, long long ll, float f, double d) {
- (void)abs(i);
+void test(long long ll, double d, int i, float f) {
+ // Suggest including cmath
+ (void)abs(d);
+ // expected-warning@-1{{using integer absolute value function 'abs' when argument is of floating point type}}
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // expected-note@-3{{please include the header <cmath> or explicitly provide a declaration for 'std::abs'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:9-[[@LINE-4]]:12}:"std::abs"
- // Remove abs call
- (void)abs(u);
- // expected-warning@-1{{taking the absolute value of unsigned type 'unsigned int' has no effect}}
- // expected-note@-2{{remove the call to 'abs' since unsigned values cannot be negative}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:12}:""
+ (void)fabsf(d);
+ // expected-warning@-1{{absolute value function 'fabsf' given an argument of type 'double' but has parameter of type 'float' which may cause truncation of value}}
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // expected-note@-3{{please include the header <cmath> or explicitly provide a declaration for 'std::abs'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:9-[[@LINE-4]]:14}:"std::abs"
- int llabs;
- (void)llabs;
- // Conflict in names, suggest qualified name
+ // Suggest including cstdlib
(void)abs(ll);
// expected-warning@-1{{absolute value function 'abs' given an argument of type 'long long' but has parameter of type 'int' which may cause truncation of value}}
- // expected-note@-2{{use function '::llabs' instead}}
- // expected-note@-3{{please include the header <stdlib.h> or explicitly provide a declaration for 'llabs'}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:9-[[@LINE-4]]:12}:"::llabs"
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // expected-note@-3{{please include the header <cstdlib> or explicitly provide a declaration for 'std::abs'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:9-[[@LINE-4]]:12}:"std::abs"
+ (void)fabsf(ll);
+ // expected-warning@-1{{using floating point absolute value function 'fabsf' when argument is of integer type}}
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // expected-note@-3{{please include the header <cstdlib> or explicitly provide a declaration for 'std::abs'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:9-[[@LINE-4]]:14}:"std::abs"
- // Conflict in names, no notes
- (void)abs(f);
- // expected-warning@-1{{using integer absolute value function 'abs' when argument is of floating point type}}
+ // Proper function already called, no warnings.
+ (void)abs(i);
+ (void)fabsf(f);
- // Suggest header.
- (void)abs(d);
+ // Declarations found, suggest name change.
+ (void)fabsf(i);
+ // expected-warning@-1{{using floating point absolute value function 'fabsf' when argument is of integer type}}
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+ (void)abs(f);
// expected-warning@-1{{using integer absolute value function 'abs' when argument is of floating point type}}
- // expected-note@-2{{use function 'fabs' instead}}
- // expected-note@-3{{please include the header <math.h> or explicitly provide a declaration for 'fabs'}}
- // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:9-[[@LINE-4]]:12}:"fabs"
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:12}:"std::abs"
}
diff --git a/test/SemaCXX/warn-absolute-value.cpp b/test/SemaCXX/warn-absolute-value.cpp
new file mode 100644
index 0000000000..8a8a6fd67d
--- /dev/null
+++ b/test/SemaCXX/warn-absolute-value.cpp
@@ -0,0 +1,823 @@
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -verify %s -Wabsolute-value -std=c++11
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only %s -Wabsolute-value -fdiagnostics-parseable-fixits -std=c++11 2>&1 | FileCheck %s
+
+extern "C" {
+int abs(int);
+long int labs(long int);
+long long int llabs(long long int);
+
+float fabsf(float);
+double fabs(double);
+long double fabsl(long double);
+
+float cabsf(float _Complex);
+double cabs(double _Complex);
+long double cabsl(long double _Complex);
+}
+
+namespace std {
+
+inline namespace __1 {
+int abs(int);
+long int abs(long int);
+long long int abs(long long int);
+}
+
+float abs(float);
+double abs(double);
+long double abs(long double);
+
+template <typename T>
+double abs(T);
+
+}
+
+void test_int(int x) {
+ (void)std::abs(x);
+
+ (void)abs(x);
+ (void)labs(x);
+ (void)llabs(x);
+
+ (void)fabsf(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabsf' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+ (void)fabs(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabs' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs"
+ (void)fabsl(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabsl' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+
+ (void)cabsf(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabsf' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+ (void)cabs(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabs' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs"
+ (void)cabsl(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabsl' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+
+ (void)__builtin_abs(x);
+ (void)__builtin_labs(x);
+ (void)__builtin_llabs(x);
+
+ (void)__builtin_fabsf(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsf' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+ (void)__builtin_fabs(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabs' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs"
+ (void)__builtin_fabsl(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsl' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+
+ (void)__builtin_cabsf(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabsf' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+ (void)__builtin_cabs(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabs' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs"
+ (void)__builtin_cabsl(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabsl' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+}
+
+void test_long(long x) {
+ (void)std::abs(x);
+
+ (void)abs(x); // no warning - int and long are same length for this target
+ (void)labs(x);
+ (void)llabs(x);
+
+ (void)fabsf(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabsf' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+ (void)fabs(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabs' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs"
+ (void)fabsl(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabsl' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+
+ (void)cabsf(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabsf' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+ (void)cabs(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabs' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs"
+ (void)cabsl(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabsl' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+
+ (void)__builtin_abs(x); // no warning - int and long are same length for
+ // this target
+ (void)__builtin_labs(x);
+ (void)__builtin_llabs(x);
+
+ (void)__builtin_fabsf(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsf' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+ (void)__builtin_fabs(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabs' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs"
+ (void)__builtin_fabsl(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsl' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+
+ (void)__builtin_cabsf(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabsf' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+ (void)__builtin_cabs(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabs' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs"
+ (void)__builtin_cabsl(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabsl' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+}
+
+void test_long_long(long long x) {
+ (void)std::abs(x);
+
+ (void)abs(x);
+ // expected-warning@-1{{absolute value function 'abs' given an argument of type 'long long' but has parameter of type 'int' which may cause truncation of value}}
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:12}:"std::abs"
+ (void)labs(x);
+ // expected-warning@-1{{absolute value function 'labs' given an argument of type 'long long' but has parameter of type 'long' which may cause truncation of value}}
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs"
+ (void)llabs(x);
+
+ (void)fabsf(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabsf' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+ (void)fabs(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabs' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs"
+ (void)fabsl(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabsl' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+
+ (void)cabsf(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabsf' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+ (void)cabs(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabs' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs"
+ (void)cabsl(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabsl' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+
+ (void)__builtin_abs(x);
+ // expected-warning@-1{{absolute value function '__builtin_abs' given an argument of type 'long long' but has parameter of type 'int' which may cause truncation of value}}
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:22}:"std::abs"
+ (void)__builtin_labs(x);
+ // expected-warning@-1{{absolute value function '__builtin_labs' given an argument of type 'long long' but has parameter of type 'long' which may cause truncation of value}}
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs"
+ (void)__builtin_llabs(x);
+
+ (void)__builtin_fabsf(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsf' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+ (void)__builtin_fabs(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabs' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs"
+ (void)__builtin_fabsl(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsl' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+
+ (void)__builtin_cabsf(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabsf' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+ (void)__builtin_cabs(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabs' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs"
+ (void)__builtin_cabsl(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabsl' when argument is of integer type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+}
+
+void test_float(float x) {
+ (void)std::abs(x);
+
+ (void)abs(x);
+ // expected-warning@-1 {{using integer absolute value function 'abs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:12}:"std::abs"
+ (void)labs(x);
+ // expected-warning@-1 {{using integer absolute value function 'labs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs"
+ (void)llabs(x);
+ // expected-warning@-1 {{using integer absolute value function 'llabs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+
+ (void)fabsf(x);
+ (void)fabs(x);
+ (void)fabsl(x);
+
+ (void)cabsf(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabsf' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+ (void)cabs(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs"
+ (void)cabsl(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabsl' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+
+ (void)__builtin_abs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_abs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:22}:"std::abs"
+ (void)__builtin_labs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_labs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs"
+ (void)__builtin_llabs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_llabs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+
+ (void)__builtin_fabsf(x);
+ (void)__builtin_fabs(x);
+ (void)__builtin_fabsl(x);
+
+ (void)__builtin_cabsf(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabsf' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+ (void)__builtin_cabs(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs"
+ (void)__builtin_cabsl(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabsl' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+}
+
+void test_double(double x) {
+ (void)std::abs(x);
+
+ (void)abs(x);
+ // expected-warning@-1 {{using integer absolute value function 'abs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:12}:"std::abs"
+ (void)labs(x);
+ // expected-warning@-1 {{using integer absolute value function 'labs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs"
+ (void)llabs(x);
+ // expected-warning@-1 {{using integer absolute value function 'llabs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+
+ (void)fabsf(x);
+ // expected-warning@-1{{absolute value function 'fabsf' given an argument of type 'double' but has parameter of type 'float' which may cause truncation of value}}
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+ (void)fabs(x);
+ (void)fabsl(x);
+
+ (void)cabsf(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabsf' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+ (void)cabs(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs"
+ (void)cabsl(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabsl' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+
+ (void)__builtin_abs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_abs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:22}:"std::abs"
+ (void)__builtin_labs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_labs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs"
+ (void)__builtin_llabs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_llabs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+
+ (void)__builtin_fabsf(x);
+ // expected-warning@-1{{absolute value function '__builtin_fabsf' given an argument of type 'double' but has parameter of type 'float' which may cause truncation of value}}
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+ (void)__builtin_fabs(x);
+ (void)__builtin_fabsl(x);
+
+ (void)__builtin_cabsf(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabsf' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+ (void)__builtin_cabs(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs"
+ (void)__builtin_cabsl(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabsl' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+}
+
+void test_long_double(long double x) {
+ (void)std::abs(x);
+
+ (void)abs(x);
+ // expected-warning@-1 {{using integer absolute value function 'abs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:12}:"std::abs"
+ (void)labs(x);
+ // expected-warning@-1 {{using integer absolute value function 'labs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs"
+ (void)llabs(x);
+ // expected-warning@-1 {{using integer absolute value function 'llabs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+
+ (void)fabsf(x);
+ // expected-warning@-1{{absolute value function 'fabsf' given an argument of type 'long double' but has parameter of type 'float' which may cause truncation of value}}
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+ (void)fabs(x);
+ // expected-warning@-1{{absolute value function 'fabs' given an argument of type 'long double' but has parameter of type 'double' which may cause truncation of value}}
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs"
+ (void)fabsl(x);
+
+ (void)cabsf(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabsf' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+ (void)cabs(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"std::abs"
+ (void)cabsl(x);
+ // expected-warning@-1 {{using complex absolute value function 'cabsl' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"std::abs"
+
+ (void)__builtin_abs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_abs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:22}:"std::abs"
+ (void)__builtin_labs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_labs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs"
+ (void)__builtin_llabs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_llabs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+
+ (void)__builtin_fabsf(x);
+ // expected-warning@-1{{absolute value function '__builtin_fabsf' given an argument of type 'long double' but has parameter of type 'float' which may cause truncation of value}}
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+ (void)__builtin_fabs(x);
+ // expected-warning@-1{{absolute value function '__builtin_fabs' given an argument of type 'long double' but has parameter of type 'double' which may cause truncation of value}}
+ // expected-note@-2{{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs"
+ (void)__builtin_fabsl(x);
+
+ (void)__builtin_cabsf(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabsf' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+ (void)__builtin_cabs(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabs' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"std::abs"
+ (void)__builtin_cabsl(x);
+ // expected-warning@-1 {{using complex absolute value function '__builtin_cabsl' when argument is of floating point type}}
+ // expected-note@-2 {{use function 'std::abs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"std::abs"
+}
+
+void test_complex_float(_Complex float x) {
+ (void)abs(x);
+ // expected-warning@-1 {{using integer absolute value function 'abs' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabsf' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:12}:"cabsf"
+ (void)labs(x);
+ // expected-warning@-1 {{using integer absolute value function 'labs' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabsf' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"cabsf"
+ (void)llabs(x);
+ // expected-warning@-1 {{using integer absolute value function 'llabs' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabsf' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabsf"
+
+ (void)fabsf(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabsf' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabsf' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabsf"
+ (void)fabs(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabs' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabsf' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"cabsf"
+ (void)fabsl(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabsl' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabsf' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabsf"
+
+ (void)cabsf(x);
+ (void)cabs(x);
+ (void)cabsl(x);
+
+ (void)__builtin_abs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_abs' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabsf' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:22}:"__builtin_cabsf"
+ (void)__builtin_labs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_labs' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabsf' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_cabsf"
+ (void)__builtin_llabs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_llabs' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabsf' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabsf"
+
+ (void)__builtin_fabsf(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsf' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabsf' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabsf"
+ (void)__builtin_fabs(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabs' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabsf' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_cabsf"
+ (void)__builtin_fabsl(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsl' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabsf' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabsf"
+
+ (void)__builtin_cabsf(x);
+ (void)__builtin_cabs(x);
+ (void)__builtin_cabsl(x);
+}
+
+void test_complex_double(_Complex double x) {
+ (void)abs(x);
+ // expected-warning@-1 {{using integer absolute value function 'abs' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:12}:"cabs"
+ (void)labs(x);
+ // expected-warning@-1 {{using integer absolute value function 'labs' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"cabs"
+ (void)llabs(x);
+ // expected-warning@-1 {{using integer absolute value function 'llabs' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabs"
+
+ (void)fabsf(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabsf' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabs"
+ (void)fabs(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabs' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"cabs"
+ (void)fabsl(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabsl' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabs"
+
+ (void)cabsf(x);
+ // expected-warning@-1 {{absolute value function 'cabsf' given an argument of type '_Complex double' but has parameter of type '_Complex float' which may cause truncation of value}}
+ // expected-note@-2 {{use function 'cabs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabs"
+ (void)cabs(x);
+ (void)cabsl(x);
+
+ (void)__builtin_abs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_abs' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:22}:"__builtin_cabs"
+ (void)__builtin_labs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_labs' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_cabs"
+ (void)__builtin_llabs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_llabs' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabs"
+
+ (void)__builtin_fabsf(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsf' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabs"
+ (void)__builtin_fabs(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabs' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_cabs"
+ (void)__builtin_fabsl(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsl' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabs"
+
+ (void)__builtin_cabsf(x);
+ // expected-warning@-1 {{absolute value function '__builtin_cabsf' given an argument of type '_Complex double' but has parameter of type '_Complex float' which may cause truncation of value}}
+ // expected-note@-2 {{use function '__builtin_cabs' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabs"
+ (void)__builtin_cabs(x);
+ (void)__builtin_cabsl(x);
+}
+
+void test_complex_long_double(_Complex long double x) {
+ (void)abs(x);
+ // expected-warning@-1 {{using integer absolute value function 'abs' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:12}:"cabsl"
+ (void)labs(x);
+ // expected-warning@-1 {{using integer absolute value function 'labs' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"cabsl"
+ (void)llabs(x);
+ // expected-warning@-1 {{using integer absolute value function 'llabs' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabsl"
+
+ (void)fabsf(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabsf' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabsl"
+ (void)fabs(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabs' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"cabsl"
+ (void)fabsl(x);
+ // expected-warning@-1 {{using floating point absolute value function 'fabsl' when argument is of complex type}}
+ // expected-note@-2 {{use function 'cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabsl"
+
+ (void)cabsf(x);
+ // expected-warning@-1 {{absolute value function 'cabsf' given an argument of type '_Complex long double' but has parameter of type '_Complex float' which may cause truncation of value}}
+ // expected-note@-2 {{use function 'cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:"cabsl"
+ (void)cabs(x);
+ // expected-warning@-1 {{absolute value function 'cabs' given an argument of type '_Complex long double' but has parameter of type '_Complex double' which may cause truncation of value}}
+ // expected-note@-2 {{use function 'cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:"cabsl"
+ (void)cabsl(x);
+
+ (void)__builtin_abs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_abs' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:22}:"__builtin_cabsl"
+ (void)__builtin_labs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_labs' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_cabsl"
+ (void)__builtin_llabs(x);
+ // expected-warning@-1 {{using integer absolute value function '__builtin_llabs' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabsl"
+
+ (void)__builtin_fabsf(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsf' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabsl"
+ (void)__builtin_fabs(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabs' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_cabsl"
+ (void)__builtin_fabsl(x);
+ // expected-warning@-1 {{using floating point absolute value function '__builtin_fabsl' when argument is of complex type}}
+ // expected-note@-2 {{use function '__builtin_cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabsl"
+
+ (void)__builtin_cabsf(x);
+ // expected-warning@-1 {{absolute value function '__builtin_cabsf' given an argument of type '_Complex long double' but has parameter of type '_Complex float' which may cause truncation of value}}
+ // expected-note@-2 {{use function '__builtin_cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:"__builtin_cabsl"
+ (void)__builtin_cabs(x);
+ // expected-warning@-1 {{absolute value function '__builtin_cabs' given an argument of type '_Complex long double' but has parameter of type '_Complex double' which may cause truncation of value}}
+ // expected-note@-2 {{use function '__builtin_cabsl' instead}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:"__builtin_cabsl"
+ (void)__builtin_cabsl(x);
+}
+
+void test_unsigned_int(unsigned int x) {
+ (void)std::abs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to 'std::abs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:17}:""
+
+ (void)abs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to 'abs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:12}:""
+ (void)labs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to 'labs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:""
+ (void)llabs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to 'llabs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:""
+
+ (void)fabsf(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to 'fabsf' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:""
+ (void)fabs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to 'fabs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:""
+ (void)fabsl(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to 'fabsl' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:""
+
+ (void)cabsf(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to 'cabsf' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:""
+ (void)cabs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to 'cabs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:""
+ (void)cabsl(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to 'cabsl' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:""
+
+ (void)__builtin_abs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_abs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:22}:""
+ (void)__builtin_labs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_labs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:""
+ (void)__builtin_llabs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_llabs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:""
+
+ (void)__builtin_fabsf(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_fabsf' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:""
+ (void)__builtin_fabs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_fabs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:""
+ (void)__builtin_fabsl(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_fabsl' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:""
+
+ (void)__builtin_cabsf(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_cabsf' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:""
+ (void)__builtin_cabs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_cabs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:""
+ (void)__builtin_cabsl(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned int' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_cabsl' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:""
+}
+
+void test_unsigned_long(unsigned long x) {
+ (void)std::abs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to 'std::abs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:17}:""
+
+ (void)abs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to 'abs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:12}:""
+ (void)labs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to 'labs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:""
+ (void)llabs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to 'llabs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:""
+
+ (void)fabsf(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to 'fabsf' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:""
+ (void)fabs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to 'fabs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:""
+ (void)fabsl(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to 'fabsl' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:""
+
+ (void)cabsf(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to 'cabsf' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:""
+ (void)cabs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to 'cabs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:13}:""
+ (void)cabsl(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to 'cabsl' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:14}:""
+
+ (void)__builtin_abs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_abs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:22}:""
+ (void)__builtin_labs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_labs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:""
+ (void)__builtin_llabs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_llabs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:""
+
+ (void)__builtin_fabsf(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_fabsf' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:""
+ (void)__builtin_fabs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_fabs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:""
+ (void)__builtin_fabsl(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_fabsl' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:""
+
+ (void)__builtin_cabsf(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_cabsf' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:""
+ (void)__builtin_cabs(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_cabs' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:23}:""
+ (void)__builtin_cabsl(x);
+ // expected-warning@-1 {{taking the absolute value of unsigned type 'unsigned long' has no effect}}
+ // expected-note@-2 {{remove the call to '__builtin_cabsl' since unsigned values cannot be negative}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:9-[[@LINE-3]]:24}:""
+}
+
diff --git a/test/SemaCXX/warn-absolute-value2.cpp b/test/SemaCXX/warn-absolute-value2.cpp
deleted file mode 100644
index 5f7e891878..0000000000
--- a/test/SemaCXX/warn-absolute-value2.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: %clang_cc1 -triple i686-pc-linux-gnu -fsyntax-only -verify %s -Wabsolute-value
-
-extern "C" {
-int abs(int);
-double fabs(double);
-}
-
-using ::fabs;
-
-double test(double x) {
- return ::abs(x);
- // expected-warning@-1{{using integer absolute value function 'abs' when argument is of floating point type}}
-}
diff --git a/test/SemaCXX/warn-float-conversion.cpp b/test/SemaCXX/warn-float-conversion.cpp
new file mode 100644
index 0000000000..22c33040b2
--- /dev/null
+++ b/test/SemaCXX/warn-float-conversion.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s -Wfloat-conversion
+
+bool ReturnBool(float f) {
+ return f; //expected-warning{{conversion}}
+}
+
+char ReturnChar(float f) {
+ return f; //expected-warning{{conversion}}
+}
+
+int ReturnInt(float f) {
+ return f; //expected-warning{{conversion}}
+}
+
+long ReturnLong(float f) {
+ return f; //expected-warning{{conversion}}
+}
+
+void Convert(float f, double d, long double ld) {
+ bool b;
+ char c;
+ int i;
+ long l;
+
+ b = f; //expected-warning{{conversion}}
+ b = d; //expected-warning{{conversion}}
+ b = ld; //expected-warning{{conversion}}
+ c = f; //expected-warning{{conversion}}
+ c = d; //expected-warning{{conversion}}
+ c = ld; //expected-warning{{conversion}}
+ i = f; //expected-warning{{conversion}}
+ i = d; //expected-warning{{conversion}}
+ i = ld; //expected-warning{{conversion}}
+ l = f; //expected-warning{{conversion}}
+ l = d; //expected-warning{{conversion}}
+ l = ld; //expected-warning{{conversion}}
+}
+
diff --git a/test/SemaCXX/warn-unreachable.cpp b/test/SemaCXX/warn-unreachable.cpp
index 04bd74304b..b08467ab51 100644
--- a/test/SemaCXX/warn-unreachable.cpp
+++ b/test/SemaCXX/warn-unreachable.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fcxx-exceptions -fexceptions -fsyntax-only -verify -fblocks -std=c++11 -Wunreachable-code-aggressive -Wno-unused-value
+// RUN: %clang_cc1 %s -fcxx-exceptions -fexceptions -fsyntax-only -verify -fblocks -std=c++11 -Wunreachable-code-aggressive -Wno-unused-value -Wno-tautological-compare
int &halt() __attribute__((noreturn));
int &live();
@@ -327,3 +327,83 @@ void test_with_paren_silencing(int x) {
calledFun();
}
+void test_with_paren_silencing_impcast(int x) {
+ if (0) calledFun(); // expected-warning {{will never be executed}} expected-note {{silence by adding parentheses to mark code as explicitly dead}}
+ if ((0)) calledFun(); // no-warning
+
+ if (1) // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
+ calledFun();
+ else
+ calledFun(); // expected-warning {{will never be executed}}
+
+ if ((1))
+ calledFun();
+ else
+ calledFun(); // no-warning
+
+ if (!1) // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
+ calledFun(); // expected-warning {{code will never be executed}}
+ else
+ calledFun();
+
+ if ((!1))
+ calledFun(); // no-warning
+ else
+ calledFun();
+
+ if (!(1))
+ calledFun(); // no-warning
+ else
+ calledFun();
+}
+
+void tautological_compare(bool x, int y) {
+ if (x > 10) // expected-note {{silence}}
+ calledFun(); // expected-warning {{will never be executed}}
+ if (10 < x) // expected-note {{silence}}
+ calledFun(); // expected-warning {{will never be executed}}
+ if (x == 10) // expected-note {{silence}}
+ calledFun(); // expected-warning {{will never be executed}}
+
+ if (x < 10) // expected-note {{silence}}
+ calledFun();
+ else
+ calledFun(); // expected-warning {{will never be executed}}
+ if (10 > x) // expected-note {{silence}}
+ calledFun();
+ else
+ calledFun(); // expected-warning {{will never be executed}}
+ if (x != 10) // expected-note {{silence}}
+ calledFun();
+ else
+ calledFun(); // expected-warning {{will never be executed}}
+
+ if (y != 5 && y == 5) // expected-note {{silence}}
+ calledFun(); // expected-warning {{will never be executed}}
+
+ if (y > 5 && y < 4) // expected-note {{silence}}
+ calledFun(); // expected-warning {{will never be executed}}
+
+ if (y < 10 || y > 5) // expected-note {{silence}}
+ calledFun();
+ else
+ calledFun(); // expected-warning {{will never be executed}}
+
+ // TODO: Extend warning to the following code:
+ if (x < -1)
+ calledFun();
+ if (x == -1)
+ calledFun();
+
+ if (x != -1)
+ calledFun();
+ else
+ calledFun();
+ if (-1 > x)
+ calledFun();
+ else
+ calledFun();
+
+ if (y == -1 && y != -1)
+ calledFun();
+}
diff --git a/test/SemaCXX/warn-unused-variables.cpp b/test/SemaCXX/warn-unused-variables.cpp
index ecb36ec274..8dcbe7271d 100644
--- a/test/SemaCXX/warn-unused-variables.cpp
+++ b/test/SemaCXX/warn-unused-variables.cpp
@@ -122,8 +122,19 @@ namespace PR19305 {
template<typename T> const int l = 0; // no warning
int b = l<int>;
+ // PR19558
+ template<typename T> const int o = 0; // no warning
+ template<typename T> const int o<T*> = 0; // no warning
+ int c = o<int*>;
+
+ template<> int o<void> = 0; // no warning
+ int d = o<void>;
+
// FIXME: It'd be nice to warn here.
template<typename T> int m = 0;
+ template<typename T> int m<T*> = 0;
+
+ template<> const int m<void> = 0; // expected-warning {{unused variable}}
}
namespace ctor_with_cleanups {
diff --git a/test/SemaCXX/writable-strings-deprecated.cpp b/test/SemaCXX/writable-strings-deprecated.cpp
index b8f605b63d..f925833498 100644
--- a/test/SemaCXX/writable-strings-deprecated.cpp
+++ b/test/SemaCXX/writable-strings-deprecated.cpp
@@ -1,14 +1,25 @@
// RUN: %clang_cc1 -fsyntax-only -Wno-deprecated-writable-strings -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wno-deprecated -Wdeprecated-increment-bool -verify %s
// RUN: %clang_cc1 -fsyntax-only -fwritable-strings -verify %s
// RUN: %clang_cc1 -fsyntax-only -Wno-write-strings -verify %s
// RUN: %clang_cc1 -fsyntax-only -Werror=c++11-compat -verify %s -DERROR
+// RUN: %clang_cc1 -fsyntax-only -Werror=deprecated -Wno-error=deprecated-increment-bool -verify %s -DERROR
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s -Wno-deprecated -Wdeprecated-increment-bool
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s -pedantic-errors -DERROR
// rdar://8827606
char *fun(void)
{
return "foo";
+#if __cplusplus >= 201103L
#ifdef ERROR
- // expected-error@-2 {{deprecated}}
+ // expected-error@-3 {{ISO C++11 does not allow conversion from string literal to 'char *'}}
+#else
+ // expected-warning@-5 {{ISO C++11 does not allow conversion from string literal to 'char *'}}
+#endif
+#elif defined(ERROR)
+ // expected-error@-8 {{deprecated}}
#endif
}
diff --git a/test/SemaObjC/attr-designated-init.m b/test/SemaObjC/attr-designated-init.m
index 6ef3439006..b52e5c5d4a 100644
--- a/test/SemaObjC/attr-designated-init.m
+++ b/test/SemaObjC/attr-designated-init.m
@@ -142,12 +142,6 @@ __attribute__((objc_root_class))
return [super initB3];
}
-(void)meth {}
--(id)initS1 {
- return 0;
-}
--(id)initS2 {
- return [super initB1];
-}
@end
@interface S6 : B1
@@ -272,7 +266,8 @@ __attribute__((objc_root_class))
// rdar://16323233
__attribute__((objc_root_class))
@interface B4
--(id)initB4 NS_DESIGNATED_INITIALIZER;
+-(id)initB4 NS_DESIGNATED_INITIALIZER; // expected-note 4 {{method marked as designated initializer of the class here}}
+-(id)initNonDI;
@end
@interface rdar16323233 : B4
@@ -291,3 +286,127 @@ __attribute__((objc_root_class))
return [self initS4];
}
@end
+
+@interface S1B4 : B4
+@end
+@implementation S1B4
+-(id)initB4 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
+ return [super initNonDI]; // expected-warning {{designated initializer invoked a non-designated initializer}}
+}
+@end
+
+@interface S2B4 : B4
+-(id)initB4;
+@end
+@implementation S2B4
+-(id)initB4 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
+ return [super initNonDI]; // expected-warning {{designated initializer invoked a non-designated initializer}}
+}
+@end
+
+@interface S3B4 : B4
+@end
+@implementation S3B4
+-(id)initNew {
+ return [super initB4];
+}
+-(id)initB4 {
+ return [self initNew];
+}
+@end
+
+@interface S4B4 : B4
+-(id)initNew;
+@end
+@implementation S4B4
+-(id)initNew {
+ return [super initB4];
+}
+-(id)initB4 {
+ return [self initNew];
+}
+@end
+
+@interface S5B4 : B4
+-(id)initB4;
+@end
+@implementation S5B4
+-(id)initNew {
+ return [super initB4];
+}
+-(id)initB4 {
+ return [self initNew];
+}
+@end
+
+@interface S6B4 : B4
+-(id)initNew;
+-(id)initB4;
+@end
+@implementation S6B4
+-(id)initNew {
+ return [super initB4];
+}
+-(id)initB4 {
+ return [self initNew];
+}
+@end
+
+__attribute__((objc_root_class))
+@interface NSObject
+-(instancetype) init NS_DESIGNATED_INITIALIZER; // expected-note {{method marked as designated initializer of the class here}}
+@end
+
+@interface Test3 : NSObject
+@end
+
+@implementation Test3
+-(instancetype) initWithBasePath:(id)path {
+ return [super init];
+}
+-(instancetype) init {
+ return [self initWithBasePath:0];
+}
+@end
+
+@interface Test1 : NSObject
+-(instancetype) init NS_DESIGNATED_INITIALIZER;
+@end
+@implementation Test1
+-(instancetype) init {
+ return self;
+}
+@end
+
+
+@interface Test2 : NSObject
+@end
+@interface SubTest2 : Test2
+@end
+@implementation SubTest2
+-(instancetype) init { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
+ return self;
+}
+@end
+
+__attribute__((objc_root_class))
+@interface RootNoDI
+-(id)init;
+@end
+
+@interface Base : RootNoDI
+@end
+
+@implementation Base
+@end
+
+@interface Derived : Base
+- (instancetype)initWithInt:(int)n NS_DESIGNATED_INITIALIZER;
+@end
+
+@implementation Derived
+- (instancetype)initWithInt:(int)n
+{
+ return [super init];
+}
+@end
diff --git a/test/SemaObjC/class-property-access.m b/test/SemaObjC/class-property-access.m
index 735b51a3c4..a4c188c434 100644
--- a/test/SemaObjC/class-property-access.m
+++ b/test/SemaObjC/class-property-access.m
@@ -11,3 +11,46 @@ int main ()
return Test.one.two;
}
+// rdar://16650575
+__attribute__((objc_root_class))
+@interface RootClass {
+ Class isa;
+}
+
+@property int property;
+-(int)method;
+- (void) setMethod : (int)arg;
++(int)classMethod;
+@end
+
+@interface Subclass : RootClass @end
+void Test1() {
+ // now okay
+ (void)RootClass.property;
+ (void)Subclass.property;
+ (void)RootClass.method;
+ (void)Subclass.method;
+
+ RootClass.property = 1;
+ Subclass.property = 2;
+ RootClass.method = 3;
+ Subclass.method = 4;
+
+ // okay
+ (void)RootClass.classMethod;
+ (void)Subclass.classMethod;
+
+ // also okay
+ [RootClass property];
+ [Subclass property];
+ [RootClass method];
+ [Subclass method];
+ [RootClass classMethod];
+ [Subclass classMethod];
+
+ // also okay
+ [RootClass setProperty : 1];
+ [Subclass setProperty : 2];
+ [RootClass setMethod : 3];
+ [Subclass setMethod : 4];
+}
diff --git a/test/SemaObjC/encode-typeof-test.m b/test/SemaObjC/encode-typeof-test.m
new file mode 100644
index 0000000000..2cda973968
--- /dev/null
+++ b/test/SemaObjC/encode-typeof-test.m
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// rdar://16655340
+@protocol X, Y, Z;
+@class Foo;
+
+@protocol Proto
+@end
+
+@interface Intf <Proto>
+{
+id <X> IVAR_x;
+id <X, Y> IVAR_xy;
+id <X, Y, Z> IVAR_xyz;
+Foo <X, Y, Z> *IVAR_Fooxyz;
+Class <X> IVAR_Classx;
+}
+@end
+
+@implementation Intf
+@end
+
+int main()
+{
+ int i;
+ typeof(@encode(typeof(i))) e = @encode(typeof(Intf)); // expected-warning {{initializer-string for char array is too long}}
+}
diff --git a/test/SemaObjC/objcbridge-attribute-arc.m b/test/SemaObjC/objcbridge-attribute-arc.m
index b2830ff82d..194f8d5719 100644
--- a/test/SemaObjC/objcbridge-attribute-arc.m
+++ b/test/SemaObjC/objcbridge-attribute-arc.m
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -x objective-c -fobjc-arc -verify -Wno-objc-root-class %s
// rdar://15454846
-typedef struct __attribute__ ((objc_bridge(NSError))) __CFErrorRef * CFErrorRef; // expected-note 7 {{declared here}}
+typedef struct __attribute__ ((objc_bridge(NSError))) __CFErrorRef * CFErrorRef; // expected-note 5 {{declared here}}
-typedef struct __attribute__ ((objc_bridge(MyError))) __CFMyErrorRef * CFMyErrorRef; // expected-note 3 {{declared here}}
+typedef struct __attribute__ ((objc_bridge(MyError))) __CFMyErrorRef * CFMyErrorRef; // expected-note 1 {{declared here}}
typedef struct __attribute__((objc_bridge(12))) __CFMyColor *CFMyColorRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}}
@@ -53,9 +53,9 @@ typedef CFErrorRef1 CFErrorRef2; // expected-note 2 {{declared here}}
@protocol P4 @end
@protocol P5 @end
-@interface NSError<P1, P2, P3> @end // expected-note 7 {{declared here}}
+@interface NSError<P1, P2, P3> @end // expected-note 5 {{declared here}}
-@interface MyError : NSError // expected-note 3 {{declared here}}
+@interface MyError : NSError // expected-note 1 {{declared here}}
@end
@interface NSUColor @end
@@ -64,9 +64,9 @@ typedef CFErrorRef1 CFErrorRef2; // expected-note 2 {{declared here}}
void Test2(CFErrorRef2 cf, NSError *ns, NSString *str, Class c, CFUColor2Ref cf2) {
(void)(NSString *)cf; // expected-warning {{'CFErrorRef2' (aka 'struct __CFErrorRef *') bridges to NSError, not 'NSString'}}
- (void)(NSError *)cf; // okay
- (void)(MyError*)cf; // okay,
- (void)(NSUColor *)cf2; // okay
+ (void)(NSError *)cf; // expected-error {{under ARC 'CFErrorRef2' (aka 'struct __CFErrorRef *') bridges to NSError, but it still requires an explicit bridge cast}}
+ (void)(MyError*)cf; // expected-error {{under ARC 'CFErrorRef2' (aka 'struct __CFErrorRef *') bridges to NSError, but it still requires an explicit bridge cast}}
+ (void)(NSUColor *)cf2; // expected-error {{under ARC 'CFUColor2Ref' (aka 'union __CFUPrimeColor *') bridges to NSUColor, but it still requires an explicit bridge cast}}
(void)(CFErrorRef)ns; // okay
(void)(CFErrorRef)str; // expected-warning {{'NSString' cannot bridge to 'CFErrorRef' (aka 'struct __CFErrorRef *')}}
(void)(Class)cf; // expected-warning {{'CFErrorRef2' (aka 'struct __CFErrorRef *') bridges to NSError, not 'Class'}}
@@ -92,8 +92,8 @@ void Test5(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12,
(void)(CFErrorRef)ID; // ok
(void)(CFErrorRef)P123; // ok
(void)(CFErrorRef)P1234; // ok
- (void)(CFErrorRef)P12; // expected-warning {{'id<P1,P2>' cannot bridge to 'CFErrorRef' (aka 'struct __CFErrorRef *')}}
- (void)(CFErrorRef)P23; // expected-warning {{'id<P2,P3>' cannot bridge to 'CFErrorRef' (aka 'struct __CFErrorRef *')}}
+ (void)(CFErrorRef)P12;
+ (void)(CFErrorRef)P23;
}
void Test6(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12, id<P2, P3> P23) {
@@ -101,21 +101,21 @@ void Test6(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12,
(void)(CFMyErrorRef)ID; // ok
(void)(CFMyErrorRef)P123; // ok
(void)(CFMyErrorRef)P1234; // ok
- (void)(CFMyErrorRef)P12; // expected-warning {{'id<P1,P2>' cannot bridge to 'CFMyErrorRef' (aka 'struct __CFMyErrorRef *')}}
- (void)(CFMyErrorRef)P23; // expected-warning {{'id<P2,P3>' cannot bridge to 'CFMyErrorRef' (aka 'struct __CFMyErrorRef *')}}
+ (void)(CFMyErrorRef)P12; // ok
+ (void)(CFMyErrorRef)P23; // ok
}
-typedef struct __attribute__ ((objc_bridge(MyPersonalError))) __CFMyPersonalErrorRef * CFMyPersonalErrorRef; // expected-note 4 {{declared here}}
+typedef struct __attribute__ ((objc_bridge(MyPersonalError))) __CFMyPersonalErrorRef * CFMyPersonalErrorRef; // expected-note 1 {{declared here}}
-@interface MyPersonalError : NSError <P4> // expected-note 4 {{declared here}}
+@interface MyPersonalError : NSError <P4> // expected-note 1 {{declared here}}
@end
void Test7(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12, id<P2, P3> P23) {
(void)(CFMyPersonalErrorRef)ID; // ok
- (void)(CFMyPersonalErrorRef)P123; // expected-warning {{'id<P1,P2,P3>' cannot bridge to 'CFMyPersonalErrorRef' (aka 'struct __CFMyPersonalErrorRef *')}}
+ (void)(CFMyPersonalErrorRef)P123; // ok
(void)(CFMyPersonalErrorRef)P1234; // ok
- (void)(CFMyPersonalErrorRef)P12; // expected-warning {{'id<P1,P2>' cannot bridge to 'CFMyPersonalErrorRef' (aka 'struct __CFMyPersonalErrorRef *')}}
- (void)(CFMyPersonalErrorRef)P23; // expected-warning {{'id<P2,P3>' cannot bridge to 'CFMyPersonalErrorRef' (aka 'struct __CFMyPersonalErrorRef *')}}
+ (void)(CFMyPersonalErrorRef)P12; // ok
+ (void)(CFMyPersonalErrorRef)P23; // ok
}
void Test8(CFMyPersonalErrorRef cf) {
diff --git a/test/SemaObjC/objcbridge-attribute.m b/test/SemaObjC/objcbridge-attribute.m
index 36b3d604c7..b4d847073d 100644
--- a/test/SemaObjC/objcbridge-attribute.m
+++ b/test/SemaObjC/objcbridge-attribute.m
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
// rdar://15454846
-typedef struct __attribute__ ((objc_bridge(NSError))) __CFErrorRef * CFErrorRef; // expected-note 5 {{declared here}}
+typedef struct __attribute__ ((objc_bridge(NSError))) __CFErrorRef * CFErrorRef; // expected-note 3 {{declared here}}
-typedef struct __attribute__ ((objc_bridge(MyError))) __CFMyErrorRef * CFMyErrorRef; // expected-note 3 {{declared here}}
+typedef struct __attribute__ ((objc_bridge(MyError))) __CFMyErrorRef * CFMyErrorRef; // expected-note 1 {{declared here}}
typedef struct __attribute__((objc_bridge(12))) __CFMyColor *CFMyColorRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}}
@@ -53,9 +53,9 @@ typedef CFErrorRef1 CFErrorRef2; // expected-note {{declared here}}
@protocol P4 @end
@protocol P5 @end
-@interface NSError<P1, P2, P3> @end // expected-note 5 {{declared here}}
+@interface NSError<P1, P2, P3> @end // expected-note 3 {{declared here}}
-@interface MyError : NSError // expected-note 3 {{declared here}}
+@interface MyError : NSError // expected-note 1 {{declared here}}
@end
@interface NSUColor @end
@@ -92,8 +92,8 @@ void Test5(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12,
(void)(CFErrorRef)ID; // ok
(void)(CFErrorRef)P123; // ok
(void)(CFErrorRef)P1234; // ok
- (void)(CFErrorRef)P12; // expected-warning {{'id<P1,P2>' cannot bridge to 'CFErrorRef' (aka 'struct __CFErrorRef *')}}
- (void)(CFErrorRef)P23; // expected-warning {{'id<P2,P3>' cannot bridge to 'CFErrorRef' (aka 'struct __CFErrorRef *')}}
+ (void)(CFErrorRef)P12; // ok
+ (void)(CFErrorRef)P23; // ok
}
void Test6(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12, id<P2, P3> P23) {
@@ -101,21 +101,21 @@ void Test6(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12,
(void)(CFMyErrorRef)ID; // ok
(void)(CFMyErrorRef)P123; // ok
(void)(CFMyErrorRef)P1234; // ok
- (void)(CFMyErrorRef)P12; // expected-warning {{'id<P1,P2>' cannot bridge to 'CFMyErrorRef' (aka 'struct __CFMyErrorRef *')}}
- (void)(CFMyErrorRef)P23; // expected-warning {{'id<P2,P3>' cannot bridge to 'CFMyErrorRef' (aka 'struct __CFMyErrorRef *')}}
+ (void)(CFMyErrorRef)P12; // ok
+ (void)(CFMyErrorRef)P23; // ok
}
-typedef struct __attribute__ ((objc_bridge(MyPersonalError))) __CFMyPersonalErrorRef * CFMyPersonalErrorRef; // expected-note 4 {{declared here}}
+typedef struct __attribute__ ((objc_bridge(MyPersonalError))) __CFMyPersonalErrorRef * CFMyPersonalErrorRef; // expected-note 1 {{declared here}}
-@interface MyPersonalError : NSError <P4> // expected-note 4 {{declared here}}
+@interface MyPersonalError : NSError <P4> // expected-note 1 {{declared here}}
@end
void Test7(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12, id<P2, P3> P23) {
(void)(CFMyPersonalErrorRef)ID; // ok
- (void)(CFMyPersonalErrorRef)P123; // expected-warning {{'id<P1,P2,P3>' cannot bridge to 'CFMyPersonalErrorRef' (aka 'struct __CFMyPersonalErrorRef *')}}
+ (void)(CFMyPersonalErrorRef)P123; // ok
(void)(CFMyPersonalErrorRef)P1234; // ok
- (void)(CFMyPersonalErrorRef)P12; // expected-warning {{'id<P1,P2>' cannot bridge to 'CFMyPersonalErrorRef' (aka 'struct __CFMyPersonalErrorRef *')}}
- (void)(CFMyPersonalErrorRef)P23; // expected-warning {{'id<P2,P3>' cannot bridge to 'CFMyPersonalErrorRef' (aka 'struct __CFMyPersonalErrorRef *')}}
+ (void)(CFMyPersonalErrorRef)P12; // ok
+ (void)(CFMyPersonalErrorRef)P23; // ok
}
void Test8(CFMyPersonalErrorRef cf) {
diff --git a/test/SemaObjCXX/lit.local.cfg b/test/SemaObjCXX/lit.local.cfg
new file mode 100644
index 0000000000..f4ef5d2fa0
--- /dev/null
+++ b/test/SemaObjCXX/lit.local.cfg
@@ -0,0 +1,4 @@
+config.substitutions = list(config.substitutions)
+config.substitutions.insert(0,
+ (r'%clang\b',
+ """*** Do not use the driver in Sema tests. ***""") )
diff --git a/test/SemaObjCXX/objcbridge-attribute-arc.mm b/test/SemaObjCXX/objcbridge-attribute-arc.mm
index 39cba2a842..4224854a69 100644
--- a/test/SemaObjCXX/objcbridge-attribute-arc.mm
+++ b/test/SemaObjCXX/objcbridge-attribute-arc.mm
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -x objective-c++ -fobjc-arc -verify -Wno-objc-root-class %s
// rdar://15454846
-typedef struct __attribute__ ((objc_bridge(NSError))) __CFErrorRef * CFErrorRef; // expected-note 7 {{declared here}}
+typedef struct __attribute__ ((objc_bridge(NSError))) __CFErrorRef * CFErrorRef; // expected-note 5 {{declared here}}
-typedef struct __attribute__ ((objc_bridge(MyError))) __CFMyErrorRef * CFMyErrorRef; // expected-note 3 {{declared here}}
+typedef struct __attribute__ ((objc_bridge(MyError))) __CFMyErrorRef * CFMyErrorRef; // expected-note 1 {{declared here}}
typedef struct __attribute__((objc_bridge(12))) __CFMyColor *CFMyColorRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}}
@@ -53,9 +53,9 @@ typedef CFErrorRef1 CFErrorRef2; // expected-note 2 {{declared here}}
@protocol P4 @end
@protocol P5 @end
-@interface NSError<P1, P2, P3> @end // expected-note 7 {{declared here}}
+@interface NSError<P1, P2, P3> @end // expected-note 5 {{declared here}}
-@interface MyError : NSError // expected-note 3 {{declared here}}
+@interface MyError : NSError // expected-note 1 {{declared here}}
@end
@interface NSUColor @end
@@ -64,9 +64,9 @@ typedef CFErrorRef1 CFErrorRef2; // expected-note 2 {{declared here}}
void Test2(CFErrorRef2 cf, NSError *ns, NSString *str, Class c, CFUColor2Ref cf2) {
(void)(NSString *)cf; // expected-warning {{'CFErrorRef2' (aka '__CFErrorRef *') bridges to NSError, not 'NSString'}}
- (void)(NSError *)cf; // okay
- (void)(MyError*)cf; // okay,
- (void)(NSUColor *)cf2; // okay
+ (void)(NSError *)cf; // expected-error {{under ARC 'CFErrorRef2' (aka '__CFErrorRef *') bridges to NSError, but it still requires an explicit bridge cast}}
+ (void)(MyError*)cf; // expected-error {{under ARC 'CFErrorRef2' (aka '__CFErrorRef *') bridges to NSError, but it still requires an explicit bridge cast}},
+ (void)(NSUColor *)cf2; // expected-error {{under ARC 'CFUColor2Ref' (aka '__CFUPrimeColor *') bridges to NSUColor, but it still requires an explicit bridge cast}}
(void)(CFErrorRef)ns; // okay
(void)(CFErrorRef)str; // expected-warning {{'NSString' cannot bridge to 'CFErrorRef' (aka '__CFErrorRef *')}}
(void)(Class)cf; // expected-warning {{'CFErrorRef2' (aka '__CFErrorRef *') bridges to NSError, not 'Class'}}
@@ -92,8 +92,8 @@ void Test5(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12,
(void)(CFErrorRef)ID; // ok
(void)(CFErrorRef)P123; // ok
(void)(CFErrorRef)P1234; // ok
- (void)(CFErrorRef)P12; // expected-warning {{'id<P1,P2>' cannot bridge to 'CFErrorRef' (aka '__CFErrorRef *')}}
- (void)(CFErrorRef)P23; // expected-warning {{'id<P2,P3>' cannot bridge to 'CFErrorRef' (aka '__CFErrorRef *')}}
+ (void)(CFErrorRef)P12;
+ (void)(CFErrorRef)P23;
}
void Test6(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12, id<P2, P3> P23) {
@@ -101,21 +101,21 @@ void Test6(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12,
(void)(CFMyErrorRef)ID; // ok
(void)(CFMyErrorRef)P123; // ok
(void)(CFMyErrorRef)P1234; // ok
- (void)(CFMyErrorRef)P12; // expected-warning {{'id<P1,P2>' cannot bridge to 'CFMyErrorRef' (aka '__CFMyErrorRef *')}}
- (void)(CFMyErrorRef)P23; // expected-warning {{'id<P2,P3>' cannot bridge to 'CFMyErrorRef' (aka '__CFMyErrorRef *')}}
+ (void)(CFMyErrorRef)P12; // ok
+ (void)(CFMyErrorRef)P23; // ok
}
-typedef struct __attribute__ ((objc_bridge(MyPersonalError))) __CFMyPersonalErrorRef * CFMyPersonalErrorRef; // expected-note 4 {{declared here}}
+typedef struct __attribute__ ((objc_bridge(MyPersonalError))) __CFMyPersonalErrorRef * CFMyPersonalErrorRef; // expected-note 1 {{declared here}}
-@interface MyPersonalError : NSError <P4> // expected-note 4 {{declared here}}
+@interface MyPersonalError : NSError <P4> // expected-note 1 {{declared here}}
@end
void Test7(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12, id<P2, P3> P23) {
(void)(CFMyPersonalErrorRef)ID; // ok
- (void)(CFMyPersonalErrorRef)P123; // expected-warning {{'id<P1,P2,P3>' cannot bridge to 'CFMyPersonalErrorRef' (aka '__CFMyPersonalErrorRef *')}}
+ (void)(CFMyPersonalErrorRef)P123; // ok
(void)(CFMyPersonalErrorRef)P1234; // ok
- (void)(CFMyPersonalErrorRef)P12; // expected-warning {{'id<P1,P2>' cannot bridge to 'CFMyPersonalErrorRef' (aka '__CFMyPersonalErrorRef *')}}
- (void)(CFMyPersonalErrorRef)P23; // expected-warning {{'id<P2,P3>' cannot bridge to 'CFMyPersonalErrorRef' (aka '__CFMyPersonalErrorRef *')}}
+ (void)(CFMyPersonalErrorRef)P12; // ok
+ (void)(CFMyPersonalErrorRef)P23; // ok
}
void Test8(CFMyPersonalErrorRef cf) {
diff --git a/test/SemaObjCXX/objcbridge-attribute.mm b/test/SemaObjCXX/objcbridge-attribute.mm
index d7a9c65da8..698cf4c957 100644
--- a/test/SemaObjCXX/objcbridge-attribute.mm
+++ b/test/SemaObjCXX/objcbridge-attribute.mm
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -x objective-c++ -verify -Wno-objc-root-class %s
// rdar://15454846
-typedef struct __attribute__ ((objc_bridge(NSError))) __CFErrorRef * CFErrorRef; // expected-note 5 {{declared here}}
+typedef struct __attribute__ ((objc_bridge(NSError))) __CFErrorRef * CFErrorRef; // expected-note 3 {{declared here}}
-typedef struct __attribute__ ((objc_bridge(MyError))) __CFMyErrorRef * CFMyErrorRef; // expected-note 3 {{declared here}}
+typedef struct __attribute__ ((objc_bridge(MyError))) __CFMyErrorRef * CFMyErrorRef; // expected-note 1 {{declared here}}
typedef struct __attribute__((objc_bridge(12))) __CFMyColor *CFMyColorRef; // expected-error {{parameter of 'objc_bridge' attribute must be a single name of an Objective-C class}}
@@ -53,9 +53,9 @@ typedef CFErrorRef1 CFErrorRef2; // expected-note {{declared here}}
@protocol P4 @end
@protocol P5 @end
-@interface NSError<P1, P2, P3> @end // expected-note 5 {{declared here}}
+@interface NSError<P1, P2, P3> @end // expected-note 3 {{declared here}}
-@interface MyError : NSError // expected-note 3 {{declared here}}
+@interface MyError : NSError // expected-note 1 {{declared here}}
@end
@interface NSUColor @end
@@ -92,8 +92,8 @@ void Test5(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12,
(void)(CFErrorRef)ID; // ok
(void)(CFErrorRef)P123; // ok
(void)(CFErrorRef)P1234; // ok
- (void)(CFErrorRef)P12; // expected-warning {{'id<P1,P2>' cannot bridge to 'CFErrorRef' (aka '__CFErrorRef *')}}
- (void)(CFErrorRef)P23; // expected-warning {{'id<P2,P3>' cannot bridge to 'CFErrorRef' (aka '__CFErrorRef *')}}
+ (void)(CFErrorRef)P12; // ok
+ (void)(CFErrorRef)P23; // ok
}
void Test6(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12, id<P2, P3> P23) {
@@ -101,21 +101,21 @@ void Test6(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12,
(void)(CFMyErrorRef)ID; // ok
(void)(CFMyErrorRef)P123; // ok
(void)(CFMyErrorRef)P1234; // ok
- (void)(CFMyErrorRef)P12; // expected-warning {{'id<P1,P2>' cannot bridge to 'CFMyErrorRef' (aka '__CFMyErrorRef *')}}
- (void)(CFMyErrorRef)P23; // expected-warning {{'id<P2,P3>' cannot bridge to 'CFMyErrorRef' (aka '__CFMyErrorRef *')}}
+ (void)(CFMyErrorRef)P12; // ok
+ (void)(CFMyErrorRef)P23; // ok
}
-typedef struct __attribute__ ((objc_bridge(MyPersonalError))) __CFMyPersonalErrorRef * CFMyPersonalErrorRef; // expected-note 4 {{declared here}}
+typedef struct __attribute__ ((objc_bridge(MyPersonalError))) __CFMyPersonalErrorRef * CFMyPersonalErrorRef; // expected-note 1 {{declared here}}
-@interface MyPersonalError : NSError <P4> // expected-note 4 {{declared here}}
+@interface MyPersonalError : NSError <P4> // expected-note 1 {{declared here}}
@end
void Test7(id<P1, P2, P3> P123, id ID, id<P1, P2, P3, P4> P1234, id<P1, P2> P12, id<P2, P3> P23) {
(void)(CFMyPersonalErrorRef)ID; // ok
- (void)(CFMyPersonalErrorRef)P123; // expected-warning {{'id<P1,P2,P3>' cannot bridge to 'CFMyPersonalErrorRef' (aka '__CFMyPersonalErrorRef *')}}
+ (void)(CFMyPersonalErrorRef)P123; // ok
(void)(CFMyPersonalErrorRef)P1234; // ok
- (void)(CFMyPersonalErrorRef)P12; // expected-warning {{'id<P1,P2>' cannot bridge to 'CFMyPersonalErrorRef' (aka '__CFMyPersonalErrorRef *')}}
- (void)(CFMyPersonalErrorRef)P23; // expected-warning {{'id<P2,P3>' cannot bridge to 'CFMyPersonalErrorRef' (aka '__CFMyPersonalErrorRef *')}}
+ (void)(CFMyPersonalErrorRef)P12; // ok
+ (void)(CFMyPersonalErrorRef)P23; // ok
}
void Test8(CFMyPersonalErrorRef cf) {
diff --git a/test/SemaOpenCL/array-parameters.cl b/test/SemaOpenCL/array-parameters.cl
new file mode 100644
index 0000000000..200acacfad
--- /dev/null
+++ b/test/SemaOpenCL/array-parameters.cl
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+// expected-no-diagnostics
+
+kernel void foo(global int a[], local int b[], constant int c[4]) { }
+
+void bar(global int a[], local int b[], constant int c[4], int d[]) { }
diff --git a/test/SemaOpenCL/invalid-kernel.cl b/test/SemaOpenCL/invalid-kernel.cl
index df73eddc3b..9a50673ecd 100644
--- a/test/SemaOpenCL/invalid-kernel.cl
+++ b/test/SemaOpenCL/invalid-kernel.cl
@@ -4,6 +4,8 @@ kernel void no_ptrptr(global int **i) { } // expected-error{{kernel parameter ca
__kernel void no_privateptr(__private int *i) { } // expected-error {{kernel parameter cannot be declared as a pointer to the __private address space}}
+__kernel void no_privatearray(__private int i[]) { } // expected-error {{kernel parameter cannot be declared as a pointer to the __private address space}}
+
kernel int bar() { // expected-error {{kernel must have void return type}}
return 6;
}
diff --git a/test/SemaOpenCL/lit.local.cfg b/test/SemaOpenCL/lit.local.cfg
new file mode 100644
index 0000000000..f4ef5d2fa0
--- /dev/null
+++ b/test/SemaOpenCL/lit.local.cfg
@@ -0,0 +1,4 @@
+config.substitutions = list(config.substitutions)
+config.substitutions.insert(0,
+ (r'%clang\b',
+ """*** Do not use the driver in Sema tests. ***""") )
diff --git a/test/SemaOpenCL/vector_conv_invalid.cl b/test/SemaOpenCL/vector_conv_invalid.cl
index e6ef5a492f..90cec26a60 100644
--- a/test/SemaOpenCL/vector_conv_invalid.cl
+++ b/test/SemaOpenCL/vector_conv_invalid.cl
@@ -7,8 +7,8 @@ typedef unsigned uint3 __attribute((ext_vector_type(3)));
void vector_conv_invalid() {
uint4 u = (uint4)(1);
- int4 i = u; // expected-error{{initializing 'int4' with an expression of incompatible type 'uint4'}}
- int4 e = (int4)u; // expected-error{{invalid conversion between ext-vector type 'int4' and 'uint4'}}
+ int4 i = u; // expected-error{{initializing 'int4' (vector of 4 'int' values) with an expression of incompatible type 'uint4' (vector of 4 'unsigned int' values)}}
+ int4 e = (int4)u; // expected-error{{invalid conversion between ext-vector type 'int4' (vector of 4 'int' values) and 'uint4' (vector of 4 'unsigned int' values)}}
- uint3 u4 = (uint3)u; // expected-error{{invalid conversion between ext-vector type 'uint3' and 'uint4'}}
+ uint3 u4 = (uint3)u; // expected-error{{invalid conversion between ext-vector type 'uint3' (vector of 3 'unsigned int' values) and 'uint4' (vector of 4 'unsigned int' values)}}
}
diff --git a/test/SemaTemplate/explicit-specialization-member.cpp b/test/SemaTemplate/explicit-specialization-member.cpp
index 07d7389446..e8dc4d219a 100644
--- a/test/SemaTemplate/explicit-specialization-member.cpp
+++ b/test/SemaTemplate/explicit-specialization-member.cpp
@@ -38,12 +38,22 @@ namespace PR18246 {
template<typename T>
template<int N>
- void Baz<T>::bar() {
+ void Baz<T>::bar() { // expected-note {{couldn't infer template argument 'N'}}
}
- // FIXME: Don't suggest the 'template<>' correction here, because this cannot
- // be an explicit specialization.
+ // FIXME: We shouldn't try to match this against a prior declaration if
+ // template parameter matching failed.
template<typename T>
- void Baz<T>::bar<0>() { // expected-error {{requires 'template<>'}}
+ void Baz<T>::bar<0>() { // expected-error {{cannot specialize a member of an unspecialized template}} \
+ // expected-error {{no function template matches}}
}
}
+
+namespace PR19340 {
+template<typename T> struct Helper {
+ template<int N> static void func(const T *m) {} // expected-note {{failed template argument deduction}}
+};
+
+template<typename T> void Helper<T>::func<2>() {} // expected-error {{cannot specialize a member}} \
+ // expected-error {{no function template matches}}
+}
diff --git a/test/VFS/Inputs/Foo.framework/Headers/Foo.h b/test/VFS/Inputs/Foo.framework/Headers/Foo.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/VFS/Inputs/Foo.framework/Headers/Foo.h
diff --git a/test/VFS/Inputs/Foo.framework/Modules/module.modulemap b/test/VFS/Inputs/Foo.framework/Modules/module.modulemap
new file mode 100644
index 0000000000..0aab69f0af
--- /dev/null
+++ b/test/VFS/Inputs/Foo.framework/Modules/module.modulemap
@@ -0,0 +1,3 @@
+framework module Foo {
+ umbrella header "Foo.h"
+}
diff --git a/test/VFS/Inputs/Foo.h b/test/VFS/Inputs/Foo.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/VFS/Inputs/Foo.h
diff --git a/test/VFS/Inputs/actual_module2.map b/test/VFS/Inputs/actual_module2.map
new file mode 100644
index 0000000000..24f860299f
--- /dev/null
+++ b/test/VFS/Inputs/actual_module2.map
@@ -0,0 +1,5 @@
+module not_real {
+ header "not_real.h"
+ export *
+ explicit module from_second_vfs { }
+}
diff --git a/test/VFS/Inputs/vfsoverlay.yaml b/test/VFS/Inputs/vfsoverlay.yaml
index 331ed33316..5c1380870d 100644
--- a/test/VFS/Inputs/vfsoverlay.yaml
+++ b/test/VFS/Inputs/vfsoverlay.yaml
@@ -14,6 +14,9 @@
},
{ 'name': 'SomeFramework.framework/Headers/public_header.h', 'type': 'file',
'external-contents': 'INPUT_DIR/public_header.h'
+ },
+ { 'name': 'Foo.framework/Headers/Foo.h', 'type': 'file',
+ 'external-contents': 'INPUT_DIR/Foo.h'
}
]
}
diff --git a/test/VFS/Inputs/vfsoverlay2.yaml b/test/VFS/Inputs/vfsoverlay2.yaml
new file mode 100644
index 0000000000..ae2a0ce4ec
--- /dev/null
+++ b/test/VFS/Inputs/vfsoverlay2.yaml
@@ -0,0 +1,12 @@
+{
+ 'version': 0,
+ 'roots': [
+ { 'name': 'OUT_DIR', 'type': 'directory',
+ 'contents': [
+ { 'name': 'module.map', 'type': 'file',
+ 'external-contents': 'INPUT_DIR/actual_module2.map'
+ }
+ ]
+ }
+ ]
+}
diff --git a/test/VFS/module-import.m b/test/VFS/module-import.m
index 3cfd906d76..d2adcfedfa 100644
--- a/test/VFS/module-import.m
+++ b/test/VFS/module-import.m
@@ -8,3 +8,20 @@
void foo() {
bar();
}
+
+// Import a submodule that is defined in actual_module2.map, which is only
+// mapped in vfsoverlay2.yaml.
+#ifdef IMPORT2
+@import not_real.from_second_module;
+// CHECK-VFS2: error: no submodule
+#endif
+
+// Override the module map (vfsoverlay2 on top)
+// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%t:g" %S/Inputs/vfsoverlay2.yaml > %t2.yaml
+// RUN: %clang_cc1 -Werror -fmodules -fmodules-cache-path=%t -ivfsoverlay %t.yaml -ivfsoverlay %t2.yaml -I %t -fsyntax-only %s
+
+// vfsoverlay2 not present
+// RUN: not %clang_cc1 -Werror -fmodules -fmodules-cache-path=%t -ivfsoverlay %t.yaml -I %t -fsyntax-only %s -DIMPORT2 2>&1 | FileCheck -check-prefix=CHECK-VFS2 %s
+
+// vfsoverlay2 on the bottom
+// RUN: not %clang_cc1 -Werror -fmodules -fmodules-cache-path=%t -ivfsoverlay %t2.yaml -ivfsoverlay %t.yaml -I %t -fsyntax-only %s -DIMPORT2 2>&1 | FileCheck -check-prefix=CHECK-VFS2 %s
diff --git a/test/VFS/umbrella-mismatch.m b/test/VFS/umbrella-mismatch.m
new file mode 100644
index 0000000000..c73129448c
--- /dev/null
+++ b/test/VFS/umbrella-mismatch.m
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t
+// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%S/Inputs:g" %S/Inputs/vfsoverlay.yaml > %t.yaml
+// REQUIRES: shell
+
+// RUN: %clang_cc1 -Werror -fmodules -fmodules-cache-path=%t -ivfsoverlay %t.yaml -F %S/Inputs -fsyntax-only %s -verify
+// RUN: %clang_cc1 -Werror -fmodules -fmodules-cache-path=%t -F %S/Inputs -fsyntax-only %s -verify
+// expected-no-diagnostics
+@import Foo;
diff --git a/tools/c-arcmt-test/Makefile b/tools/c-arcmt-test/Makefile
index 6ac5e20fe4..0be3bc136e 100644
--- a/tools/c-arcmt-test/Makefile
+++ b/tools/c-arcmt-test/Makefile
@@ -27,9 +27,12 @@ LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
# when -static is given to linker on cygming.
USEDLIBS = clang.a \
clangARCMigrate.a \
+ clangIndex.a \
+ clangFormat.a \
+ clangTooling.a \
clangRewriteFrontend.a \
clangRewriteCore.a \
- clangIndex.a clangFrontend.a clangDriver.a \
+ clangFrontend.a clangDriver.a \
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
clangSerialization.a clangParse.a clangSema.a \
clangAnalysis.a clangEdit.a clangAST.a clangLex.a clangBasic.a
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index f6b5510292..ae2b81b2c5 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -3,6 +3,7 @@
#include "clang-c/Index.h"
#include "clang-c/CXCompilationDatabase.h"
#include "clang-c/BuildSystem.h"
+#include "clang-c/Documentation.h"
#include "llvm/Config/config.h"
#include <ctype.h>
#include <stdlib.h>
@@ -768,6 +769,8 @@ static void PrintCursor(CXCursor Cursor,
printf(" (static)");
if (clang_CXXMethod_isVirtual(Cursor))
printf(" (virtual)");
+ if (clang_CXXMethod_isConst(Cursor))
+ printf(" (const)");
if (clang_CXXMethod_isPureVirtual(Cursor))
printf(" (pure)");
if (clang_Cursor_isVariadic(Cursor))
@@ -1293,6 +1296,13 @@ static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p,
}
/* Print if this is a non-POD type. */
printf(" [isPOD=%d]", clang_isPODType(T));
+ /* Print the pointee type. */
+ {
+ CXType PT = clang_getPointeeType(T);
+ if (PT.kind != CXType_Invalid) {
+ PrintTypeAndTypeKind(PT, " [pointeetype=%s] [pointeekind=%s]");
+ }
+ }
printf("\n");
}
@@ -1324,18 +1334,25 @@ static enum CXChildVisitResult PrintTypeSize(CXCursor cursor, CXCursor p,
}
/* Print the record field offset if applicable. */
{
- const char *FieldName = clang_getCString(clang_getCursorSpelling(cursor));
+ CXString FieldSpelling = clang_getCursorSpelling(cursor);
+ const char *FieldName = clang_getCString(FieldSpelling);
/* recurse to get the root anonymous record parent */
CXCursor Parent, Root;
- if (clang_getCursorKind(cursor) == CXCursor_FieldDecl ) {
- const char *RootParentName;
+ if (clang_getCursorKind(cursor) == CXCursor_FieldDecl) {
+ CXString RootParentSpelling;
+ const char *RootParentName = 0;
Parent = p;
do {
+ if (RootParentName != 0)
+ clang_disposeString(RootParentSpelling);
+
Root = Parent;
- RootParentName = clang_getCString(clang_getCursorSpelling(Root));
+ RootParentSpelling = clang_getCursorSpelling(Root);
+ RootParentName = clang_getCString(RootParentSpelling);
Parent = clang_getCursorSemanticParent(Root);
- } while ( clang_getCursorType(Parent).kind == CXType_Record &&
- !strcmp(RootParentName, "") );
+ } while (clang_getCursorType(Parent).kind == CXType_Record &&
+ !strcmp(RootParentName, ""));
+ clang_disposeString(RootParentSpelling);
/* if RootParentName is "", record is anonymous. */
{
long long Offset = clang_Type_getOffsetOf(clang_getCursorType(Root),
@@ -1343,6 +1360,7 @@ static enum CXChildVisitResult PrintTypeSize(CXCursor cursor, CXCursor p,
printf(" [offsetof=%lld]", Offset);
}
}
+ clang_disposeString(FieldSpelling);
}
/* Print if its a bitfield */
{
@@ -3736,7 +3754,6 @@ static const char *getDiagnosticCodeStr(enum CXLoadDiag_Error error) {
static const char *getSeverityString(enum CXDiagnosticSeverity severity) {
switch (severity) {
case CXDiagnostic_Note: return "note";
- case CXDiagnostic_Remark: return "remark";
case CXDiagnostic_Error: return "error";
case CXDiagnostic_Fatal: return "fatal";
case CXDiagnostic_Ignored: return "ignored";
diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp
index 4fc970c0d1..cc8d43cec2 100644
--- a/tools/clang-check/ClangCheck.cpp
+++ b/tools/clang-check/ClangCheck.cpp
@@ -215,7 +215,7 @@ int main(int argc, const char **argv) {
Analyze ? "--analyze" : "-fsyntax-only", InsertAdjuster::BEGIN));
clang_check::ClangCheckActionFactory CheckFactory;
- FrontendActionFactory *FrontendFactory;
+ std::unique_ptr<FrontendActionFactory> FrontendFactory;
// Choose the correct factory based on the selected mode.
if (Analyze)
@@ -225,5 +225,5 @@ int main(int argc, const char **argv) {
else
FrontendFactory = newFrontendActionFactory(&CheckFactory);
- return Tool.run(FrontendFactory);
+ return Tool.run(FrontendFactory.get());
}
diff --git a/tools/clang-format/clang-format.py b/tools/clang-format/clang-format.py
index 0c0da6e4dc..46af0682aa 100644
--- a/tools/clang-format/clang-format.py
+++ b/tools/clang-format/clang-format.py
@@ -59,12 +59,7 @@ def main():
# If successful, replace buffer contents.
if stderr:
- message = stderr.splitlines()[0]
- parts = message.split(' ', 2)
- if len(parts) > 2:
- message = parts[2]
- print 'Formatting failed: %s (total %d warnings, %d errors)' % (
- message, stderr.count('warning:'), stderr.count('error:'))
+ print stderr
if not stdout:
print ('No output from clang-format (crashed?).\n' +
diff --git a/tools/clang-format/git-clang-format b/tools/clang-format/git-clang-format
index b0737ed034..c40b74dae4 100755
--- a/tools/clang-format/git-clang-format
+++ b/tools/clang-format/git-clang-format
@@ -75,6 +75,9 @@ def main():
'm', # ObjC
'mm', # ObjC++
'cc', 'cp', 'cpp', 'c++', 'cxx', 'hpp', # C++
+ # Other languages that clang-format supports
+ 'proto', 'protodevel', # Protocol Buffers
+ 'js', # JavaScript
])
p = argparse.ArgumentParser(
diff --git a/tools/diagtool/DiagnosticNames.cpp b/tools/diagtool/DiagnosticNames.cpp
index 155c62d80b..f5df05905e 100644
--- a/tools/diagtool/DiagnosticNames.cpp
+++ b/tools/diagtool/DiagnosticNames.cpp
@@ -53,8 +53,8 @@ const DiagnosticRecord &diagtool::getDiagnosticForID(short DiagID) {
DiagnosticRecord Key = {0, DiagID, 0};
const DiagnosticRecord *Result =
- std::lower_bound(BuiltinDiagnosticsByID,
- llvm::array_endof(BuiltinDiagnosticsByID),
+ std::lower_bound(std::begin(BuiltinDiagnosticsByID),
+ std::end(BuiltinDiagnosticsByID),
Key, orderByID);
assert(Result && "diagnostic not found; table may be out of date");
return *Result;
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index f60162f5e1..67d2115b84 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -10,6 +10,7 @@ set( LLVM_LINK_COMPONENTS
MCParser
ObjCARCOpts
Option
+ ProfileData
ScalarOpts
Support
TransformUtils
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index d75b19cf2a..7404496875 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -33,7 +33,7 @@ endif
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader bitwriter codegen \
instrumentation ipo irreader linker objcarcopts option \
- selectiondag
+ profiledata selectiondag
USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
clangSerialization.a clangCodeGen.a clangParse.a clangSema.a
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index 8521c2a120..68efc19a7a 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -34,6 +34,7 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetAsmParser.h"
+#include "llvm/MC/MCTargetOptions.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
@@ -373,8 +374,11 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
std::unique_ptr<MCAsmParser> Parser(
createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
+
+ // FIXME: init MCTargetOptions from sanitizer flags here.
+ MCTargetOptions Options;
std::unique_ptr<MCTargetAsmParser> TAP(
- TheTarget->createMCAsmParser(*STI, *Parser, *MCII));
+ TheTarget->createMCAsmParser(*STI, *Parser, *MCII, Options));
if (!TAP) {
Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
return false;
diff --git a/tools/libclang/BuildSystem.cpp b/tools/libclang/BuildSystem.cpp
index 89c6e91d23..c9d3c55327 100644
--- a/tools/libclang/BuildSystem.cpp
+++ b/tools/libclang/BuildSystem.cpp
@@ -19,6 +19,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/TimeValue.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/YAMLParser.h"
using namespace clang;
using namespace llvm::sys;
@@ -147,10 +148,9 @@ private:
OS.indent(Indent) << "{\n";
Indent += 2;
OS.indent(Indent) << "'type': 'file',\n";
- OS.indent(Indent) << "'name': \"";
- OS.write_escaped(VName) << "\",\n";
- OS.indent(Indent) << "'external-contents': \"";
- OS.write_escaped(Entry.RPath) << "\"\n";
+ OS.indent(Indent) << "'name': \"" << llvm::yaml::escape(VName) << "\",\n";
+ OS.indent(Indent) << "'external-contents': \""
+ << llvm::yaml::escape(Entry.RPath) << "\"\n";
Indent -= 2;
OS.indent(Indent) << '}';
if (Entries.empty()) {
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 04797a98d3..26b3bf16af 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -15,7 +15,6 @@
#include "CIndexer.h"
#include "CIndexDiagnostic.h"
#include "CLog.h"
-#include "CXComment.h"
#include "CXCursor.h"
#include "CXSourceLocation.h"
#include "CXString.h"
@@ -1954,6 +1953,10 @@ void OMPClauseEnqueue::VisitOMPFirstprivateClause(
void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) {
VisitOMPClauseList(C);
}
+void OMPClauseEnqueue::VisitOMPLinearClause(const OMPLinearClause *C) {
+ VisitOMPClauseList(C);
+ Visitor->AddStmt(C->getStep());
+}
void OMPClauseEnqueue::VisitOMPCopyinClause(const OMPCopyinClause *C) {
VisitOMPClauseList(C);
}
@@ -6029,8 +6032,10 @@ static int getCursorPlatformAvailabilityForDecl(const Decl *D,
HadAvailAttr = true;
if (always_deprecated)
*always_deprecated = 1;
- if (deprecated_message)
+ if (deprecated_message) {
+ clang_disposeString(*deprecated_message);
*deprecated_message = cxstring::createDup(Deprecated->getMessage());
+ }
continue;
}
@@ -6039,6 +6044,7 @@ static int getCursorPlatformAvailabilityForDecl(const Decl *D,
if (always_unavailable)
*always_unavailable = 1;
if (unavailable_message) {
+ clang_disposeString(*unavailable_message);
*unavailable_message = cxstring::createDup(Unavailable->getMessage());
}
continue;
@@ -6305,17 +6311,6 @@ CXString clang_Cursor_getBriefCommentText(CXCursor C) {
return cxstring::createNull();
}
-CXComment clang_Cursor_getParsedComment(CXCursor C) {
- if (!clang_isDeclaration(C.kind))
- return cxcomment::createCXComment(NULL, NULL);
-
- const Decl *D = getCursorDecl(C);
- const ASTContext &Context = getCursorContext(C);
- const comments::FullComment *FC = Context.getCommentForDecl(D, /*PP=*/ NULL);
-
- return cxcomment::createCXComment(FC, getCursorTU(C));
-}
-
CXModule clang_Cursor_getModule(CXCursor C) {
if (C.kind == CXCursor_ModuleImportDecl) {
if (const ImportDecl *ImportD =
@@ -6403,6 +6398,16 @@ unsigned clang_CXXMethod_isPureVirtual(CXCursor C) {
return (Method && Method->isVirtual() && Method->isPure()) ? 1 : 0;
}
+unsigned clang_CXXMethod_isConst(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+
+ const Decl *D = cxcursor::getCursorDecl(C);
+ const CXXMethodDecl *Method =
+ D ? dyn_cast_or_null<CXXMethodDecl>(D->getAsFunction()) : 0;
+ return (Method && (Method->getTypeQualifiers() & Qualifiers::Const)) ? 1 : 0;
+}
+
unsigned clang_CXXMethod_isStatic(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return 0;
@@ -6706,7 +6711,7 @@ void cxindex::printDiagsToStderr(ASTUnit *Unit) {
for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),
DEnd = Unit->stored_diag_end();
D != DEnd; ++D) {
- CXStoredDiagnostic Diag(*D, Unit->getASTContext().getLangOpts());
+ CXStoredDiagnostic Diag(*D, Unit->getLangOpts());
CXString Msg = clang_formatDiagnostic(&Diag,
clang_defaultDiagnosticDisplayOptions());
fprintf(stderr, "%s\n", clang_getCString(Msg));
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index 591294599d..23fdf93b76 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -249,7 +249,7 @@ namespace {
/// AllocatedCXCodeCompleteResults outlives the CXTranslationUnit, so we can
/// not rely on the StringPool in the TU.
struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
- AllocatedCXCodeCompleteResults(const FileSystemOptions& FileSystemOpts);
+ AllocatedCXCodeCompleteResults(IntrusiveRefCntPtr<FileManager> FileMgr);
~AllocatedCXCodeCompleteResults();
/// \brief Diagnostics produced while performing code completion.
@@ -263,8 +263,6 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
/// \brief Language options used to adjust source locations.
LangOptions LangOpts;
- FileSystemOptions FileSystemOpts;
-
/// \brief File manager, used for diagnostics.
IntrusiveRefCntPtr<FileManager> FileMgr;
@@ -318,20 +316,15 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
static std::atomic<unsigned> CodeCompletionResultObjects;
AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
- const FileSystemOptions& FileSystemOpts)
- : CXCodeCompleteResults(),
- DiagOpts(new DiagnosticOptions),
- Diag(new DiagnosticsEngine(
- IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
- &*DiagOpts)),
- FileSystemOpts(FileSystemOpts),
- FileMgr(new FileManager(FileSystemOpts)),
- SourceMgr(new SourceManager(*Diag, *FileMgr)),
- CodeCompletionAllocator(new clang::GlobalCodeCompletionAllocator),
- Contexts(CXCompletionContext_Unknown),
- ContainerKind(CXCursor_InvalidCode),
- ContainerIsIncomplete(1)
-{
+ IntrusiveRefCntPtr<FileManager> FileMgr)
+ : CXCodeCompleteResults(),
+ DiagOpts(new DiagnosticOptions),
+ Diag(new DiagnosticsEngine(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts)),
+ FileMgr(FileMgr), SourceMgr(new SourceManager(*Diag, *FileMgr)),
+ CodeCompletionAllocator(new clang::GlobalCodeCompletionAllocator),
+ Contexts(CXCompletionContext_Unknown),
+ ContainerKind(CXCursor_InvalidCode), ContainerIsIncomplete(1) {
if (getenv("LIBCLANG_OBJTRACKING"))
fprintf(stderr, "+++ %u completion results\n",
++CodeCompletionResultObjects);
@@ -709,8 +702,8 @@ void clang_codeCompleteAt_Impl(void *UserData) {
}
// Parse the resulting source file to find code-completion results.
- AllocatedCXCodeCompleteResults *Results =
- new AllocatedCXCodeCompleteResults(AST->getFileSystemOpts());
+ AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults(
+ &AST->getFileManager());
Results->Results = 0;
Results->NumResults = 0;
diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp
index cf9dc6f240..8a57d7dfff 100644
--- a/tools/libclang/CIndexDiagnostic.cpp
+++ b/tools/libclang/CIndexDiagnostic.cpp
@@ -308,7 +308,6 @@ CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
switch (Severity) {
case CXDiagnostic_Ignored: llvm_unreachable("impossible");
case CXDiagnostic_Note: Out << "note: "; break;
- case CXDiagnostic_Remark: Out << "remark: "; break;
case CXDiagnostic_Warning: Out << "warning: "; break;
case CXDiagnostic_Error: Out << "error: "; break;
case CXDiagnostic_Fatal: Out << "fatal error: "; break;
diff --git a/tools/libclang/CXComment.cpp b/tools/libclang/CXComment.cpp
index 2c4f269f9e..8fb7c0a5c4 100644
--- a/tools/libclang/CXComment.cpp
+++ b/tools/libclang/CXComment.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang-c/Index.h"
+#include "clang-c/Documentation.h"
#include "CXComment.h"
#include "CXCursor.h"
#include "CXString.h"
@@ -28,6 +29,19 @@ using namespace clang::cxcomment;
extern "C" {
+CXComment clang_Cursor_getParsedComment(CXCursor C) {
+ using namespace clang::cxcursor;
+
+ if (!clang_isDeclaration(C.kind))
+ return createCXComment(NULL, NULL);
+
+ const Decl *D = getCursorDecl(C);
+ const ASTContext &Context = getCursorContext(C);
+ const FullComment *FC = Context.getCommentForDecl(D, /*PP=*/NULL);
+
+ return createCXComment(FC, getCursorTU(C));
+}
+
enum CXCommentKind clang_Comment_getKind(CXComment CXC) {
const Comment *C = getASTNode(CXC);
if (!C)
diff --git a/tools/libclang/CXComment.h b/tools/libclang/CXComment.h
index 1e2561d585..606ee26bb6 100644
--- a/tools/libclang/CXComment.h
+++ b/tools/libclang/CXComment.h
@@ -16,6 +16,7 @@
#include "CXTranslationUnit.h"
#include "clang-c/Index.h"
+#include "clang-c/Documentation.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Comment.h"
#include "clang/Frontend/ASTUnit.h"
diff --git a/tools/libclang/CXLoadedDiagnostic.cpp b/tools/libclang/CXLoadedDiagnostic.cpp
index 679c528526..8385f242d4 100644
--- a/tools/libclang/CXLoadedDiagnostic.cpp
+++ b/tools/libclang/CXLoadedDiagnostic.cpp
@@ -79,8 +79,9 @@ CXDiagnosticSeverity CXLoadedDiagnostic::getSeverity() const {
CASE(Warning)
CASE(Error)
CASE(Fatal)
- CASE(Remark)
#undef CASE
+ // The 'Remark' level isn't represented in the stable API.
+ case serialized_diags::Remark: return CXDiagnostic_Warning;
}
llvm_unreachable("Invalid diagnostic level");
diff --git a/tools/libclang/CXStoredDiagnostic.cpp b/tools/libclang/CXStoredDiagnostic.cpp
index 45ce39b60d..faaf746a1e 100644
--- a/tools/libclang/CXStoredDiagnostic.cpp
+++ b/tools/libclang/CXStoredDiagnostic.cpp
@@ -31,7 +31,8 @@ CXDiagnosticSeverity CXStoredDiagnostic::getSeverity() const {
switch (Diag.getLevel()) {
case DiagnosticsEngine::Ignored: return CXDiagnostic_Ignored;
case DiagnosticsEngine::Note: return CXDiagnostic_Note;
- case DiagnosticsEngine::Remark: return CXDiagnostic_Remark;
+ case DiagnosticsEngine::Remark:
+ // The 'Remark' level isn't represented in the stable API.
case DiagnosticsEngine::Warning: return CXDiagnostic_Warning;
case DiagnosticsEngine::Error: return CXDiagnostic_Error;
case DiagnosticsEngine::Fatal: return CXDiagnostic_Fatal;
diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp
index 55e6e79873..47ba97bd9a 100644
--- a/tools/libclang/Indexing.cpp
+++ b/tools/libclang/Indexing.cpp
@@ -610,6 +610,11 @@ static void clang_indexSourceFile_Impl(void *UserData) {
ASTUnit *Unit = ASTUnit::create(CInvok.getPtr(), Diags,
CaptureDiagnostics,
/*UserFilesAreVolatile=*/true);
+ if (!Unit) {
+ ITUI->result = CXError_InvalidArguments;
+ return;
+ }
+
std::unique_ptr<CXTUOwner> CXTU(
new CXTUOwner(MakeCXTranslationUnit(CXXIdx, Unit)));
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 37b6159bd0..df8d85c01f 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -2,6 +2,7 @@ clang_CXCursorSet_contains
clang_CXCursorSet_insert
clang_CXIndex_getGlobalOptions
clang_CXIndex_setGlobalOptions
+clang_CXXMethod_isConst
clang_CXXMethod_isPureVirtual
clang_CXXMethod_isStatic
clang_CXXMethod_isVirtual
diff --git a/tools/scan-build/set-xcode-analyzer b/tools/scan-build/set-xcode-analyzer
index 5ac5c18f11..8e674823ba 100755
--- a/tools/scan-build/set-xcode-analyzer
+++ b/tools/scan-build/set-xcode-analyzer
@@ -100,7 +100,7 @@ def main():
if (xcode_path.find(".app/") != -1):
# Cut off the 'Developer' dir, as the xcspec lies in another part
# of the Xcode.app subtree.
- xcode_path = os.path.dirname(xcode_path)
+ xcode_path = xcode_path.rsplit('/Developer', 1)[0]
foundSpec = False
for x in FindClangSpecs(xcode_path):
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index e224722e96..8e243cf078 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -64,8 +64,10 @@ testing::AssertionResult matchesConditionally(const std::string &Code,
llvm::StringRef CompileArg) {
bool Found = false, DynamicFound = false;
MatchFinder Finder;
- Finder.addMatcher(AMatcher, new VerifyMatch(0, &Found));
- if (!Finder.addDynamicMatcher(AMatcher, new VerifyMatch(0, &DynamicFound)))
+ VerifyMatch VerifyFound(0, &Found);
+ Finder.addMatcher(AMatcher, &VerifyFound);
+ VerifyMatch VerifyDynamicFound(0, &DynamicFound);
+ if (!Finder.addDynamicMatcher(AMatcher, &VerifyDynamicFound))
return testing::AssertionFailure() << "Could not add dynamic matcher";
std::unique_ptr<FrontendActionFactory> Factory(
newFrontendActionFactory(&Finder));
@@ -109,8 +111,8 @@ matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
std::unique_ptr<BoundNodesCallback> ScopedVerifier(FindResultVerifier);
bool VerifiedResult = false;
MatchFinder Finder;
- Finder.addMatcher(
- AMatcher, new VerifyMatch(FindResultVerifier, &VerifiedResult));
+ VerifyMatch VerifyVerifiedResult(FindResultVerifier, &VerifiedResult);
+ Finder.addMatcher(AMatcher, &VerifyVerifiedResult);
std::unique_ptr<FrontendActionFactory> Factory(
newFrontendActionFactory(&Finder));
// Some tests use typeof, which is a gnu extension.
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index cdf4f92db6..a4b493295e 100644
--- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -39,9 +39,7 @@ public:
Errors.push_back(Error.toStringFull());
}
- llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName,
- const SourceRange &NameRange,
- Diagnostics *Error) {
+ llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) {
const ExpectedMatchersTy::value_type *Matcher =
&*ExpectedMatchers.find(MatcherName);
return reinterpret_cast<MatcherCtor>(Matcher);
@@ -175,6 +173,29 @@ TEST(ParserTest, FullParserTest) {
EXPECT_TRUE(matches("void f(int a, int x);", M));
EXPECT_FALSE(matches("void f(int x, int a);", M));
+ // Test named values.
+ struct NamedSema : public Parser::RegistrySema {
+ public:
+ virtual VariantValue getNamedValue(StringRef Name) {
+ if (Name == "nameX")
+ return std::string("x");
+ if (Name == "param0")
+ return VariantMatcher::SingleMatcher(hasParameter(0, hasName("a")));
+ return VariantValue();
+ }
+ };
+ NamedSema Sema;
+ llvm::Optional<DynTypedMatcher> HasParameterWithNamedValues(
+ Parser::parseMatcherExpression(
+ "functionDecl(param0, hasParameter(1, hasName(nameX)))", &Sema,
+ &Error));
+ EXPECT_EQ("", Error.toStringFull());
+ M = HasParameterWithNamedValues->unconditionalConvertTo<Decl>();
+
+ EXPECT_TRUE(matches("void f(int a, int x);", M));
+ EXPECT_FALSE(matches("void f(int x, int a);", M));
+
+
EXPECT_TRUE(!Parser::parseMatcherExpression(
"hasInitializer(\n binaryOperator(hasLHS(\"A\")))",
&Error).hasValue());
@@ -208,6 +229,10 @@ TEST(ParserTest, Errors) {
"1:9: Error parsing matcher. Found token <123> while looking for ','.",
ParseWithError("Foo(\"A\" 123)"));
EXPECT_EQ(
+ "1:1: Error parsing argument 1 for matcher stmt.\n"
+ "1:6: Value not found: someValue",
+ ParseWithError("stmt(someValue)"));
+ EXPECT_EQ(
"1:1: Matcher not found: Foo\n"
"1:4: Error parsing matcher. Found end-of-code while looking for ')'.",
ParseWithError("Foo("));
diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
index 150f8c929c..abacb6fe7d 100644
--- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -35,21 +35,15 @@ public:
return Out;
}
- llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName,
- Diagnostics *Error = 0) {
- Diagnostics DummyError;
- if (!Error) Error = &DummyError;
- llvm::Optional<MatcherCtor> Ctor =
- Registry::lookupMatcherCtor(MatcherName, SourceRange(), Error);
- EXPECT_EQ("", DummyError.toStringFull());
- return Ctor;
+ llvm::Optional<MatcherCtor> lookupMatcherCtor(StringRef MatcherName) {
+ return Registry::lookupMatcherCtor(MatcherName);
}
VariantMatcher constructMatcher(StringRef MatcherName,
Diagnostics *Error = NULL) {
Diagnostics DummyError;
if (!Error) Error = &DummyError;
- llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName, Error);
+ llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
VariantMatcher Out;
if (Ctor)
Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(), Error);
@@ -62,7 +56,7 @@ public:
Diagnostics *Error = NULL) {
Diagnostics DummyError;
if (!Error) Error = &DummyError;
- llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName, Error);
+ llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
VariantMatcher Out;
if (Ctor)
Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1), Error);
@@ -76,7 +70,7 @@ public:
Diagnostics *Error = NULL) {
Diagnostics DummyError;
if (!Error) Error = &DummyError;
- llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName, Error);
+ llvm::Optional<MatcherCtor> Ctor = lookupMatcherCtor(MatcherName);
VariantMatcher Out;
if (Ctor)
Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1, Arg2),
diff --git a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
index e62a4645f7..524b73dc52 100644
--- a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
@@ -26,6 +26,7 @@ TEST(VariantValueTest, Unsigned) {
EXPECT_TRUE(Value.isUnsigned());
EXPECT_EQ(kUnsigned, Value.getUnsigned());
+ EXPECT_TRUE(Value.hasValue());
EXPECT_FALSE(Value.isString());
EXPECT_FALSE(Value.isMatcher());
}
@@ -38,6 +39,7 @@ TEST(VariantValueTest, String) {
EXPECT_EQ(kString, Value.getString());
EXPECT_EQ("String", Value.getTypeAsString());
+ EXPECT_TRUE(Value.hasValue());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isMatcher());
}
@@ -45,6 +47,7 @@ TEST(VariantValueTest, String) {
TEST(VariantValueTest, DynTypedMatcher) {
VariantValue Value = VariantMatcher::SingleMatcher(stmt());
+ EXPECT_TRUE(Value.hasValue());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
@@ -74,11 +77,13 @@ TEST(VariantValueTest, Assignment) {
VariantValue Value = std::string("A");
EXPECT_TRUE(Value.isString());
EXPECT_EQ("A", Value.getString());
+ EXPECT_TRUE(Value.hasValue());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isMatcher());
EXPECT_EQ("String", Value.getTypeAsString());
Value = VariantMatcher::SingleMatcher(recordDecl());
+ EXPECT_TRUE(Value.hasValue());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
EXPECT_TRUE(Value.isMatcher());
@@ -89,16 +94,36 @@ TEST(VariantValueTest, Assignment) {
Value = 17;
EXPECT_TRUE(Value.isUnsigned());
EXPECT_EQ(17U, Value.getUnsigned());
+ EXPECT_TRUE(Value.hasValue());
EXPECT_FALSE(Value.isMatcher());
EXPECT_FALSE(Value.isString());
Value = VariantValue();
+ EXPECT_FALSE(Value.hasValue());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
EXPECT_FALSE(Value.isMatcher());
EXPECT_EQ("Nothing", Value.getTypeAsString());
}
+TEST(VariantValueTest, ImplicitBool) {
+ VariantValue Value;
+ bool IfTrue = false;
+ if (Value) {
+ IfTrue = true;
+ }
+ EXPECT_FALSE(IfTrue);
+ EXPECT_TRUE(!Value);
+
+ Value = std::string();
+ IfTrue = false;
+ if (Value) {
+ IfTrue = true;
+ }
+ EXPECT_TRUE(IfTrue);
+ EXPECT_FALSE(!Value);
+}
+
TEST(VariantValueTest, Matcher) {
EXPECT_TRUE(matches("class X {};", VariantValue(VariantMatcher::SingleMatcher(
recordDecl(hasName("X"))))
diff --git a/unittests/Basic/SourceManagerTest.cpp b/unittests/Basic/SourceManagerTest.cpp
index d94cfe9c3f..88c3fb76ca 100644
--- a/unittests/Basic/SourceManagerTest.cpp
+++ b/unittests/Basic/SourceManagerTest.cpp
@@ -52,17 +52,22 @@ protected:
};
class VoidModuleLoader : public ModuleLoader {
- virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) {
+ ModuleLoadResult loadModule(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) override {
return ModuleLoadResult();
}
- virtual void makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc,
- bool Complain) { }
+ void makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc,
+ bool Complain) override { }
+
+ GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
+ { return 0; }
+ bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
+ { return 0; };
};
TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 76062605f7..084d1dd33d 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -7,13 +7,13 @@
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "format-test"
-
#include "FormatTestUtils.h"
#include "clang/Format/Format.h"
#include "llvm/Support/Debug.h"
#include "gtest/gtest.h"
+#define DEBUG_TYPE "format-test"
+
namespace clang {
namespace format {
@@ -511,6 +511,9 @@ TEST_F(FormatTest, FormatsSwitchStatement) {
" f();\n"
" break;\n"
"}\n"
+ "case 2: {\n"
+ " break;\n"
+ "}\n"
"}");
verifyFormat("switch (x) {\n"
"case 1: {\n"
@@ -615,6 +618,10 @@ TEST_F(FormatTest, FormatsSwitchStatement) {
" break;\n"
" }\n"
"});");
+ verifyFormat("switch (a) {\n"
+ "case (b):\n"
+ " return;\n"
+ "}");
}
TEST_F(FormatTest, CaseRanges) {
@@ -829,6 +836,17 @@ TEST_F(FormatTest, UnderstandsSingleLineComments) {
" // first\n"
"// at start\n"
"otherLine();"));
+
+ verifyFormat(
+ "#define A \\\n"
+ " int i; /* iiiiiiiiiiiiiiiiiiiii */ \\\n"
+ " int jjjjjjjjjjjjjjjjjjjjjjjj; /* */",
+ getLLVMStyleWithColumns(60));
+ verifyFormat(
+ "#define A \\\n"
+ " int i; /* iiiiiiiiiiiiiiiiiiiii */ \\\n"
+ " int jjjjjjjjjjjjjjjjjjjjjjjj; /* */",
+ getLLVMStyleWithColumns(61));
}
TEST_F(FormatTest, KeepsParameterWithTrailingCommentsOnTheirOwnLine) {
@@ -1010,6 +1028,30 @@ TEST_F(FormatTest, AlignsBlockComments) {
format("int i; /* Comment with empty...\n"
" *\n"
" * line. */"));
+ EXPECT_EQ("int foobar = 0; /* comment */\n"
+ "int bar = 0; /* multiline\n"
+ " comment 1 */\n"
+ "int baz = 0; /* multiline\n"
+ " comment 2 */\n"
+ "int bzz = 0; /* multiline\n"
+ " comment 3 */",
+ format("int foobar = 0; /* comment */\n"
+ "int bar = 0; /* multiline\n"
+ " comment 1 */\n"
+ "int baz = 0; /* multiline\n"
+ " comment 2 */\n"
+ "int bzz = 0; /* multiline\n"
+ " comment 3 */"));
+ EXPECT_EQ("int foobar = 0; /* comment */\n"
+ "int bar = 0; /* multiline\n"
+ " comment */\n"
+ "int baz = 0; /* multiline\n"
+ "comment */",
+ format("int foobar = 0; /* comment */\n"
+ "int bar = 0; /* multiline\n"
+ "comment */\n"
+ "int baz = 0; /* multiline\n"
+ "comment */"));
}
TEST_F(FormatTest, CorrectlyHandlesLengthOfBlockComments) {
@@ -2937,8 +2979,9 @@ TEST_F(FormatTest, ExpressionIndentationBreakingBeforeOperators) {
" + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}",
Style);
verifyFormat("if () {\n"
- "} else if (aaaaa && bbbbb // break\n"
- " > ccccc) {\n"
+ "} else if (aaaaa\n"
+ " && bbbbb // break\n"
+ " > ccccc) {\n"
"}",
Style);
@@ -3267,9 +3310,15 @@ TEST_F(FormatTest, BreaksFunctionDeclarationsWithTrailingTokens) {
" int someLongParameter) override {}",
Style);
verifyFormat("void someLongFunction(\n"
+ " int someLongParameter) OVERRIDE {}",
+ Style);
+ verifyFormat("void someLongFunction(\n"
" int someLongParameter) final {}",
Style);
verifyFormat("void someLongFunction(\n"
+ " int someLongParameter) FINAL {}",
+ Style);
+ verifyFormat("void someLongFunction(\n"
" int parameter) const override {}",
Style);
@@ -3286,6 +3335,8 @@ TEST_F(FormatTest, BreaksFunctionDeclarationsWithTrailingTokens) {
" LOCKS_EXCLUDED(aaaaaaaaaaaaa);");
verifyFormat("void aaaaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) const\n"
" LOCKS_EXCLUDED(aaaaaaaaaaaaa) {}");
+ verifyGoogleFormat("void aaaaaaaaaaaaaa(aaaaaaaa aaa) override\n"
+ " AAAAAAAAAAAAAAAAAAAAAAAA(aaaaaaaaaaaaaaa);");
verifyFormat(
"void aaaaaaaaaaaaaaaaaa()\n"
@@ -3293,14 +3344,15 @@ TEST_F(FormatTest, BreaksFunctionDeclarationsWithTrailingTokens) {
" aaaaaaaaaaaaaaaaaaaaaaaaa));");
verifyFormat("bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" __attribute__((unused));");
- verifyFormat(
+ verifyGoogleFormat(
"bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " GUARDED_BY(aaaaaaaaaaaa);",
- getGoogleStyle());
- verifyFormat(
+ " GUARDED_BY(aaaaaaaaaaaa);");
+ verifyGoogleFormat(
"bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " GUARDED_BY(aaaaaaaaaaaa);",
- getGoogleStyle());
+ " GUARDED_BY(aaaaaaaaaaaa);");
+ verifyGoogleFormat(
+ "bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa GUARDED_BY(aaaaaaaaaaaa) =\n"
+ " aaaaaaaa::aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
}
TEST_F(FormatTest, BreaksDesireably) {
@@ -3685,6 +3737,12 @@ TEST_F(FormatTest, BreaksConditionalExpressions) {
" : (bbbbbbbbbbbbbbb //\n"
" ? ccccccccccccccc\n"
" : ddddddddddddddd);");
+ verifyFormat(
+ "int aaaaaaaaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " ? aaaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaa\n"
+ " : aaaaaaaaaa;");
FormatStyle NoBinPacking = getLLVMStyle();
NoBinPacking.BinPackParameters = false;
@@ -3964,6 +4022,18 @@ TEST_F(FormatTest, AlignsPipes) {
"aaaaaaaa << (aaaaaaaaaaaaaaaaaaa << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
" << aaaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
+ verifyFormat(
+ "llvm::errs() << \"a: \" << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat(
+ "llvm::errs() << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " << bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;");
+ verifyFormat(
+ "llvm::errs() << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
verifyFormat("return out << \"somepacket = {\\n\"\n"
" << \" aaaaaa = \" << pkt.aaaaaa << \"\\n\"\n"
@@ -3988,6 +4058,8 @@ TEST_F(FormatTest, AlignsPipes) {
" llvm::outs() << \"aaaaaaaaaaaaaaaaaaaa: \"\n"
" << aaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaa);\n"
"}");
+ verifyFormat("llvm::outs() << \"aaaaaaaaaaaaaaaa: \"\n"
+ " << aaaaaaaa.aaaaaaaaaaaa(aaa)->aaaaaaaaaaaaaa();");
// Breaking before the first "<<" is generally not desirable.
verifyFormat(
@@ -4451,6 +4523,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyIndependentOfContext("a * [self dostuff];");
verifyIndependentOfContext("int x = a * (a + b);");
verifyIndependentOfContext("(a *)(a + b);");
+ verifyIndependentOfContext("*(int *)(p & ~3UL) = 0;");
verifyIndependentOfContext("int *pa = (int *)&a;");
verifyIndependentOfContext("return sizeof(int **);");
verifyIndependentOfContext("return sizeof(int ******);");
@@ -4470,6 +4543,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyIndependentOfContext("A<int *> a;");
verifyIndependentOfContext("A<int **> a;");
verifyIndependentOfContext("A<int *, int *> a;");
+ verifyIndependentOfContext("A<int *[]> a;");
verifyIndependentOfContext(
"const char *const p = reinterpret_cast<const char *const>(q);");
verifyIndependentOfContext("A<int **, int **> a;");
@@ -4504,8 +4578,9 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyIndependentOfContext("f(b * /* confusing comment */ ++c);");
verifyFormat(
- "int *MyValues = {*A, // Operator detection might be confused by the '{'\n"
- " *BB // Operator detection might be confused by previous comment\n"
+ "int *MyValues = {\n"
+ " *A, // Operator detection might be confused by the '{'\n"
+ " *BB // Operator detection might be confused by previous comment\n"
"};");
verifyIndependentOfContext("if (int *a = &b)");
@@ -4561,6 +4636,16 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
// FIXME: Is there a way to make this work?
// verifyIndependentOfContext("MACRO(A *a);");
+ EXPECT_EQ("#define OP(x) \\\n"
+ " ostream &operator<<(ostream &s, const A &a) { \\\n"
+ " return s << a.DebugString(); \\\n"
+ " }",
+ format("#define OP(x) \\\n"
+ " ostream &operator<<(ostream &s, const A &a) { \\\n"
+ " return s << a.DebugString(); \\\n"
+ " }",
+ getLLVMStyleWithColumns(50)));
+
// FIXME: We cannot handle this case yet; we might be able to figure out that
// foo<x> d > v; doesn't make sense.
verifyFormat("foo<a < b && c> d > v;");
@@ -4624,6 +4709,7 @@ TEST_F(FormatTest, UnderstandsRvalueReferences) {
"};");
verifyGoogleFormat("#define IF(a, b, c) if (a && (b == c))");
verifyGoogleFormat("#define WHILE(a, b, c) while (a && (b == c))");
+ verifyFormat("#define A(a, b) (a && b)");
}
TEST_F(FormatTest, FormatsBinaryOperatorsPrecedingEquals) {
@@ -4981,7 +5067,7 @@ TEST_F(FormatTest, LayoutBraceInitializersInReturnStatement) {
verifyFormat("return (a)(b) {1, 2, 3};");
}
-TEST_F(FormatTest, LayoutCxx11ConstructorBraceInitializers) {
+TEST_F(FormatTest, LayoutCxx11BraceInitializers) {
verifyFormat("vector<int> x{1, 2, 3, 4};");
verifyFormat("vector<int> x{\n"
" 1, 2, 3, 4,\n"
@@ -5003,6 +5089,36 @@ TEST_F(FormatTest, LayoutCxx11ConstructorBraceInitializers) {
"};");
verifyFormat("vector<int> foo = {::SomeGlobalFunction()};");
+ // In combination with BinPackParameters = false.
+ FormatStyle NoBinPacking = getLLVMStyle();
+ NoBinPacking.BinPackParameters = false;
+ verifyFormat("const Aaaaaa aaaaa = {aaaaa,\n"
+ " bbbbb,\n"
+ " ccccc,\n"
+ " ddddd,\n"
+ " eeeee,\n"
+ " ffffff,\n"
+ " ggggg,\n"
+ " hhhhhh,\n"
+ " iiiiii,\n"
+ " jjjjjj,\n"
+ " kkkkkk};",
+ NoBinPacking);
+ verifyFormat("const Aaaaaa aaaaa = {\n"
+ " aaaaa,\n"
+ " bbbbb,\n"
+ " ccccc,\n"
+ " ddddd,\n"
+ " eeeee,\n"
+ " ffffff,\n"
+ " ggggg,\n"
+ " hhhhhh,\n"
+ " iiiiii,\n"
+ " jjjjjj,\n"
+ " kkkkkk,\n"
+ "};",
+ NoBinPacking);
+
// FIXME: The alignment of these trailing comments might be bad. Then again,
// this might be utterly useless in real code.
verifyFormat("Constructor::Constructor()\n"
@@ -5060,7 +5176,10 @@ TEST_F(FormatTest, LayoutCxx11ConstructorBraceInitializers) {
" bbbbbbbbbbbbbbbbbbbb, bbbbb };",
ExtraSpaces);
verifyFormat("DoSomethingWithVector({} /* No data */);", ExtraSpaces);
- verifyFormat("DoSomethingWithVector({ {} /* No data */ }, { { 1, 2 } });",
+ verifyFormat("DoSomethingWithVector({\n"
+ " {} /* No data */\n"
+ " },\n"
+ " { { 1, 2 } });",
ExtraSpaces);
verifyFormat(
"someFunction(OtherParam,\n"
@@ -5125,13 +5244,14 @@ TEST_F(FormatTest, FormatsBracedListsInColumnLayout) {
" 1, 1, 1, 1, 1, 1, 1, 1,\n"
"};",
getLLVMStyleWithColumns(39));
- verifyFormat("vector<int> x = {1, 1, 1, 1,\n"
- " 1, 1, 1, 1, //\n"
+ verifyFormat("vector<int> x = {\n"
+ " 1, 1, 1, 1, 1, 1, 1, 1, //\n"
"};",
getLLVMStyleWithColumns(39));
- verifyFormat("vector<int> x = {1, 1, 1, 1,\n"
- " 1, 1, 1, 1,\n"
- " /**/ /**/};",
+ verifyFormat("vector<int> x = {\n"
+ " 1, 1, 1, 1, 1, 1, 1, 1,\n"
+ " /**/ /**/\n"
+ "};",
getLLVMStyleWithColumns(39));
verifyFormat("return {{aaaaaaaaaaaaaaaaaaaaa},\n"
" {aaaaaaaaaaaaaaaaaaa},\n"
@@ -5159,7 +5279,7 @@ TEST_F(FormatTest, FormatsBracedListsInColumnLayout) {
TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) {
FormatStyle DoNotMerge = getLLVMStyle();
- DoNotMerge.AllowShortFunctionsOnASingleLine = false;
+ DoNotMerge.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
verifyFormat("void f() { return 42; }");
verifyFormat("void f() {\n"
@@ -5216,7 +5336,8 @@ TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) {
format("A()\n:b(0)\n{\n}", NoColumnLimit));
FormatStyle DoNotMergeNoColumnLimit = NoColumnLimit;
- DoNotMergeNoColumnLimit.AllowShortFunctionsOnASingleLine = false;
+ DoNotMergeNoColumnLimit.AllowShortFunctionsOnASingleLine =
+ FormatStyle::SFS_None;
EXPECT_EQ("A()\n"
" : b(0) {\n"
"}",
@@ -5246,6 +5367,19 @@ TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) {
getLLVMStyleWithColumns(23));
}
+TEST_F(FormatTest, PullInlineFunctionDefinitionsIntoSingleLine) {
+ FormatStyle MergeInlineOnly = getLLVMStyle();
+ MergeInlineOnly.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
+ verifyFormat("class C {\n"
+ " int f() { return 42; }\n"
+ "};",
+ MergeInlineOnly);
+ verifyFormat("int f() {\n"
+ " return 42;\n"
+ "}",
+ MergeInlineOnly);
+}
+
TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
// Elaborate type variable declarations.
verifyFormat("struct foo a = {bar};\nint n;");
@@ -5719,6 +5853,16 @@ TEST_F(FormatTest, FormatObjCInterface) {
"}\n"
"+ (id)init;\n"
"@end");
+
+ FormatStyle OnePerLine = getGoogleStyle();
+ OnePerLine.BinPackParameters = false;
+ verifyFormat("@interface aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ()<\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa> {\n"
+ "}",
+ OnePerLine);
}
TEST_F(FormatTest, FormatObjCImplementation) {
@@ -6314,7 +6458,7 @@ TEST_F(FormatTest, ReformatRegionAdjustsIndent) {
67, 0, getLLVMStyle()));
}
-TEST_F(FormatTest, BreakStringLiterals) {
+TEST_F(FormatTest, BreaksStringLiterals) {
EXPECT_EQ("\"some text \"\n"
"\"other\";",
format("\"some text other\";", getLLVMStyleWithColumns(12)));
@@ -6474,6 +6618,16 @@ TEST_F(FormatTest, BreakStringLiterals) {
format("#define A \"some text other\";", AlignLeft));
}
+TEST_F(FormatTest, BreaksStringLiteralsWithTabs) {
+ EXPECT_EQ(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "(\n"
+ " \"x\t\");",
+ format("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaa("
+ "\"x\t\");"));
+}
+
TEST_F(FormatTest, BreaksWideAndNSStringLiterals) {
EXPECT_EQ(
"u8\"utf8 string \"\n"
@@ -6611,6 +6765,10 @@ TEST_F(FormatTest, DoesNotTryToParseUDLiteralsInPreCpp11Code) {
format("#define x(_a) printf(\"foo\"_a);", Style));
}
+TEST_F(FormatTest, UnderstandsCpp1y) {
+ verifyFormat("int bi{1'000'000};");
+}
+
TEST_F(FormatTest, BreakStringLiteralsBeforeUnbreakableTokenSequence) {
EXPECT_EQ("someFunction(\"aaabbbcccd\"\n"
" \"ddeeefff\");",
@@ -7534,7 +7692,6 @@ TEST_F(FormatTest, ParsesConfiguration) {
CHECK_PARSE_BOOL(AlignEscapedNewlinesLeft);
CHECK_PARSE_BOOL(AlignTrailingComments);
CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine);
- CHECK_PARSE_BOOL(AllowShortFunctionsOnASingleLine);
CHECK_PARSE_BOOL(AllowShortIfStatementsOnASingleLine);
CHECK_PARSE_BOOL(AllowShortLoopsOnASingleLine);
CHECK_PARSE_BOOL(AlwaysBreakTemplateDeclarations);
@@ -7587,6 +7744,18 @@ TEST_F(FormatTest, ParsesConfiguration) {
CHECK_PARSE("UseTab: ForIndentation", UseTab, FormatStyle::UT_ForIndentation);
CHECK_PARSE("UseTab: Always", UseTab, FormatStyle::UT_Always);
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
+ CHECK_PARSE("AllowShortFunctionsOnASingleLine: false",
+ AllowShortFunctionsOnASingleLine, FormatStyle::SFS_None);
+ CHECK_PARSE("AllowShortFunctionsOnASingleLine: true",
+ AllowShortFunctionsOnASingleLine, FormatStyle::SFS_All);
+ CHECK_PARSE("AllowShortFunctionsOnASingleLine: None",
+ AllowShortFunctionsOnASingleLine, FormatStyle::SFS_None);
+ CHECK_PARSE("AllowShortFunctionsOnASingleLine: Inline",
+ AllowShortFunctionsOnASingleLine, FormatStyle::SFS_Inline);
+ CHECK_PARSE("AllowShortFunctionsOnASingleLine: All",
+ AllowShortFunctionsOnASingleLine, FormatStyle::SFS_All);
+
Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
CHECK_PARSE("SpaceBeforeParens: Never", SpaceBeforeParens,
FormatStyle::SBPO_Never);
@@ -7940,7 +8109,7 @@ TEST_F(FormatTest, ConstructorInitializerIndentWidth) {
"}",
Style);
- Style.AllowShortFunctionsOnASingleLine = false;
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
verifyFormat("SomeClass::Constructor()\n"
" : a(a)\n"
" , b(b)\n"
@@ -7951,7 +8120,7 @@ TEST_F(FormatTest, ConstructorInitializerIndentWidth) {
Style);
Style.ColumnLimit = 80;
- Style.AllowShortFunctionsOnASingleLine = true;
+ Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
Style.ConstructorInitializerIndentWidth = 2;
verifyFormat("SomeClass::Constructor()\n"
" : a(a)\n"
@@ -8096,6 +8265,29 @@ TEST_F(FormatTest, FormatsWithWebKitStyle) {
format("#define aNumber \\\n"
" 10",
Style));
+
+ // Keep empty and one-element array literals on a single line.
+ verifyFormat("NSArray* a = [[NSArray alloc] initWithArray:@[]\n"
+ " copyItems:YES];",
+ Style);
+ verifyFormat("NSArray* a = [[NSArray alloc] initWithArray:@[ @\"a\" ]\n"
+ " copyItems:YES];",
+ Style);
+ EXPECT_EQ("NSArray* a = [[NSArray alloc] initWithArray:@[\n"
+ " @\"a\",\n"
+ " @\"a\"\n"
+ " ]\n"
+ " copyItems:YES];",
+ format("NSArray* a = [[NSArray alloc] initWithArray:@[\n"
+ " @\"a\",\n"
+ " @\"a\"\n"
+ " ]\n"
+ " copyItems:YES];",
+ Style));
+ verifyFormat(
+ "NSArray* a = [[NSArray alloc] initWithArray:@[ @\"a\", @\"a\" ]\n"
+ " copyItems:YES];",
+ Style);
}
TEST_F(FormatTest, FormatsLambdas) {
@@ -8123,6 +8315,9 @@ TEST_F(FormatTest, FormatsLambdas) {
" x.end(), //\n"
" [&](int, int) { return 1; });\n"
"}\n");
+ verifyFormat("SomeFunction([]() { // A cool function...\n"
+ " return 43;\n"
+ "});");
// Lambdas with return types.
verifyFormat("int c = []() -> int { return 2; }();\n");
@@ -8133,6 +8328,16 @@ TEST_F(FormatTest, FormatsLambdas) {
" return fffffffffffffffffffffffffffffffffffffff(i * j);\n"
"};");
+ // Multiple lambdas in the same parentheses change indentation rules.
+ verifyFormat("SomeFunction([]() {\n"
+ " int i = 42;\n"
+ " return i;\n"
+ " },\n"
+ " []() {\n"
+ " int j = 43;\n"
+ " return j;\n"
+ " });");
+
// Not lambdas.
verifyFormat("constexpr char hello[]{\"hello\"};");
verifyFormat("double &operator[](int i) { return 0; }\n"
@@ -8220,6 +8425,12 @@ TEST_F(FormatTest, FormatsBlocks) {
" // ...\n"
" int i;\n"
" }];");
+ verifyFormat("[myObject doSomethingWith:arg1\n"
+ " firstBlock:-1\n"
+ " secondBlock:^(Bar *b) {\n"
+ " // ...\n"
+ " int i;\n"
+ " }];");
verifyFormat("f(^{\n"
" @autoreleasepool {\n"
@@ -8340,5 +8551,97 @@ TEST_F(FormatTest, HandleUnbalancedImplicitBracesAcrossPPBranches) {
EXPECT_EQ(code, format(code));
}
+TEST_F(FormatTest, HandleConflictMarkers) {
+ // Git/SVN conflict markers.
+ EXPECT_EQ("int a;\n"
+ "void f() {\n"
+ " callme(some(parameter1,\n"
+ "<<<<<<< text by the vcs\n"
+ " parameter2),\n"
+ "||||||| text by the vcs\n"
+ " parameter2),\n"
+ " parameter3,\n"
+ "======= text by the vcs\n"
+ " parameter2, parameter3),\n"
+ ">>>>>>> text by the vcs\n"
+ " otherparameter);\n",
+ format("int a;\n"
+ "void f() {\n"
+ " callme(some(parameter1,\n"
+ "<<<<<<< text by the vcs\n"
+ " parameter2),\n"
+ "||||||| text by the vcs\n"
+ " parameter2),\n"
+ " parameter3,\n"
+ "======= text by the vcs\n"
+ " parameter2,\n"
+ " parameter3),\n"
+ ">>>>>>> text by the vcs\n"
+ " otherparameter);\n"));
+
+ // Perforce markers.
+ EXPECT_EQ("void f() {\n"
+ " function(\n"
+ ">>>> text by the vcs\n"
+ " parameter,\n"
+ "==== text by the vcs\n"
+ " parameter,\n"
+ "==== text by the vcs\n"
+ " parameter,\n"
+ "<<<< text by the vcs\n"
+ " parameter);\n",
+ format("void f() {\n"
+ " function(\n"
+ ">>>> text by the vcs\n"
+ " parameter,\n"
+ "==== text by the vcs\n"
+ " parameter,\n"
+ "==== text by the vcs\n"
+ " parameter,\n"
+ "<<<< text by the vcs\n"
+ " parameter);\n"));
+
+ EXPECT_EQ("<<<<<<<\n"
+ "|||||||\n"
+ "=======\n"
+ ">>>>>>>",
+ format("<<<<<<<\n"
+ "|||||||\n"
+ "=======\n"
+ ">>>>>>>"));
+
+ EXPECT_EQ("<<<<<<<\n"
+ "|||||||\n"
+ "int i;\n"
+ "=======\n"
+ ">>>>>>>",
+ format("<<<<<<<\n"
+ "|||||||\n"
+ "int i;\n"
+ "=======\n"
+ ">>>>>>>"));
+
+ // FIXME: Handle parsing of macros around conflict markers correctly:
+ EXPECT_EQ("#define Macro \\\n"
+ "<<<<<<<\n"
+ "Something \\\n"
+ "|||||||\n"
+ "Else \\\n"
+ "=======\n"
+ "Other \\\n"
+ ">>>>>>>\n"
+ "End int i;\n",
+ format("#define Macro \\\n"
+ "<<<<<<<\n"
+ " Something \\\n"
+ "|||||||\n"
+ " Else \\\n"
+ "=======\n"
+ " Other \\\n"
+ ">>>>>>>\n"
+ " End\n"
+ "int i;\n"));
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp
index c0215e7d14..e7ca14f595 100644
--- a/unittests/Format/FormatTestJS.cpp
+++ b/unittests/Format/FormatTestJS.cpp
@@ -7,13 +7,13 @@
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "format-test"
-
#include "FormatTestUtils.h"
#include "clang/Format/Format.h"
#include "llvm/Support/Debug.h"
#include "gtest/gtest.h"
+#define DEBUG_TYPE "format-test"
+
namespace clang {
namespace format {
diff --git a/unittests/Format/FormatTestProto.cpp b/unittests/Format/FormatTestProto.cpp
index 0a4416ec26..b3dd354b2c 100644
--- a/unittests/Format/FormatTestProto.cpp
+++ b/unittests/Format/FormatTestProto.cpp
@@ -7,13 +7,13 @@
//
//===----------------------------------------------------------------------===//
-#define DEBUG_TYPE "format-test"
-
#include "FormatTestUtils.h"
#include "clang/Format/Format.h"
#include "llvm/Support/Debug.h"
#include "gtest/gtest.h"
+#define DEBUG_TYPE "format-test"
+
namespace clang {
namespace format {
@@ -81,10 +81,13 @@ TEST_F(FormatTestProto, MessageFieldAttributes) {
verifyFormat("optional LongMessageType long_proto_field = 1\n"
" [default = REALLY_REALLY_LONG_CONSTANT_VALUE];");
verifyFormat("repeated double value = 1\n"
- " [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaaa : AAAAAAAA}];");
+ " [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaaa: AAAAAAAA}];");
verifyFormat("repeated double value = 1\n"
- " [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaa : AAAAAAAAAA,\n"
- " bbbbbbbbbbbbbbbb : BBBBBBBBBB}];");
+ " [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaa: AAAAAAAAAA,\n"
+ " bbbbbbbbbbbbbbbb: BBBBBBBBBB}];");
+ verifyFormat("repeated double value = 1\n"
+ " [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaa: AAAAAAAAAA\n"
+ " bbbbbbbbbbbbbbbb: BBBBBBBBBB}];");
}
TEST_F(FormatTestProto, FormatsOptions) {
@@ -92,5 +95,13 @@ TEST_F(FormatTestProto, FormatsOptions) {
verifyFormat("option (my_custom_option) = \"abc\";");
}
+TEST_F(FormatTestProto, FormatsService) {
+ verifyFormat("service SearchService {\n"
+ " rpc Search(SearchRequest) returns (SearchResponse) {\n"
+ " option foo = true;\n"
+ " }\n"
+ "};");
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Lex/CMakeLists.txt b/unittests/Lex/CMakeLists.txt
index 461e0d95fc..1fb57cfdfb 100644
--- a/unittests/Lex/CMakeLists.txt
+++ b/unittests/Lex/CMakeLists.txt
@@ -14,4 +14,5 @@ target_link_libraries(LexTests
clangLex
clangParse
clangSema
+ clangSerialization
)
diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp
index 40ce928014..0faad45983 100644
--- a/unittests/Lex/LexerTest.cpp
+++ b/unittests/Lex/LexerTest.cpp
@@ -29,17 +29,22 @@ using namespace clang;
namespace {
class VoidModuleLoader : public ModuleLoader {
- virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) {
+ ModuleLoadResult loadModule(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) override {
return ModuleLoadResult();
}
- virtual void makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc,
- bool Complain) { }
+ void makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc,
+ bool Complain) override { }
+
+ GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
+ { return 0; }
+ bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
+ { return 0; };
};
// The test fixture.
diff --git a/unittests/Lex/Makefile b/unittests/Lex/Makefile
index fa233ce25f..071d01c8b5 100644
--- a/unittests/Lex/Makefile
+++ b/unittests/Lex/Makefile
@@ -9,8 +9,8 @@
CLANG_LEVEL = ../..
TESTNAME = Lex
-LINK_COMPONENTS := mcparser support mc
+LINK_COMPONENTS := mcparser support mc bitreader
USEDLIBS = clangParse.a clangSema.a clangAnalysis.a clangEdit.a \
- clangAST.a clangLex.a clangBasic.a
+ clangSerialization.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Lex/PPCallbacksTest.cpp b/unittests/Lex/PPCallbacksTest.cpp
index e3a4a76a77..bdc026a223 100644
--- a/unittests/Lex/PPCallbacksTest.cpp
+++ b/unittests/Lex/PPCallbacksTest.cpp
@@ -34,17 +34,22 @@ namespace {
// Stub out module loading.
class VoidModuleLoader : public ModuleLoader {
- virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) {
+ ModuleLoadResult loadModule(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) override {
return ModuleLoadResult();
}
- virtual void makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc,
- bool Complain) { }
+ void makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc,
+ bool Complain) override { }
+
+ GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
+ { return 0; }
+ bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
+ { return 0; };
};
// Stub to collect data from InclusionDirective callbacks.
diff --git a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
index 58857fa5a1..bacc899bec 100644
--- a/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
+++ b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
@@ -53,17 +53,22 @@ protected:
};
class VoidModuleLoader : public ModuleLoader {
- virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) {
+ ModuleLoadResult loadModule(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) override {
return ModuleLoadResult();
}
- virtual void makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind Visibility,
- SourceLocation ImportLoc,
- bool Complain) { }
+ void makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc,
+ bool Complain) override { }
+
+ GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
+ { return 0; }
+ bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
+ { return 0; };
};
TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) {
diff --git a/unittests/Tooling/RefactoringTest.cpp b/unittests/Tooling/RefactoringTest.cpp
index 8c7bfa1c76..b1ed3c72be 100644
--- a/unittests/Tooling/RefactoringTest.cpp
+++ b/unittests/Tooling/RefactoringTest.cpp
@@ -252,7 +252,9 @@ public:
// descriptor, which might not see the changes made.
// FIXME: Figure out whether there is a way to get the SourceManger to
// reopen the file.
- return Context.Files.getBufferForFile(Path, NULL)->getBuffer();
+ std::unique_ptr<const llvm::MemoryBuffer> FileBuffer(
+ Context.Files.getBufferForFile(Path, NULL));
+ return FileBuffer->getBuffer();
}
llvm::StringMap<std::string> TemporaryFiles;
diff --git a/unittests/Tooling/RewriterTestContext.h b/unittests/Tooling/RewriterTestContext.h
index 841cd0f909..f02ba1a9ff 100644
--- a/unittests/Tooling/RewriterTestContext.h
+++ b/unittests/Tooling/RewriterTestContext.h
@@ -52,7 +52,7 @@ class RewriterTestContext {
llvm::MemoryBuffer::getMemBuffer(Content);
const FileEntry *Entry =
Files.getVirtualFile(Name, Source->getBufferSize(), 0);
- Sources.overrideFileContents(Entry, Source, true);
+ Sources.overrideFileContents(Entry, Source);
assert(Entry != NULL);
return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
}
@@ -102,7 +102,9 @@ class RewriterTestContext {
// descriptor, which might not see the changes made.
// FIXME: Figure out whether there is a way to get the SourceManger to
// reopen the file.
- return Files.getBufferForFile(Path, NULL)->getBuffer();
+ std::unique_ptr<const llvm::MemoryBuffer> FileBuffer(
+ Files.getBufferForFile(Path, NULL));
+ return FileBuffer->getBuffer();
}
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp
index 1eff6d064f..2d055e7085 100644
--- a/unittests/Tooling/ToolingTest.cpp
+++ b/unittests/Tooling/ToolingTest.cpp
@@ -108,11 +108,11 @@ TEST(runToolOnCode, FindsClassDecl) {
}
TEST(buildASTFromCode, FindsClassDecl) {
- std::unique_ptr<ASTUnit> AST(buildASTFromCode("class X;"));
+ std::unique_ptr<ASTUnit> AST = buildASTFromCode("class X;");
ASSERT_TRUE(AST.get());
EXPECT_TRUE(FindClassDeclX(AST.get()));
- AST.reset(buildASTFromCode("class Y;"));
+ AST = buildASTFromCode("class Y;");
ASSERT_TRUE(AST.get());
EXPECT_FALSE(FindClassDeclX(AST.get()));
}
@@ -206,7 +206,9 @@ TEST(newFrontendActionFactory, InjectsSourceFileCallbacks) {
Tool.mapVirtualFile("/a.cc", "void a() {}");
Tool.mapVirtualFile("/b.cc", "void b() {}");
- Tool.run(newFrontendActionFactory(&EndCallback, &EndCallback));
+ std::unique_ptr<FrontendActionFactory> Action(
+ newFrontendActionFactory(&EndCallback, &EndCallback));
+ Tool.run(Action.get());
EXPECT_TRUE(EndCallback.Matched);
EXPECT_EQ(2u, EndCallback.BeginCalled);
@@ -277,10 +279,13 @@ TEST(ClangToolTest, ArgumentAdjusters) {
ClangTool Tool(Compilations, std::vector<std::string>(1, "/a.cc"));
Tool.mapVirtualFile("/a.cc", "void a() {}");
+ std::unique_ptr<FrontendActionFactory> Action(
+ newFrontendActionFactory<SyntaxOnlyAction>());
+
bool Found = false;
bool Ran = false;
Tool.appendArgumentsAdjuster(new CheckSyntaxOnlyAdjuster(Found, Ran));
- Tool.run(newFrontendActionFactory<SyntaxOnlyAction>());
+ Tool.run(Action.get());
EXPECT_TRUE(Ran);
EXPECT_TRUE(Found);
@@ -288,7 +293,7 @@ TEST(ClangToolTest, ArgumentAdjusters) {
Tool.clearArgumentsAdjusters();
Tool.appendArgumentsAdjuster(new CheckSyntaxOnlyAdjuster(Found, Ran));
Tool.appendArgumentsAdjuster(new ClangSyntaxOnlyAdjuster());
- Tool.run(newFrontendActionFactory<SyntaxOnlyAction>());
+ Tool.run(Action.get());
EXPECT_TRUE(Ran);
EXPECT_FALSE(Found);
}
@@ -305,11 +310,9 @@ TEST(ClangToolTest, BuildASTs) {
Tool.mapVirtualFile("/a.cc", "void a() {}");
Tool.mapVirtualFile("/b.cc", "void b() {}");
- std::vector<ASTUnit *> ASTs;
+ std::vector<std::unique_ptr<ASTUnit>> ASTs;
EXPECT_EQ(0, Tool.buildASTs(ASTs));
EXPECT_EQ(2u, ASTs.size());
-
- llvm::DeleteContainerPointers(ASTs);
}
struct TestDiagnosticConsumer : public DiagnosticConsumer {
@@ -327,7 +330,9 @@ TEST(ClangToolTest, InjectDiagnosticConsumer) {
Tool.mapVirtualFile("/a.cc", "int x = undeclared;");
TestDiagnosticConsumer Consumer;
Tool.setDiagnosticConsumer(&Consumer);
- Tool.run(newFrontendActionFactory<SyntaxOnlyAction>());
+ std::unique_ptr<FrontendActionFactory> Action(
+ newFrontendActionFactory<SyntaxOnlyAction>());
+ Tool.run(Action.get());
EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen);
}
@@ -337,7 +342,7 @@ TEST(ClangToolTest, InjectDiagnosticConsumerInBuildASTs) {
Tool.mapVirtualFile("/a.cc", "int x = undeclared;");
TestDiagnosticConsumer Consumer;
Tool.setDiagnosticConsumer(&Consumer);
- std::vector<ASTUnit*> ASTs;
+ std::vector<std::unique_ptr<ASTUnit>> ASTs;
Tool.buildASTs(ASTs);
EXPECT_EQ(1u, ASTs.size());
EXPECT_EQ(1u, Consumer.NumDiagnosticsSeen);
diff --git a/unittests/libclang/LibclangTest.cpp b/unittests/libclang/LibclangTest.cpp
index 64128f158f..addffe5036 100644
--- a/unittests/libclang/LibclangTest.cpp
+++ b/unittests/libclang/LibclangTest.cpp
@@ -49,14 +49,14 @@ struct TestVFO {
}
~TestVFO() {
- if (!Contents)
- return;
- char *BufPtr;
- unsigned BufSize;
- clang_VirtualFileOverlay_writeToBuffer(VFO, 0, &BufPtr, &BufSize);
- std::string BufStr(BufPtr, BufSize);
- EXPECT_STREQ(Contents, BufStr.c_str());
- free(BufPtr);
+ if (Contents) {
+ char *BufPtr;
+ unsigned BufSize;
+ clang_VirtualFileOverlay_writeToBuffer(VFO, 0, &BufPtr, &BufSize);
+ std::string BufStr(BufPtr, BufSize);
+ EXPECT_STREQ(Contents, BufStr.c_str());
+ free(BufPtr);
+ }
clang_VirtualFileOverlay_dispose(VFO);
}
};
@@ -85,6 +85,27 @@ TEST(libclang, VirtualFileOverlay) {
T.map("/path/virtual/foo.h", "/real/foo.h");
}
{
+ const char *contents =
+ "{\n"
+ " 'version': 0,\n"
+ " 'roots': [\n"
+ " {\n"
+ " 'type': 'directory',\n"
+ " 'name': \"/path/virtual\",\n"
+ " 'contents': [\n"
+ " {\n"
+ " 'type': 'file',\n"
+ " 'name': \"\\u2602.h\",\n"
+ " 'external-contents': \"/real/\\u2602.h\"\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " ]\n"
+ "}\n";
+ TestVFO T(contents);
+ T.map("/path/virtual/☂.h", "/real/☂.h");
+ }
+ {
TestVFO T(NULL);
T.mapError("/path/./virtual/../foo.h", "/real/foo.h",
CXError_InvalidArguments);
diff --git a/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp b/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp
index bfcd2cfd15..2a9110f8eb 100644
--- a/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp
+++ b/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
+#include "TableGenBackends.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/StringMatcher.h"
#include "llvm/TableGen/TableGenBackend.h"
@@ -19,14 +20,11 @@
using namespace llvm;
-namespace clang {
-void EmitClangCommentHTMLTags(RecordKeeper &Records, raw_ostream &OS) {
+void clang::EmitClangCommentHTMLTags(RecordKeeper &Records, raw_ostream &OS) {
std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Tag");
std::vector<StringMatcher::StringPair> Matches;
- for (std::vector<Record *>::iterator I = Tags.begin(), E = Tags.end();
- I != E; ++I) {
- Record &Tag = **I;
- std::string Spelling = Tag.getValueAsString("Spelling");
+ for (Record *Tag : Tags) {
+ std::string Spelling = Tag->getValueAsString("Spelling");
Matches.push_back(StringMatcher::StringPair(Spelling, "return true;"));
}
@@ -38,19 +36,17 @@ void EmitClangCommentHTMLTags(RecordKeeper &Records, raw_ostream &OS) {
<< "}\n\n";
}
-void EmitClangCommentHTMLTagsProperties(RecordKeeper &Records,
- raw_ostream &OS) {
+void clang::EmitClangCommentHTMLTagsProperties(RecordKeeper &Records,
+ raw_ostream &OS) {
std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Tag");
std::vector<StringMatcher::StringPair> MatchesEndTagOptional;
std::vector<StringMatcher::StringPair> MatchesEndTagForbidden;
- for (std::vector<Record *>::iterator I = Tags.begin(), E = Tags.end();
- I != E; ++I) {
- Record &Tag = **I;
- std::string Spelling = Tag.getValueAsString("Spelling");
+ for (Record *Tag : Tags) {
+ std::string Spelling = Tag->getValueAsString("Spelling");
StringMatcher::StringPair Match(Spelling, "return true;");
- if (Tag.getValueAsBit("EndTagOptional"))
+ if (Tag->getValueAsBit("EndTagOptional"))
MatchesEndTagOptional.push_back(Match);
- if (Tag.getValueAsBit("EndTagForbidden"))
+ if (Tag->getValueAsBit("EndTagForbidden"))
MatchesEndTagForbidden.push_back(Match);
}
@@ -65,6 +61,21 @@ void EmitClangCommentHTMLTagsProperties(RecordKeeper &Records,
StringMatcher("Name", MatchesEndTagForbidden, OS).Emit();
OS << " return false;\n"
<< "}\n\n";
+
+ std::vector<Record *> Attributes =
+ Records.getAllDerivedDefinitions("Attribute");
+ std::vector<StringMatcher::StringPair> Matches;
+ for (Record *Attribute : Attributes) {
+ std::string Spelling = Attribute->getValueAsString("Spelling");
+ if (!Attribute->getValueAsBit("IsSafeToPassThrough"))
+ Matches.push_back(StringMatcher::StringPair(Spelling, "return false;"));
+ }
+
+ emitSourceFileHeader("HTML attribute name matcher", OS);
+
+ OS << "bool isHTMLAttributeSafeToPassThrough(StringRef Name) {\n";
+ StringMatcher("Name", Matches, OS).Emit();
+ OS << " return true;\n"
+ << "}\n\n";
}
-} // end namespace clang
diff --git a/www/analyzer/open_projects.html b/www/analyzer/open_projects.html
index 4a888adbb6..75c069260c 100644
--- a/www/analyzer/open_projects.html
+++ b/www/analyzer/open_projects.html
@@ -56,7 +56,7 @@ mailing list</a> to notify other members of the community.</p>
<li>Enhance CFG to model C++ temporaries properly.
<p>There is an existing implementation of this, but it's not complete and
is disabled in the analyzer.
- <i>(Difficulty: Medium)</i></p>
+ <i>(Difficulty: Medium; current contact: Alex McCarthy)</i></p>
<li>Enhance CFG to model exception-handling properly.
<p>Currently exceptions are treated as "black holes", and exception-handling
@@ -70,7 +70,7 @@ mailing list</a> to notify other members of the community.</p>
(<code>operator new</code>), then initialize the result with a constructor
call. The problem is discussed at length in
<a href="http://llvm.org/bugs/show_bug.cgi?id=12014">PR12014</a>.
- <i>(Difficulty: Easy)</i></p>
+ <i>(Difficulty: Easy; current contact: Karthik Bhat)</i></p>
<li>Enhance CFG to model C++ <code>delete</code> more precisely.
<p>Similarly, the representation of <code>delete</code> does not include
@@ -78,7 +78,14 @@ mailing list</a> to notify other members of the community.</p>
function (<code>operator delete</code>). One particular issue
(<tt>noreturn</tt> destructors) is discussed in
<a href="http://llvm.org/bugs/show_bug.cgi?id=15599">PR15599</a>
- <i>(Difficulty: Easy)</i></p>
+ <i>(Difficulty: Easy; current contact: Karthik Bhat)</i></p>
+
+ <li>Implement a BitwiseConstraintManager to handle <a href="http://llvm.org/bugs/show_bug.cgi?id=3098">PR3098</a>.
+ <p>Constraints on the bits of an integer are not easily representable as
+ ranges. A bitwise constraint manager would model constraints such as "bit 32
+ is known to be 1". This would help code that made use of bitmasks</code>.
+ <i>(Difficulty: Medium)</i></p>
+ </li>
<li>Track type info through casts more precisely.
<p>The DynamicTypePropagation checker is in charge of inferring a region's
@@ -107,14 +114,6 @@ mailing list</a> to notify other members of the community.</p>
display such paths in HTML output. <i>(Difficulty: Medium)</i> </p>
</li>
- <li>Relate bugs to checkers / "bug types"
- <p>We need to come up with an API which will relate bug reports
- to the checkers that produce them and refactor the existing code to use the
- new API. This would allow us to identify the checker from the bug report,
- which paves the way for selective control of certain checks.
- <i>(Difficulty: Easy-Medium)</i></p>
- </li>
-
<li>Refactor path diagnostic generation in <a href="http://clang.llvm.org/doxygen/BugReporter_8cpp_source.html">BugReporter.cpp</a>.
<p>It would be great to have more code reuse between "Minimal" and
"Extensive" PathDiagnostic generation algorithms. One idea is to create an
@@ -182,7 +181,7 @@ mailing list</a> to notify other members of the community.</p>
<p>Take a look at the
<a href="http://pages.cs.wisc.edu/~shanlu/paper/TSE-CPMiner.pdf">CP-Miner</a>
paper for inspiration.
- <i>(Difficulty: Medium-Hard)</i></p>
+ <i>(Difficulty: Medium-Hard; current contacts: Per Viberg and Daniel Fahlgren)</i></p>
</li>
</ul>
</li>
diff --git a/www/analyzer/potential_checkers.html b/www/analyzer/potential_checkers.html
index 5b32dd0329..335e50d848 100644
--- a/www/analyzer/potential_checkers.html
+++ b/www/analyzer/potential_checkers.html
@@ -314,6 +314,34 @@ int foo(bool cond) {
</table>
+<!-- =============================== POSIX ================================= -->
+<h3>POSIX</h3>
+<table class="checkers">
+<col class="namedescr"><col class="example"><col class="progress">
+<thead><tr><td>Name, Description</td><td>Example</td><td>Progress</td></tr></thead>
+
+<tr><td><span class="name">posix.Errno</span><br><br>
+Record that <code>errno</code> is non-zero when certain functions fail.
+</td><td><pre>
+#include &lt;stdlib.h&gt;
+
+int readWrapper(int fd, int *count) {
+ int lcount = read(fd, globalBuf, sizeof(globalBuf));
+ if (lcount &lt; 0)
+ return errno;
+ *count = lcount;
+ return 0;
+}
+
+void use(int fd) {
+ int count;
+ if (!readWrapper(fd, &amp;count))
+ print("%d", count); // should not warn
+}
+</pre></td><td class="aligned"><a href="http://llvm.org/bugs/show_bug.cgi?id=18701">PR18701</a></td></tr>
+
+</table>
+
<!-- ========================= undefined behavior ========================== -->
<h3>undefined behavior</h3>
<table class="checkers">
diff --git a/www/comparison.html b/www/comparison.html
index 40a0d001b2..e76a07b683 100644
--- a/www/comparison.html
+++ b/www/comparison.html
@@ -31,7 +31,7 @@
analysis, you may not care that something lacks codegen support, for
example.</p>
- <p>Please email cfe-dev if you think we should add another compiler to this
+ <p>Please email <a href="get_involved.html">cfe-dev</a> if you think we should add another compiler to this
list or if you think some characterization is unfair here.</p>
<ul>
@@ -49,7 +49,7 @@
<ul>
<li>GCC supports languages that clang does not aim to, such as Java, Ada,
- FORTRAN, etc.</li>
+ FORTRAN, Go, etc.</li>
<li>GCC supports more targets than LLVM.</li>
<li>GCC supports many language extensions, some of which are not implemented
by Clang. For instance, in C mode, GCC supports
@@ -82,13 +82,6 @@
custom garbage collector, uses global variables extensively, is not
reentrant or multi-threadable, etc. Clang has none of these problems.
</li>
- <li>For every token, clang tracks information about where it was written and
- where it was ultimately expanded into if it was involved in a macro.
- GCC does not track information about macro instantiations when parsing
- source code. This makes it very difficult for source rewriting tools
- (e.g. for refactoring) to work in the presence of (even simple)
- macros. This appears to be partially or fully addressed in recent
- releases of GCC.</li>
<li>Clang does not implicitly simplify code as it parses it like GCC does.
Doing so causes many problems for source analysis tools: as one simple
example, if you write "x-x" in your source code, the GCC AST will
diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html
index 73bb160e49..1ada70c702 100644
--- a/www/cxx_dr_status.html
+++ b/www/cxx_dr_status.html
@@ -3047,13 +3047,13 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#501">501</a></td>
<td>NAD</td>
<td>Visibility of friend declarations within the befriending class</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="502">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#502">502</a></td>
<td>C++11</td>
<td>Dependency of nested enumerations and enumerators</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr class="open" id="503">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#503">503</a></td>
@@ -3071,37 +3071,37 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#505">505</a></td>
<td>CD1</td>
<td>Conditionally-supported behavior for unknown character escapes</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="506">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#506">506</a></td>
<td>CD1</td>
<td>Conditionally-supported behavior for non-POD objects passed to ellipsis</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="507">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#507">507</a></td>
<td>dup</td>
<td>Ambiguity assigning class object to built-in type</td>
- <td class="none" align="center">Unknown</td>
+ <td class="none" align="center">Duplicate of <a href="#260">260</a></td>
</tr>
<tr id="508">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#508">508</a></td>
<td>C++11</td>
<td>Non-constructed value-initialized objects</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="509">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#509">509</a></td>
<td>CD1</td>
<td>Dead code in the specification of default initialization</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="510">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#510">510</a></td>
<td>CD1</td>
<td>Default initialization of POD classes?</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr class="open" id="511">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#511">511</a></td>
@@ -3113,67 +3113,67 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#512">512</a></td>
<td>NAD</td>
<td>Union members with user-declared non-default constructors</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="513">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#513">513</a></td>
<td>CD1</td>
<td>Non-class &#8220;most-derived&#8221; objects</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="514">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#514">514</a></td>
<td>CD1</td>
<td>Is the initializer for a namespace member in the scope of the namespace?</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="515">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#515">515</a></td>
<td>CD1</td>
<td>Non-dependent references to base class members</td>
- <td class="none" align="center">Unknown</td>
+ <td class="none" align="center">Superseded by <a href="#1017">1017</a></td>
</tr>
<tr id="516">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#516">516</a></td>
<td>CD1</td>
<td>Use of <TT>signed</TT> in bit-field declarations</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="517">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#517">517</a></td>
<td>CD1</td>
<td>Partial specialization following explicit instantiation</td>
- <td class="none" align="center">Unknown</td>
+ <td class="none" align="center">No</td>
</tr>
<tr id="518">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#518">518</a></td>
<td>CD1</td>
<td>Trailing comma following <I>enumerator-list</I></td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes (C++11 onwards)</td>
</tr>
<tr id="519">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#519">519</a></td>
<td>CD1</td>
<td>Null pointer preservation in <TT>void*</TT> conversions</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="520">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#520">520</a></td>
<td>CD1</td>
<td>Old-style casts between incomplete class types</td>
- <td class="none" align="center">Unknown</td>
+ <td class="na" align="center">N/A</td>
</tr>
<tr id="521">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#521">521</a></td>
<td>CD1</td>
<td>Requirements for exceptions thrown by allocation functions</td>
- <td class="none" align="center">Unknown</td>
+ <td class="none" align="center">No</td>
</tr>
<tr id="522">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#522">522</a></td>
<td>CD1</td>
<td>Array-to-pointer decay in template argument deduction</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr class="open" id="523">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#523">523</a></td>
@@ -3185,13 +3185,13 @@ of class templates</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#524">524</a></td>
<td>CD1</td>
<td>Can function-notation calls to operator functions be dependent?</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="525">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#525">525</a></td>
<td>CD1</td>
<td>Missing <TT>*</TT> in example</td>
- <td class="none" align="center">Unknown</td>
+ <td class="full" align="center">Yes</td>
</tr>
<tr id="526">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#526">526</a></td>
diff --git a/www/features.html b/www/features.html
index d6d992b548..8a1c856cd1 100644
--- a/www/features.html
+++ b/www/features.html
@@ -65,71 +65,18 @@ These features are:
<p>A major focus of our work on clang is to make it fast, light and scalable.
The library-based architecture of clang makes it straight-forward to time and
profile the cost of each layer of the stack, and the driver has a number of
-options for performance analysis.</p>
-
-<p>While there is still much that can be done, we find that the clang front-end
-is significantly quicker than gcc and uses less memory For example, when
-compiling "Carbon.h" on Mac OS X, we see that clang is 2.5x faster than GCC:</p>
-
-<img class="img_slide" src="feature-compile1.png" width="400" height="300"
- alt="Time to parse carbon.h: -fsyntax-only">
-
-<p>Carbon.h is a monster: it transitively includes 558 files, 12.3M of code,
-declares 10000 functions, has 2000 struct definitions, 8000 fields, 20000 enum
-constants, etc (see slide 25+ of the <a href="clang_video-07-25-2007.html">clang
-talk</a> for more information). It is also #include'd into almost every C file
-in a GUI app on the Mac, so its compile time is very important.</p>
-
-<p>From the slide above, you can see that we can measure the time to preprocess
-the file independently from the time to parse it, and independently from the
-time to build the ASTs for the code. GCC doesn't provide a way to measure the
-parser without AST building (it only provides -fsyntax-only). In our
-measurements, we find that clang's preprocessor is consistently 40% faster than
-GCCs, and the parser + AST builder is ~4x faster than GCC's. If you have
-sources that do not depend as heavily on the preprocessor (or if you
-use Precompiled Headers) you may see a much bigger speedup from clang.
-</p>
+options for performance analysis. Many detailed benchmarks can be found online.</p>
<p>Compile time performance is important, but when using clang as an API, often
memory use is even moreso: the less memory the code takes the more code you can
fit into memory at a time (useful for whole program analysis tools, for
example).</p>
-<img class="img_slide" src="feature-memory1.png" width="400" height="300"
- alt="Space">
-
-<p>Here we see a huge advantage of clang: its ASTs take <b>5x less memory</b>
-than GCC's syntax trees, despite the fact that clang's ASTs capture far more
-source-level information than GCC's trees do. This feat is accomplished through
-the use of carefully designed APIs and efficient representations.</p>
-
<p>In addition to being efficient when pitted head-to-head against GCC in batch
-mode, clang is built with a <a href="#libraryarch">library based
+mode, clang is built with a <a href="#libraryarch">library based
architecture</a> that makes it relatively easy to adapt it and build new tools
with it. This means that it is often possible to apply out-of-the-box thinking
-and novel techniques to improve compilation in various ways.</p>
-
-<img class="img_slide" src="feature-compile2.png" width="400" height="300"
- alt="Preprocessor Speeds: GCC 4.2 vs clang-all">
-
-<p>This slide shows how the clang preprocessor can be used to make "distcc"
-parallelization <b>3x</b> more scalable than when using the GCC preprocessor.
-"distcc" quickly bottlenecks on the preprocessor running on the central driver
-machine, so a fast preprocessor is very useful. Comparing the first two bars
-of each group shows how a ~40% faster preprocessor can reduce preprocessing time
-of these large C++ apps by about 40% (shocking!).</p>
-
-<p>The third bar on the slide is the interesting part: it shows how trivial
-caching of file system accesses across invocations of the preprocessor allows
-clang to reduce time spent in the kernel by 10x, making distcc over 3x more
-scalable. This is obviously just one simple hack, doing more interesting things
-(like caching tokens across preprocessed files) would yield another substantial
-speedup.</p>
-
-<p>The clean framework-based design of clang means that many things are possible
-that would be very difficult in other systems, for example incremental
-compilation, multithreading, intelligent caching, etc. We are only starting
-to tap the full potential of the clang design.</p>
+and novel techniques to improve compilation in various ways.</p>
<!--=======================================================================-->
@@ -157,7 +104,7 @@ GCC and Clang diagnostic:</p>
</pre>
<p>Here you can see that you don't even need to see the original source code to
-understand what is wrong based on the Clang error: Because clang prints a
+understand what is wrong based on the Clang error: Because Clang prints a
caret, you know exactly <em>which</em> plus it is complaining about. The range
information highlights the left and right side of the plus which makes it
immediately obvious what the compiler is talking about, which is very useful for
diff --git a/www/get_started.html b/www/get_started.html
index c7ec3eba3a..6f08f5e6f0 100644
--- a/www/get_started.html
+++ b/www/get_started.html
@@ -23,9 +23,8 @@ bugs in <a href="http://llvm.org/bugs/">LLVM Bugzilla</a>.</p>
<h2 id="download">Release Clang Versions</h2>
-<p>Clang has been released as part of regular LLVM releases since LLVM 2.6. You
-can download the release versions
-from <a href="http://llvm.org/releases/">http://llvm.org/releases/</a>.</p>
+<p>Clang is released as part of regular LLVM releases. You can download the release versions from <a href="http://llvm.org/releases/">http://llvm.org/releases/</a>.</p>
+<p>Clang is also provided in all major BSD or GNU/Linux distributions as part of their respective packaging systems. From Xcode 4.2, Clang is the default compiler for Mac OS X.</p>
<h2 id="build">Building Clang and Working with the Code</h2>
diff --git a/www/related.html b/www/related.html
index 8191daabb1..62dd2632cd 100644
--- a/www/related.html
+++ b/www/related.html
@@ -19,7 +19,7 @@
custom analysis tools using Clang. This page tracks some of those Clang
related projects.</p>
- <p>Please email cfe-dev if you have a Clang related project you would like
+ <p>Please email <a href="get_involved.html">cfe-dev</a> if you have a Clang related project you would like
added to this list.</p>
<dl>