aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt5
-rw-r--r--docs/AutomaticReferenceCounting.rst35
-rw-r--r--docs/ClangFormat.rst6
-rw-r--r--docs/ClangTools.rst27
-rw-r--r--docs/ExternalClangExamples.rst8
-rw-r--r--docs/LibASTMatchersReference.html159
-rw-r--r--docs/LibASTMatchersTutorial.rst76
-rw-r--r--docs/UsersManual.rst2
-rw-r--r--include/clang-c/Index.h47
-rw-r--r--include/clang/AST/ASTContext.h3
-rw-r--r--include/clang/AST/AttrIterator.h1
-rw-r--r--include/clang/AST/CharUnits.h11
-rw-r--r--include/clang/AST/Comment.h56
-rw-r--r--include/clang/AST/CommentCommandTraits.h12
-rw-r--r--include/clang/AST/CommentCommands.td48
-rw-r--r--include/clang/AST/CommentLexer.h11
-rw-r--r--include/clang/AST/CommentParser.h2
-rw-r--r--include/clang/AST/CommentSema.h23
-rw-r--r--include/clang/AST/Decl.h35
-rw-r--r--include/clang/AST/DeclObjC.h7
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h2
-rw-r--r--include/clang/AST/Type.h2
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h117
-rw-r--r--include/clang/ASTMatchers/ASTMatchersInternal.h38
-rw-r--r--include/clang/Basic/Attr.td3
-rw-r--r--include/clang/Basic/Diagnostic.h2
-rw-r--r--include/clang/Basic/DiagnosticCommentKinds.td40
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td7
-rw-r--r--include/clang/Basic/DiagnosticGroups.td1
-rw-r--r--include/clang/Basic/DiagnosticIDs.h2
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td10
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td6
-rw-r--r--include/clang/Basic/DiagnosticSerializationKinds.td2
-rw-r--r--include/clang/Basic/TokenKinds.h18
-rw-r--r--include/clang/Driver/CC1Options.td6
-rw-r--r--include/clang/Driver/Options.td2
-rw-r--r--include/clang/Driver/Phases.h4
-rw-r--r--include/clang/Driver/ToolChain.h2
-rw-r--r--include/clang/Driver/Types.h13
-rw-r--r--include/clang/Frontend/ASTUnit.h3
-rw-r--r--include/clang/Frontend/CodeGenOptions.def2
-rw-r--r--include/clang/Frontend/CodeGenOptions.h4
-rw-r--r--include/clang/Parse/Parser.h6
-rw-r--r--include/clang/Sema/AttributeList.h52
-rw-r--r--include/clang/Sema/DeclSpec.h72
-rw-r--r--include/clang/Sema/Sema.h44
-rw-r--r--include/clang/Serialization/ASTReader.h6
-rw-r--r--include/clang/Serialization/Module.h39
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h40
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h21
-rw-r--r--lib/ARCMigrate/TransUnbridgedCasts.cpp4
-rw-r--r--lib/ARCMigrate/Transforms.cpp4
-rw-r--r--lib/AST/ASTContext.cpp57
-rw-r--r--lib/AST/ASTImporter.cpp7
-rw-r--r--lib/AST/CommentBriefParser.cpp2
-rw-r--r--lib/AST/CommentLexer.cpp7
-rw-r--r--lib/AST/CommentParser.cpp22
-rw-r--r--lib/AST/CommentSema.cpp232
-rw-r--r--lib/AST/Decl.cpp13
-rw-r--r--lib/AST/DeclObjC.cpp53
-rw-r--r--lib/AST/ExprCXX.cpp3
-rw-r--r--lib/AST/LambdaMangleContext.cpp9
-rw-r--r--lib/AST/TemplateName.cpp2
-rw-r--r--lib/AST/Type.cpp22
-rw-r--r--lib/Basic/DiagnosticIDs.cpp6
-rw-r--r--lib/Basic/SourceManager.cpp12
-rw-r--r--lib/Basic/Targets.cpp135
-rw-r--r--lib/CodeGen/ABIInfo.h13
-rw-r--r--lib/CodeGen/BackendUtil.cpp6
-rw-r--r--lib/CodeGen/CGAtomic.cpp942
-rw-r--r--lib/CodeGen/CGBlocks.cpp46
-rw-r--r--lib/CodeGen/CGBuiltin.cpp8
-rw-r--r--lib/CodeGen/CGCUDANV.cpp4
-rw-r--r--lib/CodeGen/CGCall.cpp284
-rw-r--r--lib/CodeGen/CGClass.cpp32
-rw-r--r--lib/CodeGen/CGCleanup.cpp12
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp111
-rw-r--r--lib/CodeGen/CGDebugInfo.h15
-rw-r--r--lib/CodeGen/CGDecl.cpp26
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp20
-rw-r--r--lib/CodeGen/CGException.cpp117
-rw-r--r--lib/CodeGen/CGExpr.cpp624
-rw-r--r--lib/CodeGen/CGExprAgg.cpp189
-rw-r--r--lib/CodeGen/CGExprCXX.cpp26
-rw-r--r--lib/CodeGen/CGExprComplex.cpp121
-rw-r--r--lib/CodeGen/CGExprConstant.cpp2
-rw-r--r--lib/CodeGen/CGExprScalar.cpp115
-rw-r--r--lib/CodeGen/CGObjC.cpp103
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp147
-rw-r--r--lib/CodeGen/CGObjCMac.cpp258
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp2
-rw-r--r--lib/CodeGen/CGObjCRuntime.h10
-rw-r--r--lib/CodeGen/CGStmt.cpp41
-rw-r--r--lib/CodeGen/CGVTables.cpp2
-rw-r--r--lib/CodeGen/CGValue.h34
-rw-r--r--lib/CodeGen/CMakeLists.txt1
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp107
-rw-r--r--lib/CodeGen/CodeGenFunction.h87
-rw-r--r--lib/CodeGen/CodeGenModule.cpp35
-rw-r--r--lib/CodeGen/CodeGenModule.h10
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp24
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp10
-rw-r--r--lib/CodeGen/TargetInfo.cpp76
-rw-r--r--lib/Driver/Driver.cpp17
-rw-r--r--lib/Driver/ToolChain.cpp16
-rw-r--r--lib/Driver/ToolChains.cpp45
-rw-r--r--lib/Driver/ToolChains.h13
-rw-r--r--lib/Driver/Tools.cpp51
-rw-r--r--lib/Driver/Types.cpp62
-rw-r--r--lib/Format/Format.cpp175
-rw-r--r--lib/Format/TokenAnnotator.cpp53
-rw-r--r--lib/Format/TokenAnnotator.h5
-rw-r--r--lib/Format/UnwrappedLineParser.cpp11
-rw-r--r--lib/Format/UnwrappedLineParser.h8
-rw-r--r--lib/Frontend/ASTUnit.cpp9
-rw-r--r--lib/Frontend/CompilerInvocation.cpp25
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp11
-rw-r--r--lib/Headers/altivec.h28
-rw-r--r--lib/Lex/HeaderSearch.cpp4
-rw-r--r--lib/Lex/Lexer.cpp35
-rw-r--r--lib/Lex/MacroArgs.cpp14
-rw-r--r--lib/Lex/PPDirectives.cpp21
-rw-r--r--lib/Lex/Pragma.cpp57
-rw-r--r--lib/Parse/ParseDecl.cpp46
-rw-r--r--lib/Rewrite/Frontend/RewriteModernObjC.cpp59
-rw-r--r--lib/Rewrite/Frontend/RewriteObjC.cpp46
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp2
-rw-r--r--lib/Sema/Sema.cpp6
-rw-r--r--lib/Sema/SemaChecking.cpp8
-rw-r--r--lib/Sema/SemaCodeComplete.cpp17
-rw-r--r--lib/Sema/SemaDecl.cpp104
-rw-r--r--lib/Sema/SemaDeclAttr.cpp81
-rw-r--r--lib/Sema/SemaDeclCXX.cpp69
-rw-r--r--lib/Sema/SemaDeclObjC.cpp6
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp18
-rw-r--r--lib/Sema/SemaExpr.cpp122
-rw-r--r--lib/Sema/SemaExprCXX.cpp10
-rw-r--r--lib/Sema/SemaExprObjC.cpp121
-rw-r--r--lib/Sema/SemaLambda.cpp267
-rw-r--r--lib/Sema/SemaLookup.cpp2
-rw-r--r--lib/Sema/SemaStmt.cpp1
-rw-r--r--lib/Sema/SemaTemplate.cpp13
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp9
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp4
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp20
-rw-r--r--lib/Sema/SemaType.cpp167
-rw-r--r--lib/Sema/TreeTransform.h60
-rw-r--r--lib/Serialization/ASTReader.cpp118
-rw-r--r--lib/Serialization/ASTReaderInternals.h32
-rw-r--r--lib/Serialization/ASTWriter.cpp66
-rw-r--r--lib/Serialization/Module.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp132
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt2
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td6
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp118
-rw-r--r--lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp193
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp12
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp96
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp414
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp1
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp10
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp7
-rw-r--r--lib/Tooling/JSONCompilationDatabase.cpp17
-rw-r--r--test/Analysis/Inputs/system-header-simulator-for-malloc.h34
-rw-r--r--test/Analysis/diagnostics/deref-track-symbolic-region.c197
-rw-r--r--test/Analysis/diagnostics/deref-track-symbolic-region.cpp12
-rw-r--r--test/Analysis/fields.c87
-rw-r--r--test/Analysis/initializer.cpp3
-rw-r--r--test/Analysis/inline-plist.c2
-rw-r--r--test/Analysis/inlining/eager-reclamation-path-notes.cpp419
-rw-r--r--test/Analysis/inlining/false-positive-suppression.cpp101
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.c99
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.cpp32
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.m46
-rw-r--r--test/Analysis/inlining/path-notes.c1004
-rw-r--r--test/Analysis/inlining/path-notes.cpp810
-rw-r--r--test/Analysis/malloc.mm47
-rw-r--r--test/Analysis/misc-ps-region-store.m2
-rw-r--r--test/Analysis/objc-method-coverage.m3
-rw-r--r--test/Analysis/reference.cpp85
-rw-r--r--test/Analysis/retain-release-cf-audited.m33
-rw-r--r--test/Analysis/stats.c1
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp2
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp5
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp18
-rw-r--r--test/CodeGen/2008-04-08-NoExceptions.c6
-rw-r--r--test/CodeGen/address-safety-attr.cpp72
-rw-r--r--test/CodeGen/atomic_ops.c5
-rw-r--r--test/CodeGen/builtins-ppc-altivec.c28
-rw-r--r--test/CodeGen/c11atomics-ios.c214
-rw-r--r--test/CodeGen/c11atomics.c344
-rw-r--r--test/CodeGen/compound-literal.c34
-rw-r--r--test/CodeGen/function-attributes.c8
-rw-r--r--test/CodeGen/mips-constraint-regs.c4
-rw-r--r--test/CodeGen/mips-constraints-mem.c26
-rw-r--r--test/CodeGen/sanitize-thread-attr.cpp48
-rw-r--r--test/CodeGen/string-literal.c72
-rw-r--r--test/CodeGen/unwind-attr.c5
-rw-r--r--test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp19
-rw-r--r--test/CodeGenCXX/attr.cpp2
-rw-r--r--test/CodeGenCXX/blocks-cxx11.cpp30
-rw-r--r--test/CodeGenCXX/cxx11-exception-spec.cpp13
-rw-r--r--test/CodeGenCXX/default-destructor-synthesis.cpp4
-rw-r--r--test/CodeGenCXX/derived-to-base.cpp6
-rw-r--r--test/CodeGenCXX/exceptions.cpp2
-rw-r--r--test/CodeGenCXX/extern-c.cpp32
-rw-r--r--test/CodeGenCXX/global-dtor-no-atexit.cpp10
-rw-r--r--test/CodeGenCXX/member-initializers.cpp4
-rw-r--r--test/CodeGenCXX/microsoft-abi-array-cookies.cpp4
-rw-r--r--test/CodeGenCXX/no-exceptions.cpp2
-rw-r--r--test/CodeGenCXX/pod-member-memcpys.cpp20
-rw-r--r--test/CodeGenCXX/pointers-to-data-members.cpp6
-rw-r--r--test/CodeGenCXX/reference-cast.cpp2
-rw-r--r--test/CodeGenCXX/runtimecc.cpp53
-rw-r--r--test/CodeGenCXX/threadsafe-statics.cpp4
-rw-r--r--test/CodeGenCXX/virtual-function-calls.cpp15
-rw-r--r--test/CodeGenObjC/arc-arm.m4
-rw-r--r--test/CodeGenObjC/arc.m1
-rw-r--r--test/CodeGenObjC/debug-info-ivars-extension.m33
-rw-r--r--test/CodeGenObjC/debug-info-ivars-indirect.m32
-rw-r--r--test/CodeGenObjC/debug-info-ivars-private.m36
-rw-r--r--test/CodeGenObjC/gnu-exceptions.m4
-rw-r--r--test/CodeGenObjCXX/arc-attrs.mm48
-rw-r--r--test/CodeGenObjCXX/message.mm24
-rw-r--r--test/CodeGenObjCXX/unknown-anytype.mm20
-rw-r--r--test/CodeGenOpenCL/addr-space-struct-arg.cl23
-rw-r--r--test/CodeGenOpenCL/kernel-attributes.cl12
-rw-r--r--test/Coverage/objc-language-features.inc1
-rw-r--r--test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbeginT.o0
-rw-r--r--test/Driver/Inputs/ubuntu_13.04_multiarch_tree/lib/x86_64-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/c++/4.7/backward/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/32/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/crtbegin.o0
-rw-r--r--test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o0
-rw-r--r--test/Driver/arm-cortex-cpus.c8
-rw-r--r--test/Driver/claim-unused.c3
-rw-r--r--test/Driver/darwin-iphone-defaults.m5
-rw-r--r--test/Driver/hexagon-toolchain.c16
-rw-r--r--test/Driver/linux-header-search.cpp28
-rw-r--r--test/Driver/linux-ld.c54
-rw-r--r--test/Driver/modules_integrated_as.c4
-rw-r--r--test/Driver/objc_default_synth.m6
-rw-r--r--test/FixIt/fixit-objc.m2
-rw-r--r--test/Index/complete-documentation-properties.m68
-rw-r--r--test/Index/complete-modules.m3
-rw-r--r--test/Index/file-includes.c24
-rw-r--r--test/Lexer/builtin_redef.c19
-rw-r--r--test/Lexer/char-literal.cpp18
-rw-r--r--test/Lexer/pragma-operators.cpp20
-rw-r--r--test/Lexer/string_concat.cpp15
-rw-r--r--test/Lexer/unicode-strings.c21
-rw-r--r--test/Lexer/utf8-char-literal.cpp1
-rw-r--r--test/Misc/warning-flags.c3
-rw-r--r--test/PCH/modified-header-error.c2
-rw-r--r--test/Parser/cxx-casting.cpp6
-rw-r--r--test/Parser/placeholder-recovery.m2
-rw-r--r--test/Preprocessor/c90.c5
-rw-r--r--test/Preprocessor/traditional-cpp.c10
-rw-r--r--test/Sema/warn-documentation.cpp83
-rw-r--r--test/Sema/warn-documentation.m60
-rw-r--r--test/SemaCXX/blocks.cpp15
-rw-r--r--test/SemaCXX/function-redecl.cpp11
-rw-r--r--test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp2
-rw-r--r--test/SemaCXX/overloaded-operator.cpp25
-rw-r--r--test/SemaCXX/pragma-weak.cpp8
-rw-r--r--test/SemaObjC/arc-objc-lifetime.m45
-rw-r--r--test/SemaObjC/bad-receiver-1.m3
-rw-r--r--test/SemaObjC/blocks.m20
-rw-r--r--test/SemaObjC/boxing-illegal.m (renamed from test/SemaObjC/boxing-illegal-types.m)17
-rw-r--r--test/SemaObjC/debugger-cast-result-to-id.m2
-rw-r--r--test/SemaObjC/message.m2
-rw-r--r--test/SemaObjC/protocol-archane.m6
-rw-r--r--test/SemaObjC/super-property-notation.m25
-rw-r--r--test/SemaObjC/super.m3
-rw-r--r--test/SemaObjC/warn-isa-ref.m8
-rw-r--r--test/SemaObjCXX/arc-nsconsumed-errors.mm32
-rw-r--r--test/SemaObjCXX/debugger-cast-result-to-id.mm34
-rw-r--r--test/SemaObjCXX/properties.mm35
-rw-r--r--test/SemaOpenCL/invalid-kernel-attrs.cl16
-rw-r--r--test/SemaTemplate/class-template-id.cpp2
-rw-r--r--test/SemaTemplate/destructor-template.cpp19
-rw-r--r--test/SemaTemplate/instantiate-type.cpp13
-rw-r--r--test/SemaTemplate/temp_arg.cpp2
-rw-r--r--test/SemaTemplate/temp_arg_type.cpp4
-rw-r--r--tools/c-index-test/c-index-test.c114
-rw-r--r--tools/driver/driver.cpp2
-rw-r--r--tools/libclang/CIndex.cpp45
-rw-r--r--tools/libclang/CIndexHigh.cpp187
-rw-r--r--tools/libclang/CLog.h3
-rw-r--r--tools/libclang/CXLoadedDiagnostic.cpp2
-rw-r--r--tools/libclang/CursorVisitor.h4
-rw-r--r--tools/libclang/libclang.exports2
-rwxr-xr-xtools/scan-build/scan-build1
-rw-r--r--unittests/AST/CommentLexer.cpp99
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.cpp81
-rw-r--r--unittests/Format/FormatTest.cpp158
-rw-r--r--unittests/Tooling/CompilationDatabaseTest.cpp6
-rw-r--r--utils/TableGen/ClangCommentCommandInfoEmitter.cpp3
-rw-r--r--www/analyzer/faq.html16
-rw-r--r--www/analyzer/latest_checker.html.incl2
-rw-r--r--www/analyzer/release_notes.html16
-rw-r--r--www/comparison.html1
-rw-r--r--www/compatibility.html6
-rw-r--r--www/cxx_status.html8
314 files changed, 10579 insertions, 3952 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fc1fed4988..6efcd4a7bd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -138,6 +138,11 @@ configure_file(
# Add appropriate flags for GCC
if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual -Wcast-qual -fno-strict-aliasing -pedantic -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings")
+
+ check_cxx_compiler_flag("-Werror -Wnested-anon-types" CXX_SUPPORTS_NO_NESTED_ANON_TYPES_FLAG)
+ if( CXX_SUPPORTS_NO_NESTED_ANON_TYPES_FLAG )
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-nested-anon-types" )
+ endif()
endif ()
if (APPLE)
diff --git a/docs/AutomaticReferenceCounting.rst b/docs/AutomaticReferenceCounting.rst
index 8993bc7b6b..65675a44bf 100644
--- a/docs/AutomaticReferenceCounting.rst
+++ b/docs/AutomaticReferenceCounting.rst
@@ -679,6 +679,9 @@ There is a single exception to this rule: an ownership qualifier may be applied
to a substituted template type parameter, which overrides the ownership
qualifier provided by the template argument.
+When forming a function type, the result type is adjusted so that any
+top-level ownership qualifier is deleted.
+
Except as described under the :ref:`inference rules <arc.ownership.inference>`,
a program is ill-formed if it attempts to form a pointer or reference type to a
retainable object owner type which lacks an ownership qualifier.
@@ -689,7 +692,9 @@ retainable object owner type which lacks an ownership qualifier.
lvalues of retainable object pointer type have an ownership qualifier. The
ability to override an ownership qualifier during template substitution is
required to counteract the :ref:`inference of __strong for template type
- arguments <arc.ownership.inference.template.arguments>`.
+ arguments <arc.ownership.inference.template.arguments>`. Ownership qualifiers
+ on return types are dropped because they serve no purpose there except to
+ cause spurious problems with overloading and templates.
There are four ownership qualifiers:
@@ -717,17 +722,37 @@ If an ownership qualifier appears in the *declaration-specifiers*, the
following rules apply:
* if the type specifier is a retainable object owner type, the qualifier
- applies to that type;
-* if the outermost non-array part of the declarator is a pointer or block
- pointer, the qualifier applies to that type;
+ initially applies to that type;
+
+* otherwise, if the outermost non-array declarator is a pointer
+ or block pointer declarator, the qualifier initially applies to
+ that type;
+
* otherwise the program is ill-formed.
+* If the qualifier is so applied at a position in the declaration
+ where the next-innermost declarator is a function declarator, and
+ there is an block declarator within that function declarator, then
+ the qualifier applies instead to that block declarator and this rule
+ is considered afresh beginning from the new position.
+
If an ownership qualifier appears on the declarator name, or on the declared
-object, it is applied to outermost pointer or block-pointer type.
+object, it is applied to the innermost pointer or block-pointer type.
If an ownership qualifier appears anywhere else in a declarator, it applies to
the type there.
+.. admonition:: Rationale
+
+ Ownership qualifiers are like ``const`` and ``volatile`` in the sense
+ that they may sensibly apply at multiple distinct positions within a
+ declarator. However, unlike those qualifiers, there are many
+ situations where they are not meaningful, and so we make an effort
+ to "move" the qualifier to a place where it will be meaningful. The
+ general goal is to allow the programmer to write, say, ``__strong``
+ before the entire declaration and have it apply in the leftmost
+ sensible place.
+
.. _arc.ownership.spelling.property:
Property declarations
diff --git a/docs/ClangFormat.rst b/docs/ClangFormat.rst
index 3272458e13..f5c0b4c1fb 100644
--- a/docs/ClangFormat.rst
+++ b/docs/ClangFormat.rst
@@ -44,12 +44,12 @@ Vim Integration
There is an integration for :program:`vim` which lets you run the
:program:`clang-format` standalone tool on your current buffer, optionally
-selecting regions to reformat. The integration has to form of a `python`-file
+selecting regions to reformat. The integration has the form of a `python`-file
which can be found under `clang/tools/extra/clang-format/clang-format.py`.
-This can be integrated by mapping the following to your `.vimrc`:
+This can be integrated by adding the following to your `.vimrc`:
-.. code-block:: console
+.. code-block:: vim
map <C-I> :pyf <path-to-this-file>/clang-format.py<CR>
imap <C-I> <ESC>:pyf <path-to-this-file>/clang-format.py<CR>i
diff --git a/docs/ClangTools.rst b/docs/ClangTools.rst
index 5c31e1da65..b7f7c7b046 100644
--- a/docs/ClangTools.rst
+++ b/docs/ClangTools.rst
@@ -67,7 +67,7 @@ Core Clang Tools
================
The core set of Clang tools that are within the main repository are
-tools that very specifically compliment, and allow use and testing of
+tools that very specifically complement, and allow use and testing of
*Clang* specific functionality.
``clang-check``
@@ -120,6 +120,31 @@ Ideas for new Tools
``foo.begin()`` into ``begin(foo)`` and similarly for ``end()``, where
``foo`` is a standard container. We could also detect similar patterns for
arrays.
+* ``tr1`` removal tool. Will migrate source code from using TR1 library
+ features to C++11 library. For example:
+
+ .. code-block:: c++
+
+ #include <tr1/unordered_map>
+ int main()
+ {
+ std::tr1::unordered_map <int, int> ma;
+ std::cout << ma.size () << std::endl;
+ return 0;
+ }
+
+ should be rewritten to:
+
+ .. code-block:: c++
+
+ #include <unordered_map>
+ int main()
+ {
+ std::unordered_map <int, int> ma;
+ std::cout << ma.size () << std::endl;
+ return 0;
+ }
+
* A tool to remove ``auto``. Will convert ``auto`` to an explicit type or add
comments with deduced types. The motivation is that there are developers
that don't want to use ``auto`` because they are afraid that they might lose
diff --git a/docs/ExternalClangExamples.rst b/docs/ExternalClangExamples.rst
index a7fa169b81..c7fd4c51fa 100644
--- a/docs/ExternalClangExamples.rst
+++ b/docs/ExternalClangExamples.rst
@@ -28,6 +28,14 @@ that can help developers, generally they must have code available.
List of projects and tools
==========================
+`<https://github.com/Andersbakken/rtags/>`_
+ "RTags is a client/server application that indexes c/c++ code and keeps
+ a persistent in-memory database of references, symbolnames, completions
+ etc."
+
+`<http://rprichard.github.com/sourceweb/>`_
+ "A C/C++ source code indexer and navigator"
+
`<https://github.com/etaoins/qconnectlint>`_
"qconnectlint is a Clang tool for statically verifying the consistency
of signal and slot connections made with Qt's ``QObject::connect``."
diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html
index 31799008bc..5bee8ccea4 100644
--- a/docs/LibASTMatchersReference.html
+++ b/docs/LibASTMatchersReference.html
@@ -973,6 +973,23 @@ incompleteArrayType()
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('lvalueReferenceTypeLoc0')"><a name="lvalueReferenceTypeLoc0Anchor">lvalueReferenceTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LValueReferenceTypeLoc.html">LValueReferenceTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="lvalueReferenceTypeLoc0"><pre>Matches lvalue reference types.
+
+Given:
+ int *a;
+ int &amp;b = *a;
+ int &amp;&amp;c = 1;
+ auto &amp;d = b;
+ auto &amp;&amp;e = c;
+ auto &amp;&amp;f = 2;
+ int g = 5;
+
+lvalueReferenceType() matches the types of b, d, and e. e is
+matched since the type is deduced as int&amp; by reference collapsing rules.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('memberPointerTypeLoc0')"><a name="memberPointerTypeLoc0Anchor">memberPointerTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerTypeLoc.html">MemberPointerTypeLoc</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="memberPointerTypeLoc0"><pre>Matches member pointer types.
Given
@@ -1011,14 +1028,35 @@ and s.
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('referenceTypeLoc0')"><a name="referenceTypeLoc0Anchor">referenceTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceTypeLoc.html">ReferenceTypeLoc</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="referenceTypeLoc0"><pre>Matches reference types.
+<tr><td colspan="4" class="doc" id="referenceTypeLoc0"><pre>Matches both lvalue and rvalue reference types.
Given
int *a;
int &amp;b = *a;
- int c = 5;
-pointerType()
- matches "int &amp;b"
+ int &amp;&amp;c = 1;
+ auto &amp;d = b;
+ auto &amp;&amp;e = c;
+ auto &amp;&amp;f = 2;
+ int g = 5;
+
+referenceType() matches the types of b, c, d, e, and f.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('rvalueReferenceTypeLoc0')"><a name="rvalueReferenceTypeLoc0Anchor">rvalueReferenceTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RValueReferenceTypeLoc.html">RValueReferenceTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="rvalueReferenceTypeLoc0"><pre>Matches rvalue reference types.
+
+Given:
+ int *a;
+ int &amp;b = *a;
+ int &amp;&amp;c = 1;
+ auto &amp;d = b;
+ auto &amp;&amp;e = c;
+ auto &amp;&amp;f = 2;
+ int g = 5;
+
+lvalueReferenceType() matches the types of c and f. e is not
+matched as it is deduced to int&amp; by reference collapsing rules.
</pre></td></tr>
@@ -1202,6 +1240,23 @@ incompleteArrayType()
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('lvalueReferenceType0')"><a name="lvalueReferenceType0Anchor">lvalueReferenceType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LValueReferenceType.html">LValueReferenceType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="lvalueReferenceType0"><pre>Matches lvalue reference types.
+
+Given:
+ int *a;
+ int &amp;b = *a;
+ int &amp;&amp;c = 1;
+ auto &amp;d = b;
+ auto &amp;&amp;e = c;
+ auto &amp;&amp;f = 2;
+ int g = 5;
+
+lvalueReferenceType() matches the types of b, d, and e. e is
+matched since the type is deduced as int&amp; by reference collapsing rules.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('memberPointerType0')"><a name="memberPointerType0Anchor">memberPointerType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="memberPointerType0"><pre>Matches member pointer types.
Given
@@ -1240,14 +1295,35 @@ and s.
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('referenceType0')"><a name="referenceType0Anchor">referenceType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="referenceType0"><pre>Matches reference types.
+<tr><td colspan="4" class="doc" id="referenceType0"><pre>Matches both lvalue and rvalue reference types.
Given
int *a;
int &amp;b = *a;
- int c = 5;
-pointerType()
- matches "int &amp;b"
+ int &amp;&amp;c = 1;
+ auto &amp;d = b;
+ auto &amp;&amp;e = c;
+ auto &amp;&amp;f = 2;
+ int g = 5;
+
+referenceType() matches the types of b, c, d, e, and f.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('rvalueReferenceType0')"><a name="rvalueReferenceType0Anchor">rvalueReferenceType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RValueReferenceType.html">RValueReferenceType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="rvalueReferenceType0"><pre>Matches rvalue reference types.
+
+Given:
+ int *a;
+ int &amp;b = *a;
+ int &amp;&amp;c = 1;
+ auto &amp;d = b;
+ auto &amp;&amp;e = c;
+ auto &amp;&amp;f = 2;
+ int g = 5;
+
+lvalueReferenceType() matches the types of c and f. e is not
+matched as it is deduced to int&amp; by reference collapsing rules.
</pre></td></tr>
@@ -1393,17 +1469,43 @@ constructorDecl(hasAnyConstructorInitializer(isWritten()))
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;</td><td class="name" onclick="toggle('hasOverloadedOperatorName0')"><a name="hasOverloadedOperatorName0Anchor">hasOverloadedOperatorName</a></td><td>std::string Name</td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;</td><td class="name" onclick="toggle('hasOverloadedOperatorName0')"><a name="hasOverloadedOperatorName0Anchor">hasOverloadedOperatorName</a></td><td>StringRef Name</td></tr>
<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName0"><pre>Matches overloaded operator names.
Matches overloaded operator names specified in strings without the
-"operator" prefix, such as "&lt;&lt;", for OverloadedOperatorCall's.
+"operator" prefix: e.g. "&lt;&lt;".
+
+Given:
+ class A { int operator*(); };
+ const A &amp;operator&lt;&lt;(const A &amp;a, const A &amp;b);
+ A a;
+ a &lt;&lt; a; &lt;-- This matches
+
+operatorCallExpr(hasOverloadedOperatorName("&lt;&lt;"))) matches the specified
+line and recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
+the declaration of A.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;</td><td class="name" onclick="toggle('hasOverloadedOperatorName1')"><a name="hasOverloadedOperatorName1Anchor">hasOverloadedOperatorName</a></td><td>StringRef Name</td></tr>
+<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName1"><pre>Matches overloaded operator names.
+
+Matches overloaded operator names specified in strings without the
+"operator" prefix: e.g. "&lt;&lt;".
+
+Given:
+ class A { int operator*(); };
+ const A &amp;operator&lt;&lt;(const A &amp;a, const A &amp;b);
+ A a;
+ a &lt;&lt; a; &lt;-- This matches
-Example matches a &lt;&lt; b
- (matcher == operatorCallExpr(hasOverloadedOperatorName("&lt;&lt;")))
- a &lt;&lt; b;
- c &amp;&amp; d; assuming both operator&lt;&lt;
- and operator&amp;&amp; are overloaded somewhere.
+operatorCallExpr(hasOverloadedOperatorName("&lt;&lt;"))) matches the specified
+line and recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
+the declaration of A.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;
</pre></td></tr>
@@ -2230,6 +2332,18 @@ Example matches A() in the last line
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('hasMethod0')"><a name="hasMethod0Anchor">hasMethod</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasMethod0"><pre>Matches the first method of a class or struct that satisfies InnerMatcher.
+
+Given:
+ class A { void func(); };
+ class B { void member(); };
+
+recordDecl(hasMethod(hasName("func"))) matches the declaration of A
+but not B.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isDerivedFrom0')"><a name="isDerivedFrom0Anchor">isDerivedFrom</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>&gt; Base</td></tr>
<tr><td colspan="4" class="doc" id="isDerivedFrom0"><pre>Matches C++ classes that are directly or indirectly derived from
a class matching Base.
@@ -2509,7 +2623,7 @@ Example matches true (matcher = hasCondition(boolLiteral(equals(true))))
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html">ElaboratedType</a>&gt;</td><td class="name" onclick="toggle('hasQualifier0')"><a name="hasQualifier0Anchor">hasQualifier</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasQualifier0"><pre>Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier,
-matches InnerMatcher.
+matches InnerMatcher if the qualifier exists.
Given
namespace N {
@@ -2909,6 +3023,19 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockP
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('hasCanonicalType0')"><a name="hasCanonicalType0Anchor">hasCanonicalType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasCanonicalType0"><pre>Matches QualTypes whose canonical type matches InnerMatcher.
+
+Given:
+ typedef int &amp;int_ref;
+ int a;
+ int_ref b = a;
+
+varDecl(hasType(qualType(referenceType()))))) will not match the
+declaration of b but varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration5')"><a name="hasDeclaration5Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasDeclaration5"><pre>Matches a type if the declaration of the type matches the given
matcher.
diff --git a/docs/LibASTMatchersTutorial.rst b/docs/LibASTMatchersTutorial.rst
index 3d0af67cb5..ba568e3594 100644
--- a/docs/LibASTMatchersTutorial.rst
+++ b/docs/LibASTMatchersTutorial.rst
@@ -21,7 +21,7 @@ repositories, but we'll be accessing them through the git mirror. For
further information, see the `getting started
guide <http://llvm.org/docs/GettingStarted.html>`_.
-::
+.. code-block:: console
mkdir ~/clang-llvm && cd ~/clang-llvm
git clone http://llvm.org/git/llvm.git
@@ -32,7 +32,7 @@ Next you need to obtain the CMake build system and Ninja build tool. You
may already have CMake installed, but current binary versions of CMake
aren't built with Ninja support.
-::
+.. code-block:: console
cd ~/clang-llvm
git clone https://github.com/martine/ninja.git
@@ -51,7 +51,7 @@ aren't built with Ninja support.
Okay. Now we'll build Clang!
-::
+.. code-block:: console
cd ~/clang-llvm
mkdir build && cd build
@@ -69,7 +69,7 @@ in both the llvm and clang directories should fix any problems.
Finally, we want to set Clang as its own compiler.
-::
+.. code-block:: console
cd ~/clang-llvm/build
ccmake ../llvm
@@ -94,7 +94,7 @@ First, we'll need to create a new directory for our tool and tell CMake
that it exists. As this is not going to be a core clang tool, it will
live in the ``tools/extra`` repository.
-::
+.. code-block:: console
cd ~/clang-llvm/llvm/tools/clang
mkdir tools/extra/loop-convert
@@ -123,7 +123,7 @@ something to compile! Put the following into
why the different parts are needed can be found in the `LibTooling
documentation <LibTooling.html>`_.
-::
+.. code-block:: c++
// Declares clang::SyntaxOnlyAction.
#include "clang/Frontend/FrontendActions.h"
@@ -153,7 +153,7 @@ documentation <LibTooling.html>`_.
And that's it! You can compile our new tool by running ninja from the
``build`` directory.
-::
+.. code-block:: console
cd ~/clang-llvm/build
ninja
@@ -161,7 +161,7 @@ And that's it! You can compile our new tool by running ninja from the
You should now be able to run the syntax checker, which is located in
``~/clang-llvm/build/bin``, on any source file. Try it!
-::
+.. code-block:: console
cat "void main() {}" > test.cpp
bin/loop-convert test.cpp --
@@ -186,7 +186,7 @@ For example, suppose you wanted to examine only binary operators. There
is a matcher to do exactly that, conveniently named ``binaryOperator``.
I'll give you one guess what this matcher does:
-::
+.. code-block:: c++
binaryOperator(hasOperatorName("+"), hasLHS(integerLiteral(equals(0))))
@@ -207,7 +207,7 @@ All matcher that are nouns describe entities in the AST and can be
bound, so that they can be referred to whenever a match is found. To do
so, simply call the method ``bind`` on these matchers, e.g.:
-::
+.. code-block:: c++
variable(hasType(isInteger())).bind("intvar")
@@ -218,21 +218,21 @@ Okay, on to using matchers for real. Let's start by defining a matcher
which will capture all ``for`` statements that define a new variable
initialized to zero. Let's start with matching all ``for`` loops:
-::
+.. code-block:: c++
forStmt()
Next, we want to specify that a single variable is declared in the first
portion of the loop, so we can extend the matcher to
-::
+.. code-block:: c++
forStmt(hasLoopInit(declStmt(hasSingleDecl(varDecl()))))
Finally, we can add the condition that the variable is initialized to
zero.
-::
+.. code-block:: c++
forStmt(hasLoopInit(declStmt(hasSingleDecl(varDecl(
hasInitializer(integerLiteral(equals(0))))))))
@@ -247,7 +247,7 @@ zero besides the integer 0.
The last step is giving the matcher a name and binding the ``ForStmt``
as we will want to do something with it:
-::
+.. code-block:: c++
StatementMatcher LoopMatcher =
forStmt(hasLoopInit(declStmt(hasSingleDecl(varDecl(
@@ -260,7 +260,13 @@ from a ``ClangTool``. More code!
Add the following to ``LoopConvert.cpp``:
-::
+.. code-block:: c++
+
+ #include "clang/ASTMatchers/ASTMatchers.h"
+ #include "clang/ASTMatchers/ASTMatchFinder.h"
+
+ using namespace clang;
+ using namespace clang::ast_matchers;
StatementMatcher LoopMatcher =
forStmt(hasLoopInit(declStmt(hasSingleDecl(varDecl(
@@ -275,7 +281,7 @@ Add the following to ``LoopConvert.cpp``:
And change ``main()`` to:
-::
+.. code-block:: c++
int main(int argc, const char **argv) {
CommonOptionsParser OptionsParser(argc, argv);
@@ -293,7 +299,7 @@ Now, you should be able to recompile and run the code to discover for
loops. Create a new file with a few examples, and test out our new
handiwork:
-::
+.. code-block:: console
cd ~/clang-llvm/llvm/llvm_build/
ninja loop-convert
@@ -331,7 +337,7 @@ would like to allow, and punting extra comparisons to the callback.
In any case, we can start building this sub-matcher. We can require that
the increment step be a unary increment like this:
-::
+.. code-block:: c++
hasIncrement(unaryOperator(hasOperatorName("++")))
@@ -341,7 +347,7 @@ reference expressions") because they are expressions which refer to
variable declarations. To find a ``unaryOperator`` that refers to a
specific declaration, we can simply add a second condition to it:
-::
+.. code-block:: c++
hasIncrement(unaryOperator(
hasOperatorName("++"),
@@ -350,7 +356,7 @@ specific declaration, we can simply add a second condition to it:
Furthermore, we can restrict our matcher to only match if the
incremented variable is an integer:
-::
+.. code-block:: c++
hasIncrement(unaryOperator(
hasOperatorName("++"),
@@ -359,7 +365,7 @@ incremented variable is an integer:
And the last step will be to attach an identifier to this variable, so
that we can retrieve it in the callback:
-::
+.. code-block:: c++
hasIncrement(unaryOperator(
hasOperatorName("++"),
@@ -378,19 +384,19 @@ without looking at the body of the loop! We are again restricted to
approximating the result we want with matchers, filling in the details
in the callback. So we start with:
-::
+.. code-block:: c++
hasCondition(binaryOperator(hasOperatorName("<"))
It makes sense to ensure that the left-hand side is a reference to a
variable, and that the right-hand side has integer type.
-::
+.. code-block:: c++
hasCondition(binaryOperator(
hasOperatorName("<"),
- hasRHS(expr(hasType(isInteger()))),
- hasLHS(declRefExpr(to(varDecl(hasType(isInteger())))))))
+ hasLHS(declRefExpr(to(varDecl(hasType(isInteger()))))),
+ hasRHS(expr(hasType(isInteger())))))
Why? Because it doesn't work. Of the three loops provided in
``test-files/simple.cpp``, zero of them have a matching condition. A
@@ -422,13 +428,13 @@ in the form of ``ignoringParenImpCasts``, which instructs the matcher to
ignore implicit casts and parentheses before continuing to match.
Adjusting the condition operator will restore the desired match.
-::
+.. code-block:: c++
hasCondition(binaryOperator(
hasOperatorName("<"),
- hasLHS(expr(hasType(isInteger()))),
- hasRHS(ignoringParenImpCasts(declRefExpr(
- to(varDecl(hasType(isInteger()))))))))
+ hasLHS(ignoringParenImpCasts(declRefExpr(
+ to(varDecl(hasType(isInteger())))))),
+ hasRHS(expr(hasType(isInteger())))))
After adding binds to the expressions we wished to capture and
extracting the identifier strings into variables, we have array-step-2
@@ -456,7 +462,7 @@ using the ``getNodeAs()`` member function.
In ``LoopActions.cpp``:
-::
+.. code-block:: c++
#include "clang/AST/ASTContext.h"
@@ -474,7 +480,7 @@ Now that we have the three variables, represented by their respective
declarations, let's make sure that they're all the same, using a helper
function I call ``areSameVariable()``.
-::
+.. code-block:: c++
if (!areSameVariable(IncVar, CondVar) || !areSameVariable(IncVar, InitVar))
return;
@@ -484,7 +490,7 @@ function I call ``areSameVariable()``.
If execution reaches the end of ``LoopPrinter::run()``, we know that the
loop shell that looks like
-::
+.. code-block:: c++
for (int i= 0; i < expr(); ++i) { ... }
@@ -498,7 +504,7 @@ declaration. Since the "canonical" form of each declaration is unique by
address, all we need to do is make sure neither ``ValueDecl`` (base
class of ``VarDecl``) is ``NULL`` and compare the canonical Decls.
-::
+.. code-block:: c++
static bool areSameVariable(const ValueDecl *First, const ValueDecl *Second) {
return First && Second &&
@@ -509,9 +515,9 @@ It's not as trivial to test if two expressions are the same, though
Clang has already done the hard work for us by providing a way to
canonicalize expressions:
-::
+.. code-block:: c++
- static bool areSameExpr(ASTContext* Context, const Expr *First,
+ static bool areSameExpr(ASTContext *Context, const Expr *First,
const Expr *Second) {
if (!First || !Second)
return false;
diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst
index ea613d13a0..281cc20653 100644
--- a/docs/UsersManual.rst
+++ b/docs/UsersManual.rst
@@ -828,7 +828,7 @@ Controlling Code Generation
Clang provides a number of ways to control code generation. The options
are listed below.
-**-fsanitize=check1,check2**
+**-fsanitize=check1,check2,...**
Turn on runtime checks for various forms of undefined or suspicious
behavior.
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index c382fb17c1..07c0ffb443 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 12
+#define CINDEX_VERSION_MINOR 14
#define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
@@ -5006,6 +5006,23 @@ typedef struct {
enum CXVisitorResult (*visit)(void *context, CXCursor, CXSourceRange);
} CXCursorAndRangeVisitor;
+typedef enum {
+ /**
+ * \brief Function returned successfully.
+ */
+ CXResult_Success = 0,
+ /**
+ * \brief One of the parameters was invalid for the function.
+ */
+ CXResult_Invalid = 1,
+ /**
+ * \brief The function was terminated by a callback (e.g. it returned
+ * CXVisit_Break)
+ */
+ CXResult_VisitBreak = 2
+
+} CXResult;
+
/**
* \brief Find references of a declaration in a specific file.
*
@@ -5017,10 +5034,28 @@ typedef struct {
* each reference found.
* The CXSourceRange will point inside the file; if the reference is inside
* a macro (and not a macro argument) the CXSourceRange will be invalid.
+ *
+ * \returns one of the CXResult enumerators.
*/
-CINDEX_LINKAGE void clang_findReferencesInFile(CXCursor cursor, CXFile file,
+CINDEX_LINKAGE CXResult clang_findReferencesInFile(CXCursor cursor, CXFile file,
CXCursorAndRangeVisitor visitor);
+/**
+ * \brief Find #import/#include directives in a specific file.
+ *
+ * \param TU translation unit containing the file to query.
+ *
+ * \param file to search for #import/#include directives.
+ *
+ * \param visitor callback that will receive pairs of CXCursor/CXSourceRange for
+ * each directive found.
+ *
+ * \returns one of the CXResult enumerators.
+ */
+CINDEX_LINKAGE CXResult clang_findIncludesInFile(CXTranslationUnit TU,
+ CXFile file,
+ CXCursorAndRangeVisitor visitor);
+
#ifdef __has_feature
# if __has_feature(blocks)
@@ -5028,8 +5063,12 @@ typedef enum CXVisitorResult
(^CXCursorAndRangeVisitorBlock)(CXCursor, CXSourceRange);
CINDEX_LINKAGE
-void clang_findReferencesInFileWithBlock(CXCursor, CXFile,
- CXCursorAndRangeVisitorBlock);
+CXResult clang_findReferencesInFileWithBlock(CXCursor, CXFile,
+ CXCursorAndRangeVisitorBlock);
+
+CINDEX_LINKAGE
+CXResult clang_findIncludesInFileWithBlock(CXTranslationUnit, CXFile,
+ CXCursorAndRangeVisitorBlock);
# endif
#endif
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index d12d0545c5..d4878a99a6 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -993,8 +993,7 @@ public:
}
/// \brief Return a normal function type with a typed argument list.
- QualType getFunctionType(QualType ResultTy,
- const QualType *Args, unsigned NumArgs,
+ QualType getFunctionType(QualType ResultTy, ArrayRef<QualType> Args,
const FunctionProtoType::ExtProtoInfo &EPI) const;
/// \brief Return the unique reference to the type for the specified type
diff --git a/include/clang/AST/AttrIterator.h b/include/clang/AST/AttrIterator.h
index e74405dfb1..8bd8fbec89 100644
--- a/include/clang/AST/AttrIterator.h
+++ b/include/clang/AST/AttrIterator.h
@@ -98,6 +98,7 @@ public:
friend bool operator==(specific_attr_iterator Left,
specific_attr_iterator Right) {
+ assert((Left.Current == 0) == (Right.Current == 0));
if (Left.Current < Right.Current)
Left.AdvanceToNext(Right.Current);
else
diff --git a/include/clang/AST/CharUnits.h b/include/clang/AST/CharUnits.h
index 12e74b32be..082c672c21 100644
--- a/include/clang/AST/CharUnits.h
+++ b/include/clang/AST/CharUnits.h
@@ -171,6 +171,17 @@ namespace clang {
Align.Quantity));
}
+ /// Given that this is a non-zero alignment value, what is the
+ /// alignment at the given offset?
+ CharUnits alignmentAtOffset(CharUnits offset) {
+ // alignment: 0010000
+ // offset: 1011100
+ // lowBits: 0001011
+ // result: 0000100
+ QuantityType lowBits = (Quantity-1) & (offset.Quantity-1);
+ return CharUnits((lowBits + 1) & ~lowBits);
+ }
+
}; // class CharUnit
} // namespace clang
diff --git a/include/clang/AST/Comment.h b/include/clang/AST/Comment.h
index 78b703d78a..c02a82f0fa 100644
--- a/include/clang/AST/Comment.h
+++ b/include/clang/AST/Comment.h
@@ -28,6 +28,26 @@ class TemplateParameterList;
namespace comments {
class FullComment;
+
+/// Describes the syntax that was used in a documentation command.
+///
+/// Exact values of this enumeration are important because they used to select
+/// parts of diagnostic messages. Audit diagnostics before changing or adding
+/// a new value.
+enum CommandMarkerKind {
+ /// Command started with a backslash character:
+ /// \code
+ /// \foo
+ /// \endcode
+ CMK_Backslash = 0,
+
+ /// Command started with an 'at' character:
+ /// \code
+ /// @foo
+ /// \endcode
+ CMK_At = 1
+};
+
/// Any part of the comment.
/// Abstract class.
class Comment {
@@ -110,8 +130,12 @@ protected:
unsigned : NumCommentBits;
unsigned CommandID : 8;
+
+ /// Describes the syntax that was used in a documentation command.
+ /// Contains values from CommandMarkerKind enum.
+ unsigned CommandMarker : 1;
};
- enum { NumBlockCommandCommentBits = NumCommentBits + 8 };
+ enum { NumBlockCommandCommentBits = NumCommentBits + 9 };
class ParamCommandCommentBitfields {
friend class ParamCommandComment;
@@ -574,21 +598,25 @@ protected:
BlockCommandComment(CommentKind K,
SourceLocation LocBegin,
SourceLocation LocEnd,
- unsigned CommandID) :
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) :
BlockContentComment(K, LocBegin, LocEnd),
Paragraph(NULL) {
setLocation(getCommandNameBeginLoc());
BlockCommandCommentBits.CommandID = CommandID;
+ BlockCommandCommentBits.CommandMarker = CommandMarker;
}
public:
BlockCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
- unsigned CommandID) :
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) :
BlockContentComment(BlockCommandCommentKind, LocBegin, LocEnd),
Paragraph(NULL) {
setLocation(getCommandNameBeginLoc());
BlockCommandCommentBits.CommandID = CommandID;
+ BlockCommandCommentBits.CommandMarker = CommandMarker;
}
static bool classof(const Comment *C) {
@@ -657,6 +685,11 @@ public:
if (NewLocEnd.isValid())
setSourceRange(SourceRange(getLocStart(), NewLocEnd));
}
+
+ CommandMarkerKind getCommandMarker() const LLVM_READONLY {
+ return static_cast<CommandMarkerKind>(
+ BlockCommandCommentBits.CommandMarker);
+ }
};
/// Doxygen \\param command.
@@ -670,9 +703,10 @@ public:
ParamCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
- unsigned CommandID) :
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) :
BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd,
- CommandID),
+ CommandID, CommandMarker),
ParamIndex(InvalidParamIndex) {
ParamCommandCommentBits.Direction = In;
ParamCommandCommentBits.IsDirectionExplicit = false;
@@ -752,8 +786,10 @@ private:
public:
TParamCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
- unsigned CommandID) :
- BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID)
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) :
+ BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID,
+ CommandMarker)
{ }
static bool classof(const Comment *C) {
@@ -834,7 +870,8 @@ public:
SourceLocation LocEnd,
unsigned CommandID) :
BlockCommandComment(VerbatimBlockCommentKind,
- LocBegin, LocEnd, CommandID)
+ LocBegin, LocEnd, CommandID,
+ CMK_At) // FIXME: improve source fidelity.
{ }
static bool classof(const Comment *C) {
@@ -887,7 +924,8 @@ public:
StringRef Text) :
BlockCommandComment(VerbatimLineCommentKind,
LocBegin, LocEnd,
- CommandID),
+ CommandID,
+ CMK_At), // FIXME: improve source fidelity.
Text(Text),
TextBegin(TextBegin)
{ }
diff --git a/include/clang/AST/CommentCommandTraits.h b/include/clang/AST/CommentCommandTraits.h
index ad4f29988c..9eb99d506b 100644
--- a/include/clang/AST/CommentCommandTraits.h
+++ b/include/clang/AST/CommentCommandTraits.h
@@ -100,7 +100,17 @@ struct CommandInfo {
/// \fn void f(int a);
/// \endcode
unsigned IsDeclarationCommand : 1;
-
+
+ /// \brief True if verbatim-like line command is a function declaration.
+ unsigned IsFunctionDeclarationCommand : 1;
+
+ /// \brief True if block command is further describing a container API; such
+ /// as @coclass, @classdesign, etc.
+ unsigned IsRecordLikeDetailCommand : 1;
+
+ /// \brief True if block command is a container API; such as @interface.
+ unsigned IsRecordLikeDeclarationCommand : 1;
+
/// \brief True if this command is unknown. This \c CommandInfo object was
/// created during parsing.
unsigned IsUnknownCommand : 1;
diff --git a/include/clang/AST/CommentCommands.td b/include/clang/AST/CommentCommands.td
index f04509c5ca..e217834227 100644
--- a/include/clang/AST/CommentCommands.td
+++ b/include/clang/AST/CommentCommands.td
@@ -24,6 +24,9 @@ class Command<string name> {
bit IsVerbatimBlockEndCommand = 0;
bit IsVerbatimLineCommand = 0;
bit IsDeclarationCommand = 0;
+ bit IsFunctionDeclarationCommand = 0;
+ bit IsRecordLikeDetailCommand = 0;
+ bit IsRecordLikeDeclarationCommand = 0;
}
class InlineCommand<string name> : Command<name> {
@@ -34,6 +37,10 @@ class BlockCommand<string name> : Command<name> {
let IsBlockCommand = 1;
}
+class RecordLikeDetailCommand<string name> : BlockCommand<name> {
+ let IsRecordLikeDetailCommand = 1;
+}
+
class VerbatimBlockCommand<string name> : Command<name> {
let EndCommandName = name;
let IsVerbatimBlockCommand = 1;
@@ -59,6 +66,18 @@ class DeclarationVerbatimLineCommand<string name> :
let IsDeclarationCommand = 1;
}
+class FunctionDeclarationVerbatimLineCommand<string name> :
+ VerbatimLineCommand<name> {
+ let IsDeclarationCommand = 1;
+ let IsFunctionDeclarationCommand = 1;
+}
+
+class RecordLikeDeclarationVerbatimLineCommand<string name> :
+ VerbatimLineCommand<name> {
+ let IsDeclarationCommand = 1;
+ let IsRecordLikeDeclarationCommand = 1;
+}
+
//===----------------------------------------------------------------------===//
// InlineCommand
//===----------------------------------------------------------------------===//
@@ -120,6 +139,18 @@ def Since : BlockCommand<"since">;
def Todo : BlockCommand<"todo">;
def Version : BlockCommand<"version">;
def Warning : BlockCommand<"warning">;
+// HeaderDoc commands
+def ClassDesign : RecordLikeDetailCommand<"classdesign">;
+def CoClass : RecordLikeDetailCommand<"coclass">;
+def Dependency : RecordLikeDetailCommand<"dependency">;
+def Helper : RecordLikeDetailCommand<"helper">;
+def HelperClass : RecordLikeDetailCommand<"helperclass">;
+def Helps : RecordLikeDetailCommand<"helps">;
+def InstanceSize : RecordLikeDetailCommand<"instancesize">;
+def Ownership : RecordLikeDetailCommand<"ownership">;
+def Performance : RecordLikeDetailCommand<"performance">;
+def Security : RecordLikeDetailCommand<"security">;
+def SuperClass : RecordLikeDetailCommand<"superclass">;
//===----------------------------------------------------------------------===//
// VerbatimBlockCommand
@@ -174,17 +205,16 @@ def Typedef : DeclarationVerbatimLineCommand<"typedef">;
def Var : DeclarationVerbatimLineCommand<"var">;
// HeaderDoc commands.
-def Class : DeclarationVerbatimLineCommand<"class">;
-def Interface : DeclarationVerbatimLineCommand<"interface">;
-def Protocol : DeclarationVerbatimLineCommand<"protocol">;
+def Class : RecordLikeDeclarationVerbatimLineCommand<"class">;
+def Interface : RecordLikeDeclarationVerbatimLineCommand<"interface">;
+def Protocol : RecordLikeDeclarationVerbatimLineCommand<"protocol">;
+def Struct : RecordLikeDeclarationVerbatimLineCommand<"struct">;
+def Union : RecordLikeDeclarationVerbatimLineCommand<"union">;
def Category : DeclarationVerbatimLineCommand<"category">;
def Template : DeclarationVerbatimLineCommand<"template">;
-def Function : DeclarationVerbatimLineCommand<"function">;
-def Method : DeclarationVerbatimLineCommand<"method">;
-def Callback : DeclarationVerbatimLineCommand<"callback">;
+def Function : FunctionDeclarationVerbatimLineCommand<"function">;
+def Method : FunctionDeclarationVerbatimLineCommand<"method">;
+def Callback : FunctionDeclarationVerbatimLineCommand<"callback">;
def Const : DeclarationVerbatimLineCommand<"const">;
def Constant : DeclarationVerbatimLineCommand<"constant">;
-def Struct : DeclarationVerbatimLineCommand<"struct">;
-def Union : DeclarationVerbatimLineCommand<"union">;
def Enum : DeclarationVerbatimLineCommand<"enum">;
-
diff --git a/include/clang/AST/CommentLexer.h b/include/clang/AST/CommentLexer.h
index b90414ba01..4179f45e80 100644
--- a/include/clang/AST/CommentLexer.h
+++ b/include/clang/AST/CommentLexer.h
@@ -34,8 +34,9 @@ enum TokenKind {
eof,
newline,
text,
- unknown_command, // Command that does not have an ID.
- command, // Command with an ID.
+ unknown_command, // Command that does not have an ID.
+ backslash_command, // Command with an ID, that used backslash marker.
+ at_command, // Command with an ID, that used 'at' marker.
verbatim_block_begin,
verbatim_block_line,
verbatim_block_end,
@@ -75,7 +76,7 @@ class Token {
/// unused (command spelling can be found with CommandTraits). Otherwise,
/// contains the length of the string that starts at TextPtr.
unsigned IntVal;
-
+
public:
SourceLocation getLocation() const LLVM_READONLY { return Loc; }
void setLocation(SourceLocation SL) { Loc = SL; }
@@ -118,12 +119,12 @@ public:
}
unsigned getCommandID() const LLVM_READONLY {
- assert(is(tok::command));
+ assert(is(tok::backslash_command) || is(tok::at_command));
return IntVal;
}
void setCommandID(unsigned ID) {
- assert(is(tok::command));
+ assert(is(tok::backslash_command) || is(tok::at_command));
IntVal = ID;
}
diff --git a/include/clang/AST/CommentParser.h b/include/clang/AST/CommentParser.h
index 8bf629b45e..d6a1072786 100644
--- a/include/clang/AST/CommentParser.h
+++ b/include/clang/AST/CommentParser.h
@@ -87,7 +87,7 @@ class Parser {
}
bool isTokBlockCommand() {
- return Tok.is(tok::command) &&
+ return (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)) &&
Traits.getCommandInfo(Tok.getCommandID())->IsBlockCommand;
}
diff --git a/include/clang/AST/CommentSema.h b/include/clang/AST/CommentSema.h
index 76957c23fc..15e454dcc3 100644
--- a/include/clang/AST/CommentSema.h
+++ b/include/clang/AST/CommentSema.h
@@ -96,7 +96,8 @@ public:
BlockCommandComment *actOnBlockCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
- unsigned CommandID);
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker);
void actOnBlockCommandArgs(BlockCommandComment *Command,
ArrayRef<BlockCommandComment::Argument> Args);
@@ -106,7 +107,8 @@ public:
ParamCommandComment *actOnParamCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
- unsigned CommandID);
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker);
void actOnParamCommandDirectionArg(ParamCommandComment *Command,
SourceLocation ArgLocBegin,
@@ -123,7 +125,8 @@ public:
TParamCommandComment *actOnTParamCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
- unsigned CommandID);
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker);
void actOnTParamCommandParamNameArg(TParamCommandComment *Command,
SourceLocation ArgLocBegin,
@@ -195,14 +198,28 @@ public:
void checkBlockCommandDuplicate(const BlockCommandComment *Command);
void checkDeprecatedCommand(const BlockCommandComment *Comment);
+
+ void checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment);
+
+ void checkContainerDeclVerbatimLine(const BlockCommandComment *Comment);
+
+ void checkContainerDecl(const BlockCommandComment *Comment);
/// Resolve parameter names to parameter indexes in function declaration.
/// Emit diagnostics about unknown parametrs.
void resolveParamCommandIndexes(const FullComment *FC);
bool isFunctionDecl();
+ bool isAnyFunctionDecl();
+ bool isFunctionPointerVarDecl();
+ bool isObjCMethodDecl();
bool isObjCPropertyDecl();
bool isTemplateOrSpecialization();
+ bool isRecordLikeDecl();
+ bool isClassOrStructDecl();
+ bool isUnionDecl();
+ bool isObjCInterfaceDecl();
+ bool isObjCProtocolDecl();
ArrayRef<const ParmVarDecl *> getParamVars();
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 2f349fac47..fd1dcaa872 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -214,6 +214,11 @@ public:
/// \brief Determine what kind of linkage this entity has.
Linkage getLinkage() const;
+ /// \brief True if this decl has external linkage.
+ bool hasExternalLinkage() const {
+ return getLinkage() == ExternalLinkage;
+ }
+
/// \brief Determines the visibility of this entity.
Visibility getVisibility() const {
return getLinkageAndVisibility().getVisibility();
@@ -793,13 +798,20 @@ public:
return getStorageClass() == SC_Static && !isFileVarDecl();
}
- /// hasExternStorage - Returns true if a variable has extern or
- /// __private_extern__ storage.
+ /// \brief Returns true if a variable has extern or __private_extern__
+ /// storage.
bool hasExternalStorage() const {
return getStorageClass() == SC_Extern ||
getStorageClass() == SC_PrivateExtern;
}
+ /// \brief Returns true if a variable was written with extern or
+ /// __private_extern__ storage.
+ bool hasExternalStorageAsWritten() const {
+ return getStorageClassAsWritten() == SC_Extern ||
+ getStorageClassAsWritten() == SC_PrivateExtern;
+ }
+
/// hasGlobalStorage - Returns true for all variables that do not
/// have local storage. This includs all global variables as well
/// as static variables declared within a function.
@@ -2557,6 +2569,25 @@ public:
bool isUnion() const { return getTagKind() == TTK_Union; }
bool isEnum() const { return getTagKind() == TTK_Enum; }
+ /// Is this tag type named, either directly or via being defined in
+ /// a typedef of this type?
+ ///
+ /// C++11 [basic.link]p8:
+ /// A type is said to have linkage if and only if:
+ /// - it is a class or enumeration type that is named (or has a
+ /// name for linkage purposes) and the name has linkage; ...
+ /// C++11 [dcl.typedef]p9:
+ /// If the typedef declaration defines an unnamed class (or enum),
+ /// the first typedef-name declared by the declaration to be that
+ /// class type (or enum type) is used to denote the class type (or
+ /// enum type) for linkage purposes only.
+ ///
+ /// C does not have an analogous rule, but the same concept is
+ /// nonetheless useful in some places.
+ bool hasNameForLinkage() const {
+ return (getDeclName() || getTypedefNameForAnonDecl());
+ }
+
TypedefNameDecl *getTypedefNameForAnonDecl() const {
return hasExtInfo() ? 0 :
TypedefNameDeclOrQualifier.get<TypedefNameDecl*>();
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 1c5588f926..43f255fd04 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -651,6 +651,10 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
/// completed by the external AST source when required.
mutable bool ExternallyCompleted : 1;
+ /// \brief Indicates that the ivar cache does not yet include ivars
+ /// declared in the implementation.
+ mutable bool IvarListMissingImplementation : 1;
+
/// \brief The location of the superclass, if any.
SourceLocation SuperClassLoc;
@@ -660,7 +664,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
SourceLocation EndLoc;
DefinitionData() : Definition(), SuperClass(), CategoryList(), IvarList(),
- ExternallyCompleted() { }
+ ExternallyCompleted(),
+ IvarListMissingImplementation(true) { }
};
ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 4b5e19e733..480263e943 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -1712,7 +1712,7 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
// FunctionNoProtoType or FunctionProtoType, or a typedef. This
// also covers the return type and the function parameters,
// including exception specifications.
- if (clang::TypeSourceInfo *TSI = D->getTypeSourceInfo()) {
+ if (TypeSourceInfo *TSI = D->getTypeSourceInfo()) {
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
}
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index f9fc90dc07..10143a67ca 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -2797,7 +2797,7 @@ private:
return false;
}
- FunctionProtoType(QualType result, const QualType *args, unsigned numArgs,
+ FunctionProtoType(QualType result, ArrayRef<QualType> args,
QualType canonical, const ExtProtoInfo &epi);
/// NumArgs - The number of arguments this function has, not counting '...'.
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index b663770460..f48e8a53ef 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -1384,18 +1384,26 @@ AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) {
/// \brief Matches overloaded operator names.
///
/// Matches overloaded operator names specified in strings without the
-/// "operator" prefix, such as "<<", for OverloadedOperatorCall's.
+/// "operator" prefix: e.g. "<<".
///
-/// Example matches a << b
-/// (matcher == operatorCallExpr(hasOverloadedOperatorName("<<")))
+/// Given:
/// \code
-/// a << b;
-/// c && d; // assuming both operator<<
-/// // and operator&& are overloaded somewhere.
+/// class A { int operator*(); };
+/// const A &operator<<(const A &a, const A &b);
+/// A a;
+/// a << a; // <-- This matches
/// \endcode
-AST_MATCHER_P(CXXOperatorCallExpr,
- hasOverloadedOperatorName, std::string, Name) {
- return getOperatorSpelling(Node.getOperator()) == Name;
+///
+/// \c operatorCallExpr(hasOverloadedOperatorName("<<"))) matches the specified
+/// line and \c recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
+/// the declaration of \c A.
+///
+/// Usable as: Matcher<CXXOperatorCallExpr>, Matcher<CXXMethodDecl>
+inline internal::PolymorphicMatcherWithParam1<
+ internal::HasOverloadedOperatorNameMatcher, StringRef>
+hasOverloadedOperatorName(const StringRef Name) {
+ return internal::PolymorphicMatcherWithParam1<
+ internal::HasOverloadedOperatorNameMatcher, StringRef>(Name);
}
/// \brief Matches C++ classes that are directly or indirectly derived from
@@ -1445,6 +1453,27 @@ inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom(
return isSameOrDerivedFrom(hasName(BaseName));
}
+/// \brief Matches the first method of a class or struct that satisfies \c
+/// InnerMatcher.
+///
+/// Given:
+/// \code
+/// class A { void func(); };
+/// class B { void member(); };
+/// \code
+///
+/// \c recordDecl(hasMethod(hasName("func"))) matches the declaration of \c A
+/// but not \c B.
+AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher<CXXMethodDecl>,
+ InnerMatcher) {
+ for (CXXRecordDecl::method_iterator I = Node.method_begin(),
+ E = Node.method_end();
+ I != E; ++I)
+ if (InnerMatcher.matches(**I, Finder, Builder))
+ return true;
+ return false;
+}
+
/// \brief Matches AST nodes that have child AST nodes that match the
/// provided matcher.
///
@@ -1786,6 +1815,23 @@ AST_MATCHER_P(QualType, references, internal::Matcher<QualType>,
InnerMatcher.matches(Node->getPointeeType(), Finder, Builder));
}
+/// \brief Matches QualTypes whose canonical type matches InnerMatcher.
+///
+/// Given:
+/// \code
+/// typedef int &int_ref;
+/// int a;
+/// int_ref b = a;
+/// \code
+///
+/// \c varDecl(hasType(qualType(referenceType()))))) will not match the
+/// declaration of b but \c
+/// varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does.
+AST_MATCHER_P(QualType, hasCanonicalType, internal::Matcher<QualType>,
+ InnerMatcher) {
+ return InnerMatcher.matches(Node.getCanonicalType(), Finder, Builder);
+}
+
/// \brief Overloaded to match the referenced type's declaration.
inline internal::Matcher<QualType> references(
const internal::Matcher<Decl> &InnerMatcher) {
@@ -2876,18 +2922,56 @@ AST_TYPE_MATCHER(MemberPointerType, memberPointerType);
/// matches "int *a"
AST_TYPE_MATCHER(PointerType, pointerType);
-/// \brief Matches reference types.
+/// \brief Matches both lvalue and rvalue reference types.
///
/// Given
/// \code
/// int *a;
/// int &b = *a;
-/// int c = 5;
+/// int &&c = 1;
+/// auto &d = b;
+/// auto &&e = c;
+/// auto &&f = 2;
+/// int g = 5;
/// \endcode
-/// pointerType()
-/// matches "int &b"
+///
+/// \c referenceType() matches the types of \c b, \c c, \c d, \c e, and \c f.
AST_TYPE_MATCHER(ReferenceType, referenceType);
+/// \brief Matches lvalue reference types.
+///
+/// Given:
+/// \code
+/// int *a;
+/// int &b = *a;
+/// int &&c = 1;
+/// auto &d = b;
+/// auto &&e = c;
+/// auto &&f = 2;
+/// int g = 5;
+/// \endcode
+///
+/// \c lValueReferenceType() matches the types of \c b, \c d, and \c e. \c e is
+/// matched since the type is deduced as int& by reference collapsing rules.
+AST_TYPE_MATCHER(LValueReferenceType, lValueReferenceType);
+
+/// \brief Matches rvalue reference types.
+///
+/// Given:
+/// \code
+/// int *a;
+/// int &b = *a;
+/// int &&c = 1;
+/// auto &d = b;
+/// auto &&e = c;
+/// auto &&f = 2;
+/// int g = 5;
+/// \endcode
+///
+/// \c rValueReferenceType() matches the types of \c c and \c f. \c e is not
+/// matched as it is deduced to int& by reference collapsing rules.
+AST_TYPE_MATCHER(RValueReferenceType, rValueReferenceType);
+
/// \brief Narrows PointerType (and similar) matchers to those where the
/// \c pointee matches a given matcher.
///
@@ -2965,7 +3049,7 @@ AST_TYPE_MATCHER(RecordType, recordType);
AST_TYPE_MATCHER(ElaboratedType, elaboratedType);
/// \brief Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier,
-/// matches \c InnerMatcher.
+/// matches \c InnerMatcher if the qualifier exists.
///
/// Given
/// \code
@@ -2981,7 +3065,10 @@ AST_TYPE_MATCHER(ElaboratedType, elaboratedType);
/// matches the type of the variable declaration of \c d.
AST_MATCHER_P(ElaboratedType, hasQualifier,
internal::Matcher<NestedNameSpecifier>, InnerMatcher) {
- return InnerMatcher.matches(*Node.getQualifier(), Finder, Builder);
+ if (const NestedNameSpecifier *Qualifier = Node.getQualifier())
+ return InnerMatcher.matches(*Qualifier, Finder, Builder);
+
+ return false;
}
/// \brief Matches ElaboratedTypes whose named type matches \c InnerMatcher.
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index f309794034..30691ad8f9 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -370,6 +370,44 @@ template <typename T> struct has_getDecl {
static bool const value = sizeof(f<Derived>(0)) == 2;
};
+/// \brief Matches overloaded operators with a specific name.
+///
+/// The type argument ArgT is not used by this matcher but is used by
+/// PolymorphicMatcherWithParam1 and should be StringRef.
+template <typename T, typename ArgT>
+class HasOverloadedOperatorNameMatcher : public SingleNodeMatcherInterface<T> {
+ TOOLING_COMPILE_ASSERT((llvm::is_same<T, CXXOperatorCallExpr>::value ||
+ llvm::is_same<T, CXXMethodDecl>::value),
+ unsupported_class_for_matcher);
+ TOOLING_COMPILE_ASSERT((llvm::is_same<ArgT, StringRef>::value),
+ argument_type_must_be_StringRef);
+public:
+ explicit HasOverloadedOperatorNameMatcher(const StringRef Name)
+ : SingleNodeMatcherInterface<T>(), Name(Name) {}
+
+ virtual bool matchesNode(const T &Node) const LLVM_OVERRIDE {
+ return matchesSpecialized(Node);
+ }
+
+private:
+
+ /// \brief CXXOperatorCallExpr exist only for calls to overloaded operators
+ /// so this function returns true if the call is to an operator of the given
+ /// name.
+ bool matchesSpecialized(const CXXOperatorCallExpr &Node) const {
+ return getOperatorSpelling(Node.getOperator()) == Name;
+ }
+
+ /// \brief Returns true only if CXXMethodDecl represents an overloaded
+ /// operator and has the given operator name.
+ bool matchesSpecialized(const CXXMethodDecl &Node) const {
+ return Node.isOverloadedOperator() &&
+ getOperatorSpelling(Node.getOverloadedOperator()) == Name;
+ }
+
+ std::string Name;
+};
+
/// \brief Matches declarations for QualType and CallExpr.
///
/// Type argument DeclMatcherT is required by PolymorphicMatcherWithParam1 but
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 3d4c3e026e..53f83e1acf 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -720,8 +720,9 @@ def VectorSize : Attr {
let ASTNode = 0;
}
-def VecTypeHint : IgnoredAttr {
+def VecTypeHint : InheritableAttr {
let Spellings = [GNU<"vec_type_hint">];
+ let Args = [TypeArgument<"TypeHint">, SourceLocArgument<"TypeLoc">];
}
def Visibility : InheritableAttr {
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 3af8ea2094..0a501cb4cc 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -583,7 +583,7 @@ public:
/// \brief Return an ID for a diagnostic with the specified message and level.
///
- /// If this is the first request for this diagnosic, it is registered and
+ /// If this is the first request for this diagnostic, it is registered and
/// created, otherwise the existing ID is returned.
unsigned getCustomDiagID(Level L, StringRef Message) {
return Diags->getCustomDiagID((DiagnosticIDs::Level)L, Message);
diff --git a/include/clang/Basic/DiagnosticCommentKinds.td b/include/clang/Basic/DiagnosticCommentKinds.td
index e6dfe5b638..7682b85a13 100644
--- a/include/clang/Basic/DiagnosticCommentKinds.td
+++ b/include/clang/Basic/DiagnosticCommentKinds.td
@@ -44,18 +44,18 @@ def note_doc_html_end_tag : Note<
// Commands
def warn_doc_block_command_empty_paragraph : Warning<
- "empty paragraph passed to '\\%0' command">,
+ "empty paragraph passed to '%select{\\|@}0%1' command">,
InGroup<Documentation>, DefaultIgnore;
def warn_doc_block_command_duplicate : Warning<
- "duplicated command '\\%0'">,
+ "duplicated command '%select{\\|@}0%1'">,
InGroup<Documentation>, DefaultIgnore;
def note_doc_block_command_previous : Note<
- "previous command '\\%0' here">;
+ "previous command '%select{\\|@}0%1' here">;
def note_doc_block_command_previous_alias : Note<
- "previous command '\\%0' (an alias of '\\%1') here">;
+ "previous command '%select{\\|@}0%1' (an alias of '\\%2') here">;
// \param command
@@ -69,10 +69,28 @@ def warn_doc_param_spaces_in_direction : Warning<
InGroup<DocumentationPedantic>, DefaultIgnore;
def warn_doc_param_not_attached_to_a_function_decl : Warning<
- "'\\param' command used in a comment that is not attached to "
+ "'%select{\\|@}0param' command used in a comment that is not attached to "
"a function declaration">,
InGroup<Documentation>, DefaultIgnore;
+def warn_doc_function_method_decl_mismatch : Warning<
+ "'%select{\\|@}0%select{function|method|callback}1' command should be "
+ "used in a comment attached to "
+ "%select{a function|an Objective-C method|a pointer to function}2 declaration">,
+ InGroup<Documentation>, DefaultIgnore;
+
+def warn_doc_api_container_decl_mismatch : Warning<
+ "'%select{\\|@}0%select{class|interface|protocol|struct|union}1' "
+ "command should not be used in a comment attached to a "
+ "non-%select{class|interface|protocol|struct|union}2 declaration">,
+ InGroup<Documentation>, DefaultIgnore;
+
+def warn_doc_container_decl_mismatch : Warning<
+ "'%select{\\|@}0%select{classdesign|coclass|dependency|helper"
+ "|helperclass|helps|instancesize|ownership|performance|security|superclass}1' "
+ "command should not be used in a comment attached to a non-container declaration">,
+ InGroup<Documentation>, DefaultIgnore;
+
def warn_doc_param_duplicate : Warning<
"parameter '%0' is already documented">,
InGroup<Documentation>, DefaultIgnore;
@@ -87,10 +105,10 @@ def warn_doc_param_not_found : Warning<
def note_doc_param_name_suggestion : Note<
"did you mean '%0'?">;
-// \tparam command
+// tparam command
def warn_doc_tparam_not_attached_to_a_template_decl : Warning<
- "'\\tparam' command used in a comment that is not attached to "
+ "'%select{\\|@}0tparam' command used in a comment that is not attached to "
"a template declaration">,
InGroup<Documentation>, DefaultIgnore;
@@ -111,14 +129,14 @@ def note_doc_tparam_name_suggestion : Note<
// \returns command
def warn_doc_returns_not_attached_to_a_function_decl : Warning<
- "'\\%0' command used in a comment that is not attached to "
+ "'%select{\\|@}0%1' command used in a comment that is not attached to "
"a function or method declaration">,
InGroup<Documentation>, DefaultIgnore;
def warn_doc_returns_attached_to_a_void_function : Warning<
- "'\\%0' command used in a comment that is attached to a "
+ "'%select{\\|@}0%1' command used in a comment that is attached to a "
"%select{function returning void|constructor|destructor|"
- "method returning void}1">,
+ "method returning void}2">,
InGroup<Documentation>, DefaultIgnore;
// \deprecated command
@@ -134,7 +152,7 @@ def note_add_deprecation_attr : Note<
// verbatim block commands
def warn_verbatim_block_end_without_start : Warning<
- "'\\%0' command does not terminate a verbatim text block">,
+ "'%select{\\|@}0%1' command does not terminate a verbatim text block">,
InGroup<Documentation>, DefaultIgnore;
} // end of documentation issue category
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index 964d2bc193..469bae8dd4 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -75,7 +75,7 @@ def err_drv_invalid_libcxx_deployment : Error<
"invalid deployment target for -stdlib=libc++ (requires %0 or later)">;
def err_drv_invalid_feature : Error<
"invalid feature '%0' for CPU '%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'">;
@@ -150,4 +150,9 @@ def err_analyzer_config_no_value : Error<
"analyzer-config option '%0' has a key but no value">;
def err_analyzer_config_multiple_values : Error<
"analyzer-config option '%0' should contain only one '='">;
+
+def err_drv_modules_integrated_as : Error<
+ "modules can only be used with the compiler's integrated assembler">;
+def note_drv_modules_integrated_as : Note<
+ "'-no-integrated-as' cannot be used with '-fmodules'">;
}
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 69af407342..7b921953ff 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -39,6 +39,7 @@ def NullConversion : DiagGroup<"null-conversion">;
def ImplicitConversionFloatingPointToBool :
DiagGroup<"implicit-conversion-floating-point-to-bool">;
def BadArrayNewLength : DiagGroup<"bad-array-new-length">;
+def BuiltinMacroRedefined : DiagGroup<"builtin-macro-redefined">;
def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">;
def C99Compat : DiagGroup<"c99-compat">;
def CXXCompat: DiagGroup<"c++-compat">;
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index c030254bf8..d35b907424 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -124,7 +124,7 @@ public:
/// \brief Return an ID for a diagnostic with the specified message and level.
///
- /// If this is the first request for this diagnosic, it is registered and
+ /// If this is the first request for this diagnostic, it is registered and
/// created, otherwise the existing ID is returned.
unsigned getCustomDiagID(Level L, StringRef Message);
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index 7281d07a3b..7f66a87d61 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -182,6 +182,9 @@ def ext_string_too_long : Extension<"string literal of length %0 exceeds "
"support">, InGroup<OverlengthStrings>;
def err_character_too_large : Error<
"character too large for enclosing character literal type">;
+def warn_c99_compat_unicode_literal : Warning<
+ "unicode literals are incompatible with C99">,
+ InGroup<C99Compat>, DefaultIgnore;
def warn_cxx98_compat_unicode_literal : Warning<
"unicode literals are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
@@ -253,9 +256,10 @@ def pp_pragma_sysheader_in_main_file : Warning<
def pp_poisoning_existing_macro : Warning<"poisoning existing macro">;
def pp_out_of_date_dependency : Warning<
"current file is older than dependency %0">;
-def pp_undef_builtin_macro : Warning<"undefining builtin macro">;
-def pp_redef_builtin_macro : Warning<"redefining builtin macro">,
- InGroup<DiagGroup<"builtin-macro-redefined">>;
+def ext_pp_undef_builtin_macro : ExtWarn<"undefining builtin macro">,
+ InGroup<BuiltinMacroRedefined>;
+def ext_pp_redef_builtin_macro : ExtWarn<"redefining builtin macro">,
+ InGroup<BuiltinMacroRedefined>;
def pp_disabled_macro_expansion : Warning<
"disabled expansion of recursive macro">, DefaultIgnore,
InGroup<DiagGroup<"disabled-macro-expansion">>;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 2fbd99a688..2656a8bb8b 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -363,7 +363,7 @@ def note_objc_container_start : Note<
"%select{class|protocol|category|class extension|implementation"
"|category implementation}0 started here">;
def warn_objc_protocol_qualifier_missing_id : Warning<
- "protocol qualifiers without 'id' is archaic">;
+ "protocol has no object type specified; defaults to qualified 'id'">;
def err_objc_unknown_at : Error<"expected an Objective-C directive after '@'">;
def err_illegal_super_cast : Error<
"cannot cast 'super' (it isn't an expression)">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index a17719df99..c7cd205b54 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1672,6 +1672,8 @@ def err_attribute_argument_outof_range : Error<
def err_init_priority_object_attr : Error<
"can only use 'init_priority' attribute on file-scope definitions "
"of objects of class type">;
+def err_attribute_argument_vec_type_hint : Error<
+ "invalid attribute argument %0 - expecting a vector or vectorizable scalar type">;
def err_attribute_argument_n_not_int : Error<
"'%0' attribute requires parameter %1 to be an integer constant">;
def err_attribute_argument_n_not_string : Error<
@@ -3126,9 +3128,9 @@ def warn_cxx98_compat_template_outside_of_template : Warning<
InGroup<CXX98Compat>, DefaultIgnore;
def err_non_type_template_in_nested_name_specifier : Error<
- "qualified name refers into a specialization of function template '%0'">;
+ "qualified name refers into a specialization of function template %0">;
def err_template_id_not_a_type : Error<
- "template name refers to non-type template '%0'">;
+ "template name refers to non-type template %0">;
def note_template_declared_here : Note<
"%select{function template|class template|type alias template|template template parameter}0 "
"%1 declared here">;
diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td
index 6e377cc035..bc5bd4e2ad 100644
--- a/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -18,7 +18,7 @@ def err_fe_pch_malformed : Error<
def err_fe_pch_malformed_block : Error<
"malformed block record in PCH file: '%0'">, DefaultFatal;
def err_fe_pch_file_modified : Error<
- "file '%0' has been modified since the precompiled header was built">,
+ "file '%0' has been modified since the precompiled header '%1' was built">,
DefaultFatal;
def err_fe_pch_file_overridden : Error<
"file '%0' from the precompiled header has been overridden">;
diff --git a/include/clang/Basic/TokenKinds.h b/include/clang/Basic/TokenKinds.h
index e850971e34..dcbe1da111 100644
--- a/include/clang/Basic/TokenKinds.h
+++ b/include/clang/Basic/TokenKinds.h
@@ -68,15 +68,21 @@ inline bool isAnyIdentifier(TokenKind K) {
return (K == tok::identifier) || (K == tok::raw_identifier);
}
+/// \brief Return true if this is a C or C++ string-literal (or
+/// C++11 user-defined-string-literal) token.
+inline bool isStringLiteral(TokenKind K) {
+ return K == tok::string_literal || K == tok::wide_string_literal ||
+ K == tok::utf8_string_literal || K == tok::utf16_string_literal ||
+ K == tok::utf32_string_literal;
+}
+
/// \brief Return true if this is a "literal" kind, like a numeric
/// constant, string, etc.
inline bool isLiteral(TokenKind K) {
- return (K == tok::numeric_constant) || (K == tok::char_constant) ||
- (K == tok::wide_char_constant) || (K == tok::utf16_char_constant) ||
- (K == tok::utf32_char_constant) || (K == tok::string_literal) ||
- (K == tok::wide_string_literal) || (K == tok::utf8_string_literal) ||
- (K == tok::utf16_string_literal) || (K == tok::utf32_string_literal) ||
- (K == tok::angle_string_literal);
+ return K == tok::numeric_constant || K == tok::char_constant ||
+ K == tok::wide_char_constant || K == tok::utf16_char_constant ||
+ K == tok::utf32_char_constant || isStringLiteral(K) ||
+ K == tok::angle_string_literal;
}
/// \brief Return true if this is any of tok::annot_* kinds.
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index d1b21fdafb..b1e5bfa267 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -149,6 +149,12 @@ def femit_coverage_data: Flag<["-"], "femit-coverage-data">,
def coverage_file : Separate<["-"], "coverage-file">,
HelpText<"Emit coverage data to this filename. The extension will be replaced.">;
def coverage_file_EQ : Joined<["-"], "coverage-file=">, Alias<coverage_file>;
+def coverage_cfg_checksum : Flag<["-"], "coverage-cfg-checksum">,
+ HelpText<"Emit CFG checksum for functions in .gcno files.">;
+def coverage_function_names_in_data : Flag<["-"], "coverage-function-names-in-data">,
+ HelpText<"Emit function names in .gcda files.">;
+def coverage_version_EQ : Joined<["-"], "coverage-version=">,
+ HelpText<"Four-byte version string for gcov files.">;
def fuse_register_sized_bitfield_access: Flag<["-"], "fuse-register-sized-bitfield-access">,
HelpText<"Use register sized accesses to bit-fields, when possible.">;
def relaxed_aliasing : Flag<["-"], "relaxed-aliasing">,
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index dd2ef31119..bdd398d570 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -1165,7 +1165,7 @@ def _output_class_directory_EQ : Joined<["--"], "output-class-directory=">, Alia
def _output_class_directory : Separate<["--"], "output-class-directory">, Alias<foutput_class_dir_EQ>;
def _output_EQ : Joined<["--"], "output=">, Alias<o>;
def _output : Separate<["--"], "output">, Alias<o>;
-def _param : Separate<["--"], "param">;
+def _param : Separate<["--"], "param">, Group<CompileOnly_Group>;
def _param_EQ : Joined<["--"], "param=">, Alias<_param>;
def _prefix_EQ : Joined<["--"], "prefix=">, Alias<B>;
def _prefix : Separate<["--"], "prefix">, Alias<B>;
diff --git a/include/clang/Driver/Phases.h b/include/clang/Driver/Phases.h
index a0c42ea173..4e0f40c17d 100644
--- a/include/clang/Driver/Phases.h
+++ b/include/clang/Driver/Phases.h
@@ -23,6 +23,10 @@ namespace phases {
Link
};
+ enum {
+ MaxNumberOfPhases = Link + 1
+ };
+
const char *getPhaseName(ID Id);
} // end namespace phases
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index 9b201bab6b..ee65ed0849 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -147,7 +147,7 @@ public:
/// IsObjCDefaultSynthPropertiesDefault - Does this tool chain enable
/// -fobjc-default-synthesize-properties by default.
- virtual bool IsObjCDefaultSynthPropertiesDefault() const { return false; }
+ virtual bool IsObjCDefaultSynthPropertiesDefault() const { return true; }
/// IsEncodeExtendedBlockSignatureDefault - Does this tool chain enable
/// -fencode-extended-block-signature by default.
diff --git a/include/clang/Driver/Types.h b/include/clang/Driver/Types.h
index d28ca888d3..18cd2d5102 100644
--- a/include/clang/Driver/Types.h
+++ b/include/clang/Driver/Types.h
@@ -11,6 +11,7 @@
#define CLANG_DRIVER_TYPES_H_
#include "clang/Driver/Phases.h"
+#include "llvm/ADT/SmallVector.h"
namespace clang {
namespace driver {
@@ -73,14 +74,12 @@ namespace types {
/// specified type name.
ID lookupTypeForTypeSpecifier(const char *Name);
- /// getNumCompilationPhases - Return the complete number of phases
- /// to be done for this type.
- unsigned getNumCompilationPhases(ID Id);
+ /// getCompilationPhases - Get the list of compilation phases ('Phases') to be
+ /// done for type 'Id'.
+ void getCompilationPhases(
+ ID Id,
+ llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &Phases);
- /// getCompilationPhase - Return the \p N th compilation phase to
- /// be done for this type.
- phases::ID getCompilationPhase(ID Id, unsigned N);
-
/// lookupCXXTypeForCType - Lookup CXX input type that corresponds to given
/// C type (used for clang++ emulation of g++ behaviour)
ID lookupCXXTypeForCType(ID Id);
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 9a02c0c2b8..108114dd67 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -485,6 +485,9 @@ public:
StringRef getMainFileName() const;
+ /// \brief If this ASTUnit came from an AST file, returns the filename for it.
+ StringRef getASTFileName() const;
+
typedef std::vector<Decl *>::iterator top_level_iterator;
top_level_iterator top_level_begin() {
diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def
index bbb75ab736..333fa1e88f 100644
--- a/include/clang/Frontend/CodeGenOptions.def
+++ b/include/clang/Frontend/CodeGenOptions.def
@@ -30,6 +30,8 @@ CODEGENOPT(Name, Bits, Default)
CODEGENOPT(AsmVerbose , 1, 0) ///< -dA, -fverbose-asm.
CODEGENOPT(ObjCAutoRefCountExceptions , 1, 0) ///< Whether ARC should be EH-safe.
+CODEGENOPT(CoverageExtraChecksum, 1, 0) ///< Whether we need a second checksum for functions in GCNO files.
+CODEGENOPT(CoverageFunctionNamesInData, 1, 0) ///< Whether we should include function names in GCDA files.
CODEGENOPT(CUDAIsDevice , 1, 0) ///< Set when compiling for CUDA device.
CODEGENOPT(CXAAtExit , 1, 1) ///< Use __cxa_atexit for calling destructors.
CODEGENOPT(CXXCtorDtorAliases, 1, 0) ///< Emit complete ctors/dtors as linker
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index bda777dfd3..d0bbf30918 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -78,6 +78,9 @@ public:
/// replaced.
std::string CoverageFile;
+ /// The version string to put into coverage files.
+ char CoverageVersion[4];
+
/// Enable additional debugging information.
std::string DebugPass;
@@ -134,6 +137,7 @@ public:
#include "clang/Frontend/CodeGenOptions.def"
RelocationModel = "pic";
+ memcpy(CoverageVersion, "*204", 4);
}
};
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 8e69b64c1a..d8220b3ba5 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -279,11 +279,7 @@ private:
/// isTokenStringLiteral - True if this token is a string-literal.
///
bool isTokenStringLiteral() const {
- return Tok.getKind() == tok::string_literal ||
- Tok.getKind() == tok::wide_string_literal ||
- Tok.getKind() == tok::utf8_string_literal ||
- Tok.getKind() == tok::utf16_string_literal ||
- Tok.getKind() == tok::utf32_string_literal;
+ return tok::isStringLiteral(Tok.getKind());
}
/// \brief Returns true if the current token is '=' or is a type of '='.
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index a8d3eb4fb7..0f0d2185b0 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -144,6 +144,14 @@ private:
return *reinterpret_cast<const TypeTagForDatatypeData *>(this + 1);
}
+ ParsedType &getTypeBuffer() {
+ return *reinterpret_cast<ParsedType *>(this + 1);
+ }
+
+ const ParsedType &getTypeBuffer() const {
+ return *reinterpret_cast<const ParsedType *>(this + 1);
+ }
+
AttributeList(const AttributeList &) LLVM_DELETED_FUNCTION;
void operator=(const AttributeList &) LLVM_DELETED_FUNCTION;
void operator delete(void *) LLVM_DELETED_FUNCTION;
@@ -208,6 +216,20 @@ private:
AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
}
+ /// Constructor for attributes with a single type argument.
+ AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ ParsedType typeArg, Syntax syntaxUsed)
+ : AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
+ AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
+ EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed), Invalid(false),
+ UsedAsTypeAttr(false), IsAvailability(false),
+ IsTypeTagForDatatype(false), NextInPosition(0), NextInPool(0) {
+ new (&getTypeBuffer()) ParsedType(typeArg);
+ AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
+ }
+
friend class AttributePool;
friend class AttributeFactory;
@@ -352,6 +374,11 @@ public:
return getTypeTagForDatatypeDataSlot().MustBeNull;
}
+ const ParsedType &getTypeArg() const {
+ assert(getKind() == AT_VecTypeHint && "Not a type attribute");
+ return getTypeBuffer();
+ }
+
/// \brief Get an index into the attribute spelling list
/// defined in Attr.td. This index is used by an attribute
/// to pretty print itself.
@@ -509,6 +536,18 @@ public:
matchingCType, layoutCompatible,
mustBeNull, syntax));
}
+
+ AttributeList *createTypeAttribute(
+ IdentifierInfo *attrName, SourceRange attrRange,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ ParsedType typeArg, AttributeList::Syntax syntaxUsed) {
+ void *memory = allocate(sizeof(AttributeList) + sizeof(void *));
+ return add(new (memory) AttributeList(attrName, attrRange,
+ scopeName, scopeLoc,
+ parmName, parmLoc,
+ typeArg, syntaxUsed));
+ }
};
/// addAttributeLists - Add two AttributeLists together
@@ -651,6 +690,19 @@ public:
return attr;
}
+ /// Add an attribute with a single type argument.
+ AttributeList *
+ addNewTypeAttr(IdentifierInfo *attrName, SourceRange attrRange,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ ParsedType typeArg, AttributeList::Syntax syntaxUsed) {
+ AttributeList *attr =
+ pool.createTypeAttribute(attrName, attrRange, scopeName, scopeLoc,
+ parmName, parmLoc, typeArg, syntaxUsed);
+ add(attr);
+ return attr;
+ }
+
AttributeList *addNewInteger(ASTContext &C, IdentifierInfo *name,
SourceLocation loc, int arg) {
AttributeList *attr =
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 867c654435..4f87e9dd75 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -1435,6 +1435,9 @@ struct DeclaratorChunk {
return I;
}
+ bool isParen() const {
+ return Kind == Paren;
+ }
};
/// \brief Described the kind of function definition (if any) provided for
@@ -1796,33 +1799,41 @@ public:
return DeclTypeInfo[i];
}
- void DropFirstTypeObject()
- {
+ void DropFirstTypeObject() {
assert(!DeclTypeInfo.empty() && "No type chunks to drop.");
DeclTypeInfo.front().destroy();
DeclTypeInfo.erase(DeclTypeInfo.begin());
}
+ /// Return the innermost (closest to the declarator) chunk of this
+ /// declarator that is not a parens chunk, or null if there are no
+ /// non-parens chunks.
+ const DeclaratorChunk *getInnermostNonParenChunk() const {
+ for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) {
+ if (!DeclTypeInfo[i].isParen())
+ return &DeclTypeInfo[i];
+ }
+ return 0;
+ }
+
+ /// Return the outermost (furthest from the declarator) chunk of
+ /// this declarator that is not a parens chunk, or null if there are
+ /// no non-parens chunks.
+ const DeclaratorChunk *getOutermostNonParenChunk() const {
+ for (unsigned i = DeclTypeInfo.size(), i_end = 0; i != i_end; --i) {
+ if (!DeclTypeInfo[i-1].isParen())
+ return &DeclTypeInfo[i-1];
+ }
+ return 0;
+ }
+
/// isArrayOfUnknownBound - This method returns true if the declarator
/// is a declarator for an array of unknown bound (looking through
/// parentheses).
bool isArrayOfUnknownBound() const {
- for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) {
- switch (DeclTypeInfo[i].Kind) {
- case DeclaratorChunk::Paren:
- continue;
- case DeclaratorChunk::Function:
- case DeclaratorChunk::Pointer:
- case DeclaratorChunk::Reference:
- case DeclaratorChunk::BlockPointer:
- case DeclaratorChunk::MemberPointer:
- return false;
- case DeclaratorChunk::Array:
- return !DeclTypeInfo[i].Arr.NumElts;
- }
- llvm_unreachable("Invalid type chunk");
- }
- return false;
+ const DeclaratorChunk *chunk = getInnermostNonParenChunk();
+ return (chunk && chunk->Kind == DeclaratorChunk::Array &&
+ !chunk->Arr.NumElts);
}
/// isFunctionDeclarator - This method returns true if the declarator
@@ -1879,17 +1890,13 @@ public:
/// isn't a function declarator, if the type specifier refers to a function
/// type. This routine checks for both cases.
bool isDeclarationOfFunction() const;
-
- /// \brief Return true if a function declarator at this position would be a
- /// function declaration.
- bool isFunctionDeclaratorAFunctionDeclaration() const {
+
+ /// \brief Return true if this declaration appears in a context where a
+ /// function declarator would be a function declaration.
+ bool isFunctionDeclarationContext() const {
if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
return false;
- for (unsigned I = 0, N = getNumTypeObjects(); I != N; ++I)
- if (getTypeObject(I).Kind != DeclaratorChunk::Paren)
- return false;
-
switch (Context) {
case FileContext:
case MemberContext:
@@ -1917,6 +1924,19 @@ public:
}
llvm_unreachable("unknown context kind!");
}
+
+ /// \brief Return true if a function declarator at this position would be a
+ /// function declaration.
+ bool isFunctionDeclaratorAFunctionDeclaration() const {
+ if (!isFunctionDeclarationContext())
+ return false;
+
+ for (unsigned I = 0, N = getNumTypeObjects(); I != N; ++I)
+ if (getTypeObject(I).Kind != DeclaratorChunk::Paren)
+ return false;
+
+ return true;
+ }
/// takeAttributes - Takes attributes from the given parsed-attributes
/// set and add them to this declarator.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 12a787e329..29c1f77aa0 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -944,12 +944,39 @@ public:
SourceRange Brackets, DeclarationName Entity);
QualType BuildExtVectorType(QualType T, Expr *ArraySize,
SourceLocation AttrLoc);
+
+ /// \brief Build a function type.
+ ///
+ /// This routine checks the function type according to C++ rules and
+ /// under the assumption that the result type and parameter types have
+ /// just been instantiated from a template. It therefore duplicates
+ /// some of the behavior of GetTypeForDeclarator, but in a much
+ /// simpler form that is only suitable for this narrow use case.
+ ///
+ /// \param T The return type of the function.
+ ///
+ /// \param ParamTypes The parameter types of the function. This array
+ /// will be modified to account for adjustments to the types of the
+ /// function parameters.
+ ///
+ /// \param Loc The location of the entity whose type involves this
+ /// function type or, if there is no such entity, the location of the
+ /// type that will have function type.
+ ///
+ /// \param Entity The name of the entity that involves the function
+ /// type, if known.
+ ///
+ /// \param EPI Extra information about the function type. Usually this will
+ /// be taken from an existing function with the same prototype.
+ ///
+ /// \returns A suitable function type, if there are no errors. The
+ /// unqualified type will always be a FunctionProtoType.
+ /// Otherwise, returns a NULL type.
QualType BuildFunctionType(QualType T,
- QualType *ParamTypes, unsigned NumParamTypes,
- bool Variadic, bool HasTrailingReturn,
- unsigned Quals, RefQualifierKind RefQualifier,
+ llvm::MutableArrayRef<QualType> ParamTypes,
SourceLocation Loc, DeclarationName Entity,
- FunctionType::ExtInfo Info);
+ const FunctionProtoType::ExtProtoInfo &EPI);
+
QualType BuildMemberPointerType(QualType T, QualType Class,
SourceLocation Loc,
DeclarationName Entity);
@@ -2340,6 +2367,7 @@ public:
// More parsing and symbol table subroutines.
+ void ProcessPragmaWeak(Scope *S, Decl *D);
// Decl attributes - this routine is the top level dispatcher.
void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
bool NonInheritable = true,
@@ -6910,12 +6938,10 @@ public:
/// given type.
ExprResult forceUnknownAnyToType(Expr *E, QualType ToType);
- /// \brief Handle an expression that's being passed to an
+ /// \brief Type-check an expression that's being passed to an
/// __unknown_anytype parameter.
- ///
- /// \return the effective parameter type to use, or null if the
- /// argument is invalid.
- QualType checkUnknownAnyArg(Expr *&result);
+ ExprResult checkUnknownAnyArg(SourceLocation callLoc,
+ Expr *result, QualType &paramType);
// CheckVectorCast - check type constraints for vectors.
// Since vectors are an extension, there are no C standard reference for this.
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index df3c74c98f..2744865819 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -924,11 +924,10 @@ private:
/// \brief Reads a statement from the specified cursor.
Stmt *ReadStmtFromStream(ModuleFile &F);
- typedef llvm::PointerIntPair<const FileEntry *, 1, bool> InputFile;
-
/// \brief Retrieve the file entry and 'overridden' bit for an input
/// file in the given module file.
- InputFile getInputFile(ModuleFile &F, unsigned ID, bool Complain = true);
+ serialization::InputFile getInputFile(ModuleFile &F, unsigned ID,
+ bool Complain = true);
/// \brief Get a FileEntry out of stored-in-PCH filename, making sure we take
/// into account all the necessary relocations.
@@ -1136,6 +1135,7 @@ public:
~ASTReader();
SourceManager &getSourceManager() const { return SourceMgr; }
+ FileManager &getFileManager() const { return FileMgr; }
/// \brief Flags that indicate what kind of AST loading failures the client
/// of the AST reader can directly handle.
diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h
index 5b019bd054..89c604f393 100644
--- a/include/clang/Serialization/Module.h
+++ b/include/clang/Serialization/Module.h
@@ -55,6 +55,35 @@ struct DeclContextInfo {
unsigned NumLexicalDecls;
};
+/// \brief The input file that has been loaded from this AST file, along with
+/// bools indicating whether this was an overridden buffer or if it was
+/// out-of-date.
+class InputFile {
+ enum {
+ Overridden = 1,
+ OutOfDate = 2
+ };
+ llvm::PointerIntPair<const FileEntry *, 2, unsigned> Val;
+
+public:
+ InputFile() {}
+ InputFile(const FileEntry *File,
+ bool isOverridden = false, bool isOutOfDate = false) {
+ assert(!(isOverridden && isOutOfDate) &&
+ "an overridden cannot be out-of-date");
+ unsigned intVal = 0;
+ if (isOverridden)
+ intVal = Overridden;
+ else if (isOutOfDate)
+ intVal = OutOfDate;
+ Val.setPointerAndInt(File, intVal);
+ }
+
+ const FileEntry *getFile() const { return Val.getPointer(); }
+ bool isOverridden() const { return Val.getInt() == Overridden; }
+ bool isOutOfDate() const { return Val.getInt() == OutOfDate; }
+};
+
/// \brief Information about a module that has been loaded by the ASTReader.
///
/// Each instance of the Module class corresponds to a single AST file, which
@@ -145,10 +174,8 @@ public:
/// \brief Offsets for all of the input file entries in the AST file.
const uint32_t *InputFileOffsets;
- /// \brief The input files that have been loaded from this AST file, along
- /// with a bool indicating whether this was an overridden buffer.
- std::vector<llvm::PointerIntPair<const FileEntry *, 1, bool> >
- InputFilesLoaded;
+ /// \brief The input files that have been loaded from this AST file.
+ std::vector<InputFile> InputFilesLoaded;
// === Source Locations ===
@@ -262,10 +289,6 @@ public:
/// the header files.
void *HeaderFileInfoTable;
- /// \brief Actual data for the list of framework names used in the header
- /// search information.
- const char *HeaderFileFrameworkStrings;
-
// === Submodule information ===
/// \brief The number of submodules in this module.
unsigned LocalNumSubmodules;
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index 0a869e05f3..eb58803065 100644
--- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -214,6 +214,9 @@ private:
/// \sa shouldAvoidSuppressingNullArgumentPaths
Optional<bool> AvoidSuppressingNullArgumentPaths;
+ /// \sa shouldSuppressInlinedDefensiveChecks
+ Optional<bool> SuppressInlinedDefensiveChecks;
+
/// \sa getGraphTrimInterval
Optional<unsigned> GraphTrimInterval;
@@ -296,6 +299,13 @@ public:
/// option, which accepts the values "true" and "false".
bool shouldAvoidSuppressingNullArgumentPaths();
+ /// Returns whether or not diagnostics containing inlined defensive NULL
+ /// checks should be suppressed.
+ ///
+ /// This is controlled by the 'suppress-inlined-defensive-checks' config
+ /// option, which accepts the values "true" and "false".
+ bool shouldSuppressInlinedDefensiveChecks();
+
/// Returns whether irrelevant parts of a bug report path should be pruned
/// out of the final output.
///
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
index bef4b30a35..17c1009853 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
@@ -55,8 +55,8 @@ public:
///
/// The last parameter can be used to register a new visitor with the given
/// BugReport while processing a node.
- virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
- const ExplodedNode *PrevN,
+ virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
BugReporterContext &BRC,
BugReport &BR) = 0;
@@ -280,6 +280,42 @@ public:
BugReport &BR);
};
+class SuppressInlineDefensiveChecksVisitor
+: public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor>
+{
+ /// The symbolic value for which we are tracking constraints.
+ /// This value is constrained to null in the end of path.
+ DefinedSVal V;
+
+ /// Track if we found the node where the constraint was first added.
+ bool IsSatisfied;
+
+ /// \brief The node from which we should start tracking the value.
+ /// Note: Since the visitors can be registered on nodes previous to the last
+ /// node in the BugReport, but the path traversal always starts with the last
+ /// node, the visitor invariant (that we start with a node in which V is null)
+ /// might not hold when node visitation starts.
+ const ExplodedNode *StartN;
+
+public:
+ SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N);
+
+ void Profile(llvm::FoldingSetNodeID &ID) const;
+
+ /// Return the tag associated with this visitor. This tag will be used
+ /// to make all PathDiagnosticPieces created by this visitor.
+ static const char *getTag();
+
+ PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR);
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
+ BugReporterContext &BRC,
+ BugReport &BR);
+};
+
namespace bugreporter {
/// Attempts to add visitors to trace a null or undefined value back to its
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 6336a8b387..1c67668618 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -336,7 +336,9 @@ public:
/// of some kind.
static bool isCallStmt(const Stmt *S);
- /// \brief Returns the result type of a function, method declaration.
+ /// \brief Returns the result type of a function or method declaration.
+ ///
+ /// This will return a null QualType if the result type cannot be determined.
static QualType getDeclaredResultType(const Decl *D);
// Iterator access to formal parameters and their types.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index d7acb4842a..af2f365ead 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -651,9 +651,11 @@ public:
}
bool operator==(const referenced_vars_iterator &I) const {
+ assert((R == 0) == (I.R == 0));
return I.R == R;
}
bool operator!=(const referenced_vars_iterator &I) const {
+ assert((R == 0) == (I.R == 0));
return I.R != R;
}
referenced_vars_iterator &operator++() {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index eab248bac2..39e7429344 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -170,19 +170,30 @@ public:
// If no new state is feasible, NULL is returned.
//
+ /// Assumes that the value of \p cond is zero (if \p assumption is "false")
+ /// or non-zero (if \p assumption is "true").
+ ///
+ /// This returns a new state with the added constraint on \p cond.
+ /// If no new state is feasible, NULL is returned.
ProgramStateRef assume(DefinedOrUnknownSVal cond, bool assumption) const;
- /// This method assumes both "true" and "false" for 'cond', and
- /// returns both corresponding states. It's shorthand for doing
- /// 'assume' twice.
- std::pair<ProgramStateRef , ProgramStateRef >
+ /// Assumes both "true" and "false" for \p cond, and returns both
+ /// corresponding states (respectively).
+ ///
+ /// This is more efficient than calling assume() twice. Note that one (but not
+ /// both) of the returned states may be NULL.
+ std::pair<ProgramStateRef, ProgramStateRef>
assume(DefinedOrUnknownSVal cond) const;
ProgramStateRef assumeInBound(DefinedOrUnknownSVal idx,
DefinedOrUnknownSVal upperBound,
bool assumption,
QualType IndexType = QualType()) const;
-
+
+ /// \brief Check if the given SVal is constrained to zero or is a zero
+ /// constant.
+ ConditionTruthVal isNull(SVal V) const;
+
/// Utility method for getting regions.
const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const;
diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp
index 429a705a1f..fc4a75fdb8 100644
--- a/lib/ARCMigrate/TransUnbridgedCasts.cpp
+++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp
@@ -148,7 +148,7 @@ private:
if (FD->getName() == "CFRetain" &&
FD->getNumParams() == 1 &&
FD->getParent()->isTranslationUnit() &&
- FD->getLinkage() == ExternalLinkage) {
+ FD->hasExternalLinkage()) {
Expr *Arg = callE->getArg(0);
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
const Expr *sub = ICE->getSubExpr();
@@ -413,7 +413,7 @@ private:
FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
FD->getParent()->isTranslationUnit() &&
- FD->getLinkage() == ExternalLinkage)
+ FD->hasExternalLinkage())
return true;
return false;
diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp
index 136f618787..087219535a 100644
--- a/lib/ARCMigrate/Transforms.cpp
+++ b/lib/ARCMigrate/Transforms.cpp
@@ -94,7 +94,7 @@ bool trans::isPlusOne(const Expr *E) {
if (FD->isGlobal() &&
FD->getIdentifier() &&
FD->getParent()->isTranslationUnit() &&
- FD->getLinkage() == ExternalLinkage &&
+ FD->hasExternalLinkage() &&
ento::cocoa::isRefType(callE->getType(), "CF",
FD->getIdentifier()->getName())) {
StringRef fname = FD->getIdentifier()->getName();
@@ -198,7 +198,7 @@ bool trans::isGlobalVar(Expr *E) {
E = E->IgnoreParenCasts();
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return DRE->getDecl()->getDeclContext()->isFileContext() &&
- DRE->getDecl()->getLinkage() == ExternalLinkage;
+ DRE->getDecl()->hasExternalLinkage();
if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
return isGlobalVar(condOp->getTrueExpr()) &&
isGlobalVar(condOp->getFalseExpr());
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index db1aa1a944..b55a926e32 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1602,18 +1602,21 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
}
case Type::Atomic: {
+ // Start with the base type information.
std::pair<uint64_t, unsigned> Info
= getTypeInfo(cast<AtomicType>(T)->getValueType());
Width = Info.first;
Align = Info.second;
- if (Width != 0 && Width <= Target->getMaxAtomicPromoteWidth() &&
- llvm::isPowerOf2_64(Width)) {
- // We can potentially perform lock-free atomic operations for this
- // type; promote the alignment appropriately.
- // FIXME: We could potentially promote the width here as well...
- // is that worthwhile? (Non-struct atomic types generally have
- // power-of-two size anyway, but structs might not. Requires a bit
- // of implementation work to make sure we zero out the extra bits.)
+
+ // If the size of the type doesn't exceed the platform's max
+ // atomic promotion width, make the size and alignment more
+ // favorable to atomic operations:
+ if (Width != 0 && Width <= Target->getMaxAtomicPromoteWidth()) {
+ // Round the size up to a power of 2.
+ if (!llvm::isPowerOf2_64(Width))
+ Width = llvm::NextPowerOf2(Width);
+
+ // Set the alignment equal to the size.
Align = static_cast<unsigned>(Width);
}
}
@@ -1971,8 +1974,10 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
const FunctionProtoType *FPT = cast<FunctionProtoType>(T);
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = Info;
- Result = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI);
+ Result = getFunctionType(FPT->getResultType(),
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
}
return cast<FunctionType>(Result.getTypePtr());
@@ -2637,13 +2642,15 @@ static bool isCanonicalResultType(QualType T) {
/// getFunctionType - Return a normal function type with a typed argument
/// list. isVariadic indicates whether the argument list includes '...'.
QualType
-ASTContext::getFunctionType(QualType ResultTy,
- const QualType *ArgArray, unsigned NumArgs,
+ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
const FunctionProtoType::ExtProtoInfo &EPI) const {
+ size_t NumArgs = ArgArray.size();
+
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
- FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI, *this);
+ FunctionProtoType::Profile(ID, ResultTy, ArgArray.begin(), NumArgs, EPI,
+ *this);
void *InsertPos = 0;
if (FunctionProtoType *FTP =
@@ -2686,9 +2693,7 @@ ASTContext::getFunctionType(QualType ResultTy,
CanResultTy = getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
}
- Canonical = getFunctionType(CanResultTy,
- CanonicalArgs.data(), NumArgs,
- CanonicalEPI);
+ Canonical = getFunctionType(CanResultTy, CanonicalArgs, CanonicalEPI);
// Get the new insert position for the node we care about.
FunctionProtoType *NewIP =
@@ -2721,7 +2726,7 @@ ASTContext::getFunctionType(QualType ResultTy,
FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
FunctionProtoType::ExtProtoInfo newEPI = EPI;
newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv);
- new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, newEPI);
+ new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI);
Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos);
return QualType(FTP, 0);
@@ -6791,7 +6796,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionProtoType::ExtProtoInfo EPI = lproto->getExtProtoInfo();
EPI.ExtInfo = einfo;
- return getFunctionType(retType, types.begin(), types.size(), EPI);
+ return getFunctionType(retType, types, EPI);
}
if (lproto) allRTypes = false;
@@ -6828,8 +6833,10 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionProtoType::ExtProtoInfo EPI = proto->getExtProtoInfo();
EPI.ExtInfo = einfo;
- return getFunctionType(retType, proto->arg_type_begin(),
- proto->getNumArgs(), EPI);
+ return getFunctionType(retType,
+ ArrayRef<QualType>(proto->arg_type_begin(),
+ proto->getNumArgs()),
+ EPI);
}
if (allLTypes) return lhs;
@@ -7162,8 +7169,10 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = getFunctionExtInfo(LHS);
QualType ResultType
- = getFunctionType(OldReturnType, FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI);
+ = getFunctionType(OldReturnType,
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
return ResultType;
}
}
@@ -7555,7 +7564,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
EPI.ExtInfo = EI;
EPI.Variadic = Variadic;
- return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), EPI);
+ return getFunctionType(ResType, ArgTypes, EPI);
}
GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
@@ -7620,8 +7629,6 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
TSK = VD->getTemplateSpecializationKind();
Linkage L = VD->getLinkage();
- assert (!(L == ExternalLinkage && getLangOpts().CPlusPlus &&
- VD->getType()->getLinkage() == UniqueExternalLinkage));
switch (L) {
case NoLinkage:
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index bdf2bbc7e5..01d1a1e917 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -1619,8 +1619,7 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
ToEPI.ExceptionSpecTemplate = cast_or_null<FunctionDecl>(
Importer.Import(FromEPI.ExceptionSpecTemplate));
- return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(),
- ArgTypes.size(), ToEPI);
+ return Importer.getToContext().getFunctionType(ToResultType, ArgTypes, ToEPI);
}
QualType ASTNodeImporter::VisitParenType(const ParenType *T) {
@@ -2660,8 +2659,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
FunctionProtoType::ExtProtoInfo DefaultEPI;
FromTy = Importer.getFromContext().getFunctionType(
FromFPT->getResultType(),
- FromFPT->arg_type_begin(),
- FromFPT->arg_type_end() - FromFPT->arg_type_begin(),
+ ArrayRef<QualType>(FromFPT->arg_type_begin(),
+ FromFPT->getNumArgs()),
DefaultEPI);
usedDifferentExceptionSpec = true;
}
diff --git a/lib/AST/CommentBriefParser.cpp b/lib/AST/CommentBriefParser.cpp
index 95daa7e3f8..090b9211d4 100644
--- a/lib/AST/CommentBriefParser.cpp
+++ b/lib/AST/CommentBriefParser.cpp
@@ -78,7 +78,7 @@ std::string BriefParser::Parse() {
continue;
}
- if (Tok.is(tok::command)) {
+ if (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)) {
const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
if (Info->IsBriefCommand) {
FirstParagraphOrBrief.clear();
diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp
index cee086e103..1194520bf3 100644
--- a/lib/AST/CommentLexer.cpp
+++ b/lib/AST/CommentLexer.cpp
@@ -298,6 +298,11 @@ void Lexer::lexCommentText(Token &T) {
switch(*TokenPtr) {
case '\\':
case '@': {
+ // Commands that start with a backslash and commands that start with
+ // 'at' have equivalent semantics. But we keep information about the
+ // exact syntax in AST for comments.
+ tok::TokenKind CommandKind =
+ (*TokenPtr == '@') ? tok::at_command : tok::backslash_command;
TokenPtr++;
if (TokenPtr == CommentEnd) {
formTextToken(T, TokenPtr);
@@ -358,7 +363,7 @@ void Lexer::lexCommentText(Token &T) {
setupAndLexVerbatimLine(T, TokenPtr, Info);
return;
}
- formTokenWithChars(T, TokenPtr, tok::command);
+ formTokenWithChars(T, TokenPtr, CommandKind);
T.setCommandID(Info->getID());
return;
}
diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp
index 952c10c4a8..09912c6188 100644
--- a/lib/AST/CommentParser.cpp
+++ b/lib/AST/CommentParser.cpp
@@ -300,7 +300,7 @@ void Parser::parseBlockCommandArgs(BlockCommandComment *BC,
}
BlockCommandComment *Parser::parseBlockCommand() {
- assert(Tok.is(tok::command));
+ assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command));
ParamCommandComment *PC;
TParamCommandComment *TPC;
@@ -308,20 +308,25 @@ BlockCommandComment *Parser::parseBlockCommand() {
bool IsParam = false;
bool IsTParam = false;
const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
+ CommandMarkerKind CommandMarker =
+ Tok.is(tok::backslash_command) ? CMK_Backslash : CMK_At;
if (Info->IsParamCommand) {
IsParam = true;
PC = S.actOnParamCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandID());
+ Tok.getCommandID(),
+ CommandMarker);
} else if (Info->IsTParamCommand) {
IsTParam = true;
TPC = S.actOnTParamCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandID());
+ Tok.getCommandID(),
+ CommandMarker);
} else {
BC = S.actOnBlockCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandID());
+ Tok.getCommandID(),
+ CommandMarker);
}
consumeToken();
@@ -392,7 +397,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
}
InlineCommandComment *Parser::parseInlineCommand() {
- assert(Tok.is(tok::command));
+ assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command));
const Token CommandTok = Tok;
consumeToken();
@@ -559,7 +564,8 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
consumeToken();
continue;
- case tok::command: {
+ case tok::backslash_command:
+ case tok::at_command: {
const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
if (Info->IsBlockCommand) {
if (Content.size() == 0)
@@ -569,6 +575,7 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
if (Info->IsVerbatimBlockEndCommand) {
Diag(Tok.getLocation(),
diag::warn_verbatim_block_end_without_start)
+ << Tok.is(tok::at_command)
<< Info->Name
<< SourceRange(Tok.getLocation(), Tok.getEndLocation());
consumeToken();
@@ -706,7 +713,8 @@ BlockContentComment *Parser::parseBlockContent() {
switch (Tok.getKind()) {
case tok::text:
case tok::unknown_command:
- case tok::command:
+ case tok::backslash_command:
+ case tok::at_command:
case tok::html_start_tag:
case tok::html_end_tag:
return parseParagraphOrBlockCommand();
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index 73e49e71db..e6367c9755 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -47,10 +47,16 @@ ParagraphComment *Sema::actOnParagraphComment(
return new (Allocator) ParagraphComment(Content);
}
-BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin,
- SourceLocation LocEnd,
- unsigned CommandID) {
- return new (Allocator) BlockCommandComment(LocBegin, LocEnd, CommandID);
+BlockCommandComment *Sema::actOnBlockCommandStart(
+ SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) {
+ BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd,
+ CommandID,
+ CommandMarker);
+ checkContainerDecl(BC);
+ return BC;
}
void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
@@ -67,20 +73,133 @@ void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
checkDeprecatedCommand(Command);
}
-ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin,
- SourceLocation LocEnd,
- unsigned CommandID) {
+ParamCommandComment *Sema::actOnParamCommandStart(
+ SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) {
ParamCommandComment *Command =
- new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID);
+ new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
+ CommandMarker);
if (!isFunctionDecl())
Diag(Command->getLocation(),
diag::warn_doc_param_not_attached_to_a_function_decl)
+ << CommandMarker
<< Command->getCommandNameRange(Traits);
return Command;
}
+void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
+ const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
+ if (!Info->IsFunctionDeclarationCommand)
+ return;
+
+ unsigned DiagSelect;
+ switch (Comment->getCommandID()) {
+ case CommandTraits::KCI_function:
+ DiagSelect = !isAnyFunctionDecl() ? 1 : 0;
+ break;
+ case CommandTraits::KCI_method:
+ DiagSelect = !isObjCMethodDecl() ? 2 : 0;
+ break;
+ case CommandTraits::KCI_callback:
+ DiagSelect = !isFunctionPointerVarDecl() ? 3 : 0;
+ break;
+ default:
+ DiagSelect = 0;
+ break;
+ }
+ if (DiagSelect)
+ Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch)
+ << Comment->getCommandMarker()
+ << (DiagSelect-1) << (DiagSelect-1)
+ << Comment->getSourceRange();
+}
+
+void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
+ const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
+ if (!Info->IsRecordLikeDeclarationCommand)
+ return;
+ unsigned DiagSelect;
+ switch (Comment->getCommandID()) {
+ case CommandTraits::KCI_class:
+ DiagSelect = !isClassOrStructDecl() ? 1 : 0;
+ break;
+ case CommandTraits::KCI_interface:
+ DiagSelect = !isObjCInterfaceDecl() ? 2 : 0;
+ break;
+ case CommandTraits::KCI_protocol:
+ DiagSelect = !isObjCProtocolDecl() ? 3 : 0;
+ break;
+ case CommandTraits::KCI_struct:
+ DiagSelect = !isClassOrStructDecl() ? 4 : 0;
+ break;
+ case CommandTraits::KCI_union:
+ DiagSelect = !isUnionDecl() ? 5 : 0;
+ break;
+ default:
+ DiagSelect = 0;
+ break;
+ }
+ if (DiagSelect)
+ Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
+ << Comment->getCommandMarker()
+ << (DiagSelect-1) << (DiagSelect-1)
+ << Comment->getSourceRange();
+}
+
+void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
+ const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
+ if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl())
+ return;
+ unsigned DiagSelect;
+ switch (Comment->getCommandID()) {
+ case CommandTraits::KCI_classdesign:
+ DiagSelect = 1;
+ break;
+ case CommandTraits::KCI_coclass:
+ DiagSelect = 2;
+ break;
+ case CommandTraits::KCI_dependency:
+ DiagSelect = 3;
+ break;
+ case CommandTraits::KCI_helper:
+ DiagSelect = 4;
+ break;
+ case CommandTraits::KCI_helperclass:
+ DiagSelect = 5;
+ break;
+ case CommandTraits::KCI_helps:
+ DiagSelect = 6;
+ break;
+ case CommandTraits::KCI_instancesize:
+ DiagSelect = 7;
+ break;
+ case CommandTraits::KCI_ownership:
+ DiagSelect = 8;
+ break;
+ case CommandTraits::KCI_performance:
+ DiagSelect = 9;
+ break;
+ case CommandTraits::KCI_security:
+ DiagSelect = 10;
+ break;
+ case CommandTraits::KCI_superclass:
+ DiagSelect = 11;
+ break;
+ default:
+ DiagSelect = 0;
+ break;
+ }
+ if (DiagSelect)
+ Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
+ << Comment->getCommandMarker()
+ << (DiagSelect-1)
+ << Comment->getSourceRange();
+}
+
void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
SourceLocation ArgLocBegin,
SourceLocation ArgLocEnd,
@@ -160,15 +279,19 @@ void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
checkBlockCommandEmptyParagraph(Command);
}
-TParamCommandComment *Sema::actOnTParamCommandStart(SourceLocation LocBegin,
- SourceLocation LocEnd,
- unsigned CommandID) {
+TParamCommandComment *Sema::actOnTParamCommandStart(
+ SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) {
TParamCommandComment *Command =
- new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID);
+ new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID,
+ CommandMarker);
if (!isTemplateOrSpecialization())
Diag(Command->getLocation(),
diag::warn_doc_tparam_not_attached_to_a_template_decl)
+ << CommandMarker
<< Command->getCommandNameRange(Traits);
return Command;
@@ -326,12 +449,15 @@ VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
unsigned CommandID,
SourceLocation TextBegin,
StringRef Text) {
- return new (Allocator) VerbatimLineComment(
+ VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
LocBegin,
TextBegin.getLocWithOffset(Text.size()),
CommandID,
TextBegin,
Text);
+ checkFunctionDeclVerbatimLine(VL);
+ checkContainerDeclVerbatimLine(VL);
+ return VL;
}
HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
@@ -432,6 +558,7 @@ void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
if (!DiagLoc.isValid())
DiagLoc = Command->getCommandNameRange(Traits).getEnd();
Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
+ << Command->getCommandMarker()
<< Command->getCommandName(Traits)
<< Command->getSourceRange();
}
@@ -459,6 +586,7 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
}
Diag(Command->getLocation(),
diag::warn_doc_returns_attached_to_a_void_function)
+ << Command->getCommandMarker()
<< Command->getCommandName(Traits)
<< DiagKind
<< Command->getSourceRange();
@@ -470,6 +598,7 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
Diag(Command->getLocation(),
diag::warn_doc_returns_not_attached_to_a_function_decl)
+ << Command->getCommandMarker()
<< Command->getCommandName(Traits)
<< Command->getSourceRange();
}
@@ -502,15 +631,18 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
StringRef CommandName = Command->getCommandName(Traits);
StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
+ << Command->getCommandMarker()
<< CommandName
<< Command->getSourceRange();
if (CommandName == PrevCommandName)
Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
+ << PrevCommand->getCommandMarker()
<< PrevCommandName
<< PrevCommand->getSourceRange();
else
Diag(PrevCommand->getLocation(),
diag::note_doc_block_command_previous_alias)
+ << PrevCommand->getCommandMarker()
<< PrevCommandName
<< CommandName;
}
@@ -655,6 +787,32 @@ bool Sema::isFunctionDecl() {
inspectThisDecl();
return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
}
+
+bool Sema::isAnyFunctionDecl() {
+ return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
+ isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
+}
+
+bool Sema::isObjCMethodDecl() {
+ return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
+ isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
+}
+
+/// isFunctionPointerVarDecl - returns 'true' if declaration is a pointer to
+/// function decl.
+bool Sema::isFunctionPointerVarDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
+ if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
+ QualType QT = VD->getType();
+ return QT->isFunctionPointerType();
+ }
+ }
+ return false;
+}
bool Sema::isObjCPropertyDecl() {
if (!ThisDeclInfo)
@@ -672,6 +830,54 @@ bool Sema::isTemplateOrSpecialization() {
return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
}
+bool Sema::isRecordLikeDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return isUnionDecl() || isClassOrStructDecl()
+ || isObjCInterfaceDecl() || isObjCProtocolDecl();
+}
+
+bool Sema::isUnionDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ if (const RecordDecl *RD =
+ dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
+ return RD->isUnion();
+ return false;
+}
+
+bool Sema::isClassOrStructDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
+ !isUnionDecl();
+}
+
+bool Sema::isObjCInterfaceDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
+}
+
+bool Sema::isObjCProtocolDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
+}
+
ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
if (!ThisDeclInfo->IsFilled)
inspectThisDecl();
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index b8439cae74..9ee70e2510 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -620,8 +620,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
//
// Note that we don't want to make the variable non-external
// because of this, but unique-external linkage suits us.
- if (Context.getLangOpts().CPlusPlus &&
- !Var->getDeclContext()->isExternCContext()) {
+ if (Context.getLangOpts().CPlusPlus && !isInExternCContext(Var)) {
LinkageInfo TypeLV = Var->getType()->getLinkageAndVisibility();
if (TypeLV.getLinkage() != ExternalLinkage)
return LinkageInfo::uniqueExternal();
@@ -675,7 +674,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// has the typedef name for linkage purposes (7.1.3); or
} else if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) {
// Unnamed tags have no linkage.
- if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl())
+ if (!Tag->hasNameForLinkage())
return LinkageInfo::none();
// If this is a class template specialization, consider the
@@ -1049,8 +1048,7 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
}
if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
- if (Var->getStorageClassAsWritten() == SC_Extern ||
- Var->getStorageClassAsWritten() == SC_PrivateExtern) {
+ if (Var->hasExternalStorageAsWritten()) {
if (Var->isInAnonymousNamespace() &&
!Var->getDeclContext()->isExternCContext())
return LinkageInfo::uniqueExternal();
@@ -1600,9 +1598,8 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
// AST for 'extern "C" int foo;' is annotated with 'extern'.
if (hasExternalStorage())
return DeclarationOnly;
-
- if (getStorageClassAsWritten() == SC_Extern ||
- getStorageClassAsWritten() == SC_PrivateExtern) {
+
+ if (hasExternalStorageAsWritten()) {
for (const VarDecl *PrevVar = getPreviousDecl();
PrevVar; PrevVar = PrevVar->getPreviousDecl()) {
if (PrevVar->getLinkage() == InternalLinkage)
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index d539e0098f..d1bf9a9e45 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -1093,38 +1093,51 @@ namespace {
/// all_declared_ivar_begin - return first ivar declared in this class,
/// its extensions and its implementation. Lazily build the list on first
/// access.
+///
+/// Caveat: The list returned by this method reflects the current
+/// state of the parser. The cache will be updated for every ivar
+/// added by an extension or the implementation when they are
+/// encountered.
+/// See also ObjCIvarDecl::Create().
ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
- if (data().IvarList)
- return data().IvarList;
-
ObjCIvarDecl *curIvar = 0;
- if (!ivar_empty()) {
- ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
- data().IvarList = *I; ++I;
- for (curIvar = data().IvarList; I != E; curIvar = *I, ++I)
- curIvar->setNextIvar(*I);
- }
+ if (!data().IvarList) {
+ if (!ivar_empty()) {
+ ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
+ data().IvarList = *I; ++I;
+ for (curIvar = data().IvarList; I != E; curIvar = *I, ++I)
+ curIvar->setNextIvar(*I);
+ }
- for (ObjCInterfaceDecl::known_extensions_iterator
- Ext = known_extensions_begin(),
- ExtEnd = known_extensions_end();
- Ext != ExtEnd; ++Ext) {
- if (!Ext->ivar_empty()) {
- ObjCCategoryDecl::ivar_iterator I = Ext->ivar_begin(),E = Ext->ivar_end();
- if (!data().IvarList) {
- data().IvarList = *I; ++I;
- curIvar = data().IvarList;
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = known_extensions_begin(),
+ ExtEnd = known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (!Ext->ivar_empty()) {
+ ObjCCategoryDecl::ivar_iterator
+ I = Ext->ivar_begin(),
+ E = Ext->ivar_end();
+ if (!data().IvarList) {
+ data().IvarList = *I; ++I;
+ curIvar = data().IvarList;
+ }
+ for ( ;I != E; curIvar = *I, ++I)
+ curIvar->setNextIvar(*I);
}
- for ( ;I != E; curIvar = *I, ++I)
- curIvar->setNextIvar(*I);
}
+ data().IvarListMissingImplementation = true;
}
+
+ // cached and complete!
+ if (!data().IvarListMissingImplementation)
+ return data().IvarList;
if (ObjCImplementationDecl *ImplDecl = getImplementation()) {
+ data().IvarListMissingImplementation = false;
if (!ImplDecl->ivar_empty()) {
SmallVector<SynthesizeIvarChunk, 16> layout;
for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index e1e96e4c5c..12a47fcd78 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -178,7 +178,8 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context,
SourceLocation ColonColonLoc, SourceLocation TildeLoc,
PseudoDestructorTypeStorage DestroyedType)
: Expr(CXXPseudoDestructorExprClass,
- Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0,
+ Context.getPointerType(Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(),
FunctionProtoType::ExtProtoInfo())),
VK_RValue, OK_Ordinary,
/*isTypeDependent=*/(Base->isTypeDependent() ||
diff --git a/lib/AST/LambdaMangleContext.cpp b/lib/AST/LambdaMangleContext.cpp
index 6f4fe2d4b4..54f445df4b 100644
--- a/lib/AST/LambdaMangleContext.cpp
+++ b/lib/AST/LambdaMangleContext.cpp
@@ -23,10 +23,11 @@ unsigned LambdaMangleContext::getManglingNumber(CXXMethodDecl *CallOperator) {
= CallOperator->getType()->getAs<FunctionProtoType>();
ASTContext &Context = CallOperator->getASTContext();
- QualType Key = Context.getFunctionType(Context.VoidTy,
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
- FunctionProtoType::ExtProtoInfo());
+ QualType Key =
+ Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
+ FunctionProtoType::ExtProtoInfo());
Key = Context.getCanonicalType(Key);
return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
}
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index f68dbda7c7..8767c635f6 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -163,7 +163,9 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
LangOptions LO;
LO.CPlusPlus = true;
LO.Bool = true;
+ OS << '\'';
N.print(OS, PrintingPolicy(LO));
+ OS << '\'';
OS.flush();
return DB << NameStr;
}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index e6687a7717..ca086b1951 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1560,8 +1560,8 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
llvm_unreachable("Invalid calling convention.");
}
-FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
- unsigned numArgs, QualType canonical,
+FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> args,
+ QualType canonical,
const ExtProtoInfo &epi)
: FunctionType(FunctionProto, result, epi.TypeQuals,
canonical,
@@ -1570,17 +1570,17 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
result->isVariablyModifiedType(),
result->containsUnexpandedParameterPack(),
epi.ExtInfo),
- NumArgs(numArgs), NumExceptions(epi.NumExceptions),
+ NumArgs(args.size()), NumExceptions(epi.NumExceptions),
ExceptionSpecType(epi.ExceptionSpecType),
HasAnyConsumedArgs(epi.ConsumedArguments != 0),
Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn),
RefQualifier(epi.RefQualifier)
{
- assert(NumArgs == numArgs && "function has too many parameters");
+ assert(NumArgs == args.size() && "function has too many parameters");
// Fill in the trailing argument array.
QualType *argSlot = reinterpret_cast<QualType*>(this+1);
- for (unsigned i = 0; i != numArgs; ++i) {
+ for (unsigned i = 0; i != NumArgs; ++i) {
if (args[i]->isDependentType())
setDependent();
else if (args[i]->isInstantiationDependentType())
@@ -1594,7 +1594,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
if (getExceptionSpecType() == EST_Dynamic) {
// Fill in the exception array.
- QualType *exnSlot = argSlot + numArgs;
+ QualType *exnSlot = argSlot + NumArgs;
for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) {
if (epi.Exceptions[i]->isDependentType())
setDependent();
@@ -1608,7 +1608,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
}
} else if (getExceptionSpecType() == EST_ComputedNoexcept) {
// Store the noexcept expression and context.
- Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + numArgs);
+ Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + NumArgs);
*noexSlot = epi.NoexceptExpr;
if (epi.NoexceptExpr) {
@@ -1621,7 +1621,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
} else if (getExceptionSpecType() == EST_Uninstantiated) {
// Store the function decl from which we will resolve our
// exception specification.
- FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + numArgs);
+ FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + NumArgs);
slot[0] = epi.ExceptionSpecDecl;
slot[1] = epi.ExceptionSpecTemplate;
// This exception specification doesn't make the type dependent, because
@@ -1629,13 +1629,13 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
} else if (getExceptionSpecType() == EST_Unevaluated) {
// Store the function decl from which we will resolve our
// exception specification.
- FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + numArgs);
+ FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + NumArgs);
slot[0] = epi.ExceptionSpecDecl;
}
if (epi.ConsumedArguments) {
bool *consumedArgs = const_cast<bool*>(getConsumedArgsBuffer());
- for (unsigned i = 0; i != numArgs; ++i)
+ for (unsigned i = 0; i != NumArgs; ++i)
consumedArgs[i] = epi.ConsumedArguments[i];
}
}
@@ -2099,7 +2099,7 @@ static CachedProperties computeCachedProperties(const Type *T) {
Linkage L = Tag->getLinkage();
bool IsLocalOrUnnamed =
Tag->getDeclContext()->isFunctionOrMethod() ||
- (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl());
+ !Tag->hasNameForLinkage();
return CachedProperties(L, IsLocalOrUnnamed);
}
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index dc2e310449..353af4bd6d 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -281,14 +281,14 @@ namespace clang {
/// diagnostic.
StringRef getDescription(unsigned DiagID) const {
assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
- "Invalid diagnosic ID");
+ "Invalid diagnostic ID");
return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second;
}
/// getLevel - Return the level of the specified custom diagnostic.
DiagnosticIDs::Level getLevel(unsigned DiagID) const {
assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
- "Invalid diagnosic ID");
+ "Invalid diagnostic ID");
return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
}
@@ -325,7 +325,7 @@ DiagnosticIDs::~DiagnosticIDs() {
}
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
-/// and level. If this is the first request for this diagnosic, it is
+/// and level. If this is the first request for this diagnostic, it is
/// registered and created, otherwise the existing ID is returned.
unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef Message) {
if (CustomDiagInfo == 0)
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index ea9565006c..1b8383bc42 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -840,10 +840,17 @@ FileID SourceManager::getFileIDLoaded(unsigned SLocOffset) const {
++NumProbes;
unsigned MiddleIndex = (LessIndex - GreaterIndex) / 2 + GreaterIndex;
const SrcMgr::SLocEntry &E = getLoadedSLocEntry(MiddleIndex);
+ if (E.getOffset() == 0)
+ return FileID(); // invalid entry.
++NumProbes;
if (E.getOffset() > SLocOffset) {
+ // Sanity checking, otherwise a bug may lead to hanging in release build.
+ if (GreaterIndex == MiddleIndex) {
+ assert(0 && "binary search missed the entry");
+ return FileID();
+ }
GreaterIndex = MiddleIndex;
continue;
}
@@ -856,6 +863,11 @@ FileID SourceManager::getFileIDLoaded(unsigned SLocOffset) const {
return Res;
}
+ // Sanity checking, otherwise a bug may lead to hanging in release build.
+ if (LessIndex == MiddleIndex) {
+ assert(0 && "binary search missed the entry");
+ return FileID();
+ }
LessIndex = MiddleIndex;
}
}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 24a69ee22b..b7cd3dce7c 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -1373,16 +1373,50 @@ static const unsigned R600AddrSpaceMap[] = {
3 // cuda_shared
};
+static const char *DescriptionStringR600 =
+ "e"
+ "-p:32:32:32"
+ "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32"
+ "-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128"
+ "-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024-v2048:2048:2048"
+ "-n32:64";
+
+static const char *DescriptionStringR600DoubleOps =
+ "e"
+ "-p:32:32:32"
+ "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64"
+ "-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128"
+ "-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024-v2048:2048:2048"
+ "-n32:64";
+
+static const char *DescriptionStringSI =
+ "e"
+ "-p:64:64:64"
+ "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64"
+ "-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128"
+ "-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024-v2048:2048:2048"
+ "-n32:64";
+
class R600TargetInfo : public TargetInfo {
+ /// \brief The GPU profiles supported by the R600 target.
+ enum GPUKind {
+ GK_NONE,
+ GK_R600,
+ GK_R600_DOUBLE_OPS,
+ GK_R700,
+ GK_R700_DOUBLE_OPS,
+ GK_EVERGREEN,
+ GK_EVERGREEN_DOUBLE_OPS,
+ GK_NORTHERN_ISLANDS,
+ GK_CAYMAN,
+ GK_SOUTHERN_ISLANDS
+ } GPU;
+
public:
- R600TargetInfo(const std::string& triple) : TargetInfo(triple) {
- DescriptionString =
- "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16"
- "-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f80:32:32"
- "-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64"
- "-v96:128:128-v128:128:128-v192:256:256-v256:256:256"
- "-v512:512:512-v1024:1024:1024-v2048:2048:2048"
- "-n8:16:32:64";
+ R600TargetInfo(const std::string& triple)
+ : TargetInfo(triple),
+ GPU(GK_R600) {
+ DescriptionString = DescriptionStringR600;
AddrSpaceMap = &R600AddrSpaceMap;
}
@@ -1423,6 +1457,65 @@ public:
return TargetInfo::CharPtrBuiltinVaList;
}
+ virtual bool setCPU(const std::string &Name) {
+ GPU = llvm::StringSwitch<GPUKind>(Name)
+ .Case("r600" , GK_R600)
+ .Case("rv610", GK_R600)
+ .Case("rv620", GK_R600)
+ .Case("rv630", GK_R600)
+ .Case("rv635", GK_R600)
+ .Case("rs780", GK_R600)
+ .Case("rs880", GK_R600)
+ .Case("rv670", GK_R600_DOUBLE_OPS)
+ .Case("rv710", GK_R700)
+ .Case("rv730", GK_R700)
+ .Case("rv740", GK_R700_DOUBLE_OPS)
+ .Case("rv770", GK_R700_DOUBLE_OPS)
+ .Case("palm", GK_EVERGREEN)
+ .Case("cedar", GK_EVERGREEN)
+ .Case("sumo", GK_EVERGREEN)
+ .Case("sumo2", GK_EVERGREEN)
+ .Case("redwood", GK_EVERGREEN)
+ .Case("juniper", GK_EVERGREEN)
+ .Case("hemlock", GK_EVERGREEN_DOUBLE_OPS)
+ .Case("cypress", GK_EVERGREEN_DOUBLE_OPS)
+ .Case("barts", GK_NORTHERN_ISLANDS)
+ .Case("turks", GK_NORTHERN_ISLANDS)
+ .Case("caicos", GK_NORTHERN_ISLANDS)
+ .Case("cayman", GK_CAYMAN)
+ .Case("aruba", GK_CAYMAN)
+ .Case("SI", GK_SOUTHERN_ISLANDS)
+ .Case("pitcairn", GK_SOUTHERN_ISLANDS)
+ .Case("verde", GK_SOUTHERN_ISLANDS)
+ .Case("oland", GK_SOUTHERN_ISLANDS)
+ .Default(GK_NONE);
+
+ if (GPU == GK_NONE) {
+ return false;
+ }
+
+ // Set the correct data layout
+ switch (GPU) {
+ case GK_NONE:
+ case GK_R600:
+ case GK_R700:
+ case GK_EVERGREEN:
+ case GK_NORTHERN_ISLANDS:
+ DescriptionString = DescriptionStringR600;
+ break;
+ case GK_R600_DOUBLE_OPS:
+ case GK_R700_DOUBLE_OPS:
+ case GK_EVERGREEN_DOUBLE_OPS:
+ case GK_CAYMAN:
+ DescriptionString = DescriptionStringR600DoubleOps;
+ break;
+ case GK_SOUTHERN_ISLANDS:
+ DescriptionString = DescriptionStringSI;
+ break;
+ }
+
+ return true;
+ }
};
} // end anonymous namespace
@@ -3462,7 +3555,7 @@ public:
else if (CPU == "cortex-a8" || CPU == "cortex-a15" ||
CPU == "cortex-a9" || CPU == "cortex-a9-mp")
Features["neon"] = true;
- else if (CPU == "swift") {
+ else if (CPU == "swift" || CPU == "cortex-a7") {
Features["vfp4"] = true;
Features["neon"] = true;
}
@@ -3535,7 +3628,8 @@ public:
.Cases("arm1176jz-s", "arm1176jzf-s", "6ZK")
.Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K")
.Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
- .Cases("cortex-a5", "cortex-a8", "cortex-a9", "cortex-a15", "7A")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "7A")
+ .Cases("cortex-a9", "cortex-a15", "7A")
.Case("cortex-r5", "7R")
.Case("cortex-a9-mp", "7F")
.Case("swift", "7S")
@@ -3866,8 +3960,6 @@ public:
static const char *getHexagonCPUSuffix(StringRef Name) {
return llvm::StringSwitch<const char*>(Name)
- .Case("hexagonv2", "2")
- .Case("hexagonv3", "3")
.Case("hexagonv4", "4")
.Case("hexagonv5", "5")
.Default(0);
@@ -4393,6 +4485,9 @@ public:
case 'x': // hilo register pair
Info.setAllowsRegister();
return true;
+ case 'R': // An address that can be used in a non-macro load or store
+ Info.setAllowsMemory();
+ return true;
}
}
@@ -4835,11 +4930,15 @@ namespace {
SizeType = TargetInfo::UnsignedInt;
PtrDiffType = IntPtrType = TargetInfo::SignedInt;
DescriptionString
- = "p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"
+ = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"
"f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:32-v48:64:64-"
"v64:64:64-v96:128:128-v128:128:128-v192:256:256-v256:256:256-"
"v512:512:512-v1024:1024:1024";
- }
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "SPIR32", Opts);
+ }
};
class SPIR64TargetInfo : public SPIRTargetInfo {
@@ -4849,11 +4948,15 @@ namespace {
SizeType = TargetInfo::UnsignedLong;
PtrDiffType = IntPtrType = TargetInfo::SignedLong;
DescriptionString
- = "p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"
+ = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"
"f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:32-v48:64:64-"
"v64:64:64-v96:128:128-v128:128:128-v192:256:256-v256:256:256-"
"v512:512:512-v1024:1024:1024";
- }
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "SPIR64", Opts);
+ }
};
}
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index 10e2f60c86..35780f1556 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/lib/CodeGen/ABIInfo.h
@@ -12,6 +12,7 @@
#include "clang/AST/Type.h"
#include "llvm/IR/Type.h"
+#include "llvm/IR/CallingConv.h"
namespace llvm {
class Value;
@@ -184,14 +185,24 @@ namespace clang {
class ABIInfo {
public:
CodeGen::CodeGenTypes &CGT;
+ protected:
+ llvm::CallingConv::ID RuntimeCC;
+ public:
+ ABIInfo(CodeGen::CodeGenTypes &cgt)
+ : CGT(cgt), RuntimeCC(llvm::CallingConv::C) {}
- ABIInfo(CodeGen::CodeGenTypes &cgt) : CGT(cgt) {}
virtual ~ABIInfo();
ASTContext &getContext() const;
llvm::LLVMContext &getVMContext() const;
const llvm::DataLayout &getDataLayout() const;
+ /// Return the calling convention to use for system runtime
+ /// functions.
+ llvm::CallingConv::ID getRuntimeCC() const {
+ return RuntimeCC;
+ }
+
virtual void computeInfo(CodeGen::CGFunctionInfo &FI) const = 0;
/// EmitVAArg - Emit the target dependent code to load a value of
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 14eb57d27e..ab65801ce5 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -305,10 +305,10 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
if (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) {
MPM->add(createGCOVProfilerPass(CodeGenOpts.EmitGcovNotes,
CodeGenOpts.EmitGcovArcs,
- TargetTriple.isMacOSX(),
- false,
+ CodeGenOpts.CoverageVersion,
+ CodeGenOpts.CoverageExtraChecksum,
CodeGenOpts.DisableRedZone,
- false));
+ CodeGenOpts.CoverageFunctionNamesInData));
if (CodeGenOpts.getDebugInfo() == CodeGenOptions::NoDebugInfo)
MPM->add(createStripSymbolsPass(true));
diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp
new file mode 100644
index 0000000000..817d5c4cc6
--- /dev/null
+++ b/lib/CodeGen/CGAtomic.cpp
@@ -0,0 +1,942 @@
+//===--- CGAtomic.cpp - Emit LLVM IR for atomic operations ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the code for emitting atomic operations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenFunction.h"
+#include "CGCall.h"
+#include "CodeGenModule.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Operator.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+// The ABI values for various atomic memory orderings.
+enum AtomicOrderingKind {
+ AO_ABI_memory_order_relaxed = 0,
+ AO_ABI_memory_order_consume = 1,
+ AO_ABI_memory_order_acquire = 2,
+ AO_ABI_memory_order_release = 3,
+ AO_ABI_memory_order_acq_rel = 4,
+ AO_ABI_memory_order_seq_cst = 5
+};
+
+namespace {
+ class AtomicInfo {
+ CodeGenFunction &CGF;
+ QualType AtomicTy;
+ QualType ValueTy;
+ uint64_t AtomicSizeInBits;
+ uint64_t ValueSizeInBits;
+ CharUnits AtomicAlign;
+ CharUnits ValueAlign;
+ CharUnits LValueAlign;
+ TypeEvaluationKind EvaluationKind;
+ bool UseLibcall;
+ public:
+ AtomicInfo(CodeGenFunction &CGF, LValue &lvalue) : CGF(CGF) {
+ assert(lvalue.isSimple());
+
+ AtomicTy = lvalue.getType();
+ ValueTy = AtomicTy->castAs<AtomicType>()->getValueType();
+ EvaluationKind = CGF.getEvaluationKind(ValueTy);
+
+ ASTContext &C = CGF.getContext();
+
+ uint64_t valueAlignInBits;
+ llvm::tie(ValueSizeInBits, valueAlignInBits) = C.getTypeInfo(ValueTy);
+
+ uint64_t atomicAlignInBits;
+ llvm::tie(AtomicSizeInBits, atomicAlignInBits) = C.getTypeInfo(AtomicTy);
+
+ assert(ValueSizeInBits <= AtomicSizeInBits);
+ assert(valueAlignInBits <= atomicAlignInBits);
+
+ AtomicAlign = C.toCharUnitsFromBits(atomicAlignInBits);
+ ValueAlign = C.toCharUnitsFromBits(valueAlignInBits);
+ if (lvalue.getAlignment().isZero())
+ lvalue.setAlignment(AtomicAlign);
+
+ UseLibcall =
+ (AtomicSizeInBits > uint64_t(C.toBits(lvalue.getAlignment())) ||
+ AtomicSizeInBits > C.getTargetInfo().getMaxAtomicInlineWidth());
+ }
+
+ QualType getAtomicType() const { return AtomicTy; }
+ QualType getValueType() const { return ValueTy; }
+ CharUnits getAtomicAlignment() const { return AtomicAlign; }
+ CharUnits getValueAlignment() const { return ValueAlign; }
+ uint64_t getAtomicSizeInBits() const { return AtomicSizeInBits; }
+ uint64_t getValueSizeInBits() const { return AtomicSizeInBits; }
+ TypeEvaluationKind getEvaluationKind() const { return EvaluationKind; }
+ bool shouldUseLibcall() const { return UseLibcall; }
+
+ /// Is the atomic size larger than the underlying value type?
+ ///
+ /// Note that the absence of padding does not mean that atomic
+ /// objects are completely interchangeable with non-atomic
+ /// objects: we might have promoted the alignment of a type
+ /// without making it bigger.
+ bool hasPadding() const {
+ return (ValueSizeInBits != AtomicSizeInBits);
+ }
+
+ void emitMemSetZeroIfNecessary(LValue dest) const;
+
+ llvm::Value *getAtomicSizeValue() const {
+ CharUnits size = CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits);
+ return CGF.CGM.getSize(size);
+ }
+
+ /// Cast the given pointer to an integer pointer suitable for
+ /// atomic operations.
+ llvm::Value *emitCastToAtomicIntPointer(llvm::Value *addr) const;
+
+ /// Turn an atomic-layout object into an r-value.
+ RValue convertTempToRValue(llvm::Value *addr,
+ AggValueSlot resultSlot) const;
+
+ /// Copy an atomic r-value into atomic-layout memory.
+ void emitCopyIntoMemory(RValue rvalue, LValue lvalue) const;
+
+ /// Project an l-value down to the value field.
+ LValue projectValue(LValue lvalue) const {
+ llvm::Value *addr = lvalue.getAddress();
+ if (hasPadding())
+ addr = CGF.Builder.CreateStructGEP(addr, 0);
+
+ return LValue::MakeAddr(addr, getValueType(), lvalue.getAlignment(),
+ CGF.getContext(), lvalue.getTBAAInfo());
+ }
+
+ /// Materialize an atomic r-value in atomic-layout memory.
+ llvm::Value *materializeRValue(RValue rvalue) const;
+
+ private:
+ bool requiresMemSetZero(llvm::Type *type) const;
+ };
+}
+
+static RValue emitAtomicLibcall(CodeGenFunction &CGF,
+ StringRef fnName,
+ QualType resultType,
+ CallArgList &args) {
+ const CGFunctionInfo &fnInfo =
+ CGF.CGM.getTypes().arrangeFreeFunctionCall(resultType, args,
+ FunctionType::ExtInfo(), RequiredArgs::All);
+ llvm::FunctionType *fnTy = CGF.CGM.getTypes().GetFunctionType(fnInfo);
+ llvm::Constant *fn = CGF.CGM.CreateRuntimeFunction(fnTy, fnName);
+ return CGF.EmitCall(fnInfo, fn, ReturnValueSlot(), args);
+}
+
+/// Does a store of the given IR type modify the full expected width?
+static bool isFullSizeType(CodeGenModule &CGM, llvm::Type *type,
+ uint64_t expectedSize) {
+ return (CGM.getDataLayout().getTypeStoreSize(type) * 8 == expectedSize);
+}
+
+/// Does the atomic type require memsetting to zero before initialization?
+///
+/// The IR type is provided as a way of making certain queries faster.
+bool AtomicInfo::requiresMemSetZero(llvm::Type *type) const {
+ // If the atomic type has size padding, we definitely need a memset.
+ if (hasPadding()) return true;
+
+ // Otherwise, do some simple heuristics to try to avoid it:
+ switch (getEvaluationKind()) {
+ // For scalars and complexes, check whether the store size of the
+ // type uses the full size.
+ case TEK_Scalar:
+ return !isFullSizeType(CGF.CGM, type, AtomicSizeInBits);
+ case TEK_Complex:
+ return !isFullSizeType(CGF.CGM, type->getStructElementType(0),
+ AtomicSizeInBits / 2);
+
+ // Just be pessimistic about aggregates.
+ case TEK_Aggregate:
+ return true;
+ }
+ llvm_unreachable("bad evaluation kind");
+}
+
+void AtomicInfo::emitMemSetZeroIfNecessary(LValue dest) const {
+ llvm::Value *addr = dest.getAddress();
+ if (!requiresMemSetZero(addr->getType()->getPointerElementType()))
+ return;
+
+ CGF.Builder.CreateMemSet(addr, llvm::ConstantInt::get(CGF.Int8Ty, 0),
+ AtomicSizeInBits / 8,
+ dest.getAlignment().getQuantity());
+}
+
+static void
+EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest,
+ llvm::Value *Ptr, llvm::Value *Val1, llvm::Value *Val2,
+ uint64_t Size, unsigned Align, llvm::AtomicOrdering Order) {
+ llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
+ llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
+
+ switch (E->getOp()) {
+ case AtomicExpr::AO__c11_atomic_init:
+ llvm_unreachable("Already handled!");
+
+ case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__atomic_compare_exchange:
+ case AtomicExpr::AO__atomic_compare_exchange_n: {
+ // Note that cmpxchg only supports specifying one ordering and
+ // doesn't support weak cmpxchg, at least at the moment.
+ llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
+ LoadVal1->setAlignment(Align);
+ llvm::LoadInst *LoadVal2 = CGF.Builder.CreateLoad(Val2);
+ LoadVal2->setAlignment(Align);
+ llvm::AtomicCmpXchgInst *CXI =
+ CGF.Builder.CreateAtomicCmpXchg(Ptr, LoadVal1, LoadVal2, Order);
+ CXI->setVolatile(E->isVolatile());
+ llvm::StoreInst *StoreVal1 = CGF.Builder.CreateStore(CXI, Val1);
+ StoreVal1->setAlignment(Align);
+ llvm::Value *Cmp = CGF.Builder.CreateICmpEQ(CXI, LoadVal1);
+ CGF.EmitStoreOfScalar(Cmp, CGF.MakeAddrLValue(Dest, E->getType()));
+ return;
+ }
+
+ case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__atomic_load_n:
+ case AtomicExpr::AO__atomic_load: {
+ llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
+ Load->setAtomic(Order);
+ Load->setAlignment(Size);
+ Load->setVolatile(E->isVolatile());
+ llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Load, Dest);
+ StoreDest->setAlignment(Align);
+ return;
+ }
+
+ case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__atomic_store:
+ case AtomicExpr::AO__atomic_store_n: {
+ assert(!Dest && "Store does not return a value");
+ llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
+ LoadVal1->setAlignment(Align);
+ llvm::StoreInst *Store = CGF.Builder.CreateStore(LoadVal1, Ptr);
+ Store->setAtomic(Order);
+ Store->setAlignment(Size);
+ Store->setVolatile(E->isVolatile());
+ return;
+ }
+
+ case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__atomic_exchange_n:
+ case AtomicExpr::AO__atomic_exchange:
+ Op = llvm::AtomicRMWInst::Xchg;
+ break;
+
+ case AtomicExpr::AO__atomic_add_fetch:
+ PostOp = llvm::Instruction::Add;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__atomic_fetch_add:
+ Op = llvm::AtomicRMWInst::Add;
+ break;
+
+ case AtomicExpr::AO__atomic_sub_fetch:
+ PostOp = llvm::Instruction::Sub;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_fetch_sub:
+ Op = llvm::AtomicRMWInst::Sub;
+ break;
+
+ case AtomicExpr::AO__atomic_and_fetch:
+ PostOp = llvm::Instruction::And;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__atomic_fetch_and:
+ Op = llvm::AtomicRMWInst::And;
+ break;
+
+ case AtomicExpr::AO__atomic_or_fetch:
+ PostOp = llvm::Instruction::Or;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__atomic_fetch_or:
+ Op = llvm::AtomicRMWInst::Or;
+ break;
+
+ case AtomicExpr::AO__atomic_xor_fetch:
+ PostOp = llvm::Instruction::Xor;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_xor:
+ Op = llvm::AtomicRMWInst::Xor;
+ break;
+
+ case AtomicExpr::AO__atomic_nand_fetch:
+ PostOp = llvm::Instruction::And;
+ // Fall through.
+ case AtomicExpr::AO__atomic_fetch_nand:
+ Op = llvm::AtomicRMWInst::Nand;
+ break;
+ }
+
+ llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
+ LoadVal1->setAlignment(Align);
+ llvm::AtomicRMWInst *RMWI =
+ CGF.Builder.CreateAtomicRMW(Op, Ptr, LoadVal1, Order);
+ RMWI->setVolatile(E->isVolatile());
+
+ // For __atomic_*_fetch operations, perform the operation again to
+ // determine the value which was written.
+ llvm::Value *Result = RMWI;
+ if (PostOp)
+ Result = CGF.Builder.CreateBinOp(PostOp, RMWI, LoadVal1);
+ if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch)
+ Result = CGF.Builder.CreateNot(Result);
+ llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Result, Dest);
+ StoreDest->setAlignment(Align);
+}
+
+// This function emits any expression (scalar, complex, or aggregate)
+// into a temporary alloca.
+static llvm::Value *
+EmitValToTemp(CodeGenFunction &CGF, Expr *E) {
+ llvm::Value *DeclPtr = CGF.CreateMemTemp(E->getType(), ".atomictmp");
+ CGF.EmitAnyExprToMem(E, DeclPtr, E->getType().getQualifiers(),
+ /*Init*/ true);
+ return DeclPtr;
+}
+
+RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
+ QualType AtomicTy = E->getPtr()->getType()->getPointeeType();
+ QualType MemTy = AtomicTy;
+ if (const AtomicType *AT = AtomicTy->getAs<AtomicType>())
+ MemTy = AT->getValueType();
+ CharUnits sizeChars = getContext().getTypeSizeInChars(AtomicTy);
+ uint64_t Size = sizeChars.getQuantity();
+ CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy);
+ unsigned Align = alignChars.getQuantity();
+ unsigned MaxInlineWidthInBits =
+ getContext().getTargetInfo().getMaxAtomicInlineWidth();
+ bool UseLibcall = (Size != Align ||
+ getContext().toBits(sizeChars) > MaxInlineWidthInBits);
+
+ llvm::Value *Ptr, *Order, *OrderFail = 0, *Val1 = 0, *Val2 = 0;
+ Ptr = EmitScalarExpr(E->getPtr());
+
+ if (E->getOp() == AtomicExpr::AO__c11_atomic_init) {
+ assert(!Dest && "Init does not return a value");
+ LValue lvalue = LValue::MakeAddr(Ptr, AtomicTy, alignChars, getContext());
+ EmitAtomicInit(E->getVal1(), lvalue);
+ return RValue::get(0);
+ }
+
+ Order = EmitScalarExpr(E->getOrder());
+
+ switch (E->getOp()) {
+ case AtomicExpr::AO__c11_atomic_init:
+ llvm_unreachable("Already handled!");
+
+ case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__atomic_load_n:
+ break;
+
+ case AtomicExpr::AO__atomic_load:
+ Dest = EmitScalarExpr(E->getVal1());
+ break;
+
+ case AtomicExpr::AO__atomic_store:
+ Val1 = EmitScalarExpr(E->getVal1());
+ break;
+
+ case AtomicExpr::AO__atomic_exchange:
+ Val1 = EmitScalarExpr(E->getVal1());
+ Dest = EmitScalarExpr(E->getVal2());
+ break;
+
+ case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__atomic_compare_exchange_n:
+ case AtomicExpr::AO__atomic_compare_exchange:
+ Val1 = EmitScalarExpr(E->getVal1());
+ if (E->getOp() == AtomicExpr::AO__atomic_compare_exchange)
+ Val2 = EmitScalarExpr(E->getVal2());
+ else
+ Val2 = EmitValToTemp(*this, E->getVal2());
+ OrderFail = EmitScalarExpr(E->getOrderFail());
+ // Evaluate and discard the 'weak' argument.
+ if (E->getNumSubExprs() == 6)
+ EmitScalarExpr(E->getWeak());
+ break;
+
+ case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__c11_atomic_fetch_sub:
+ if (MemTy->isPointerType()) {
+ // For pointer arithmetic, we're required to do a bit of math:
+ // adding 1 to an int* is not the same as adding 1 to a uintptr_t.
+ // ... but only for the C11 builtins. The GNU builtins expect the
+ // user to multiply by sizeof(T).
+ QualType Val1Ty = E->getVal1()->getType();
+ llvm::Value *Val1Scalar = EmitScalarExpr(E->getVal1());
+ CharUnits PointeeIncAmt =
+ getContext().getTypeSizeInChars(MemTy->getPointeeType());
+ Val1Scalar = Builder.CreateMul(Val1Scalar, CGM.getSize(PointeeIncAmt));
+ Val1 = CreateMemTemp(Val1Ty, ".atomictmp");
+ EmitStoreOfScalar(Val1Scalar, MakeAddrLValue(Val1, Val1Ty));
+ break;
+ }
+ // Fall through.
+ case AtomicExpr::AO__atomic_fetch_add:
+ case AtomicExpr::AO__atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_add_fetch:
+ case AtomicExpr::AO__atomic_sub_fetch:
+ case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__atomic_store_n:
+ case AtomicExpr::AO__atomic_exchange_n:
+ case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_and:
+ case AtomicExpr::AO__atomic_fetch_or:
+ case AtomicExpr::AO__atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_nand:
+ case AtomicExpr::AO__atomic_and_fetch:
+ case AtomicExpr::AO__atomic_or_fetch:
+ case AtomicExpr::AO__atomic_xor_fetch:
+ case AtomicExpr::AO__atomic_nand_fetch:
+ Val1 = EmitValToTemp(*this, E->getVal1());
+ break;
+ }
+
+ if (!E->getType()->isVoidType() && !Dest)
+ Dest = CreateMemTemp(E->getType(), ".atomicdst");
+
+ // Use a library call. See: http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary .
+ if (UseLibcall) {
+
+ SmallVector<QualType, 5> Params;
+ CallArgList Args;
+ // Size is always the first parameter
+ Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
+ getContext().getSizeType());
+ // Atomic address is always the second parameter
+ Args.add(RValue::get(EmitCastToVoidPtr(Ptr)),
+ getContext().VoidPtrTy);
+
+ const char* LibCallName;
+ QualType RetTy = getContext().VoidTy;
+ switch (E->getOp()) {
+ // There is only one libcall for compare an exchange, because there is no
+ // optimisation benefit possible from a libcall version of a weak compare
+ // and exchange.
+ // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
+ // void *desired, int success, int failure)
+ case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__atomic_compare_exchange:
+ case AtomicExpr::AO__atomic_compare_exchange_n:
+ LibCallName = "__atomic_compare_exchange";
+ RetTy = getContext().BoolTy;
+ Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(EmitCastToVoidPtr(Val2)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(Order),
+ getContext().IntTy);
+ Order = OrderFail;
+ break;
+ // void __atomic_exchange(size_t size, void *mem, void *val, void *return,
+ // int order)
+ case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__atomic_exchange_n:
+ case AtomicExpr::AO__atomic_exchange:
+ LibCallName = "__atomic_exchange";
+ Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
+ getContext().VoidPtrTy);
+ break;
+ // void __atomic_store(size_t size, void *mem, void *val, int order)
+ case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__atomic_store:
+ case AtomicExpr::AO__atomic_store_n:
+ LibCallName = "__atomic_store";
+ Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
+ getContext().VoidPtrTy);
+ break;
+ // void __atomic_load(size_t size, void *mem, void *return, int order)
+ case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__atomic_load:
+ case AtomicExpr::AO__atomic_load_n:
+ LibCallName = "__atomic_load";
+ Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
+ getContext().VoidPtrTy);
+ break;
+#if 0
+ // These are only defined for 1-16 byte integers. It is not clear what
+ // their semantics would be on anything else...
+ case AtomicExpr::Add: LibCallName = "__atomic_fetch_add_generic"; break;
+ case AtomicExpr::Sub: LibCallName = "__atomic_fetch_sub_generic"; break;
+ case AtomicExpr::And: LibCallName = "__atomic_fetch_and_generic"; break;
+ case AtomicExpr::Or: LibCallName = "__atomic_fetch_or_generic"; break;
+ case AtomicExpr::Xor: LibCallName = "__atomic_fetch_xor_generic"; break;
+#endif
+ default: return EmitUnsupportedRValue(E, "atomic library call");
+ }
+ // order is always the last parameter
+ Args.add(RValue::get(Order),
+ getContext().IntTy);
+
+ const CGFunctionInfo &FuncInfo =
+ CGM.getTypes().arrangeFreeFunctionCall(RetTy, Args,
+ FunctionType::ExtInfo(), RequiredArgs::All);
+ llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo);
+ llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
+ RValue Res = EmitCall(FuncInfo, Func, ReturnValueSlot(), Args);
+ if (E->isCmpXChg())
+ return Res;
+ if (E->getType()->isVoidType())
+ return RValue::get(0);
+ return convertTempToRValue(Dest, E->getType());
+ }
+
+ bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store ||
+ E->getOp() == AtomicExpr::AO__atomic_store ||
+ E->getOp() == AtomicExpr::AO__atomic_store_n;
+ bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load ||
+ E->getOp() == AtomicExpr::AO__atomic_load ||
+ E->getOp() == AtomicExpr::AO__atomic_load_n;
+
+ llvm::Type *IPtrTy =
+ llvm::IntegerType::get(getLLVMContext(), Size * 8)->getPointerTo();
+ llvm::Value *OrigDest = Dest;
+ Ptr = Builder.CreateBitCast(Ptr, IPtrTy);
+ if (Val1) Val1 = Builder.CreateBitCast(Val1, IPtrTy);
+ if (Val2) Val2 = Builder.CreateBitCast(Val2, IPtrTy);
+ if (Dest && !E->isCmpXChg()) Dest = Builder.CreateBitCast(Dest, IPtrTy);
+
+ if (isa<llvm::ConstantInt>(Order)) {
+ int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
+ switch (ord) {
+ case AO_ABI_memory_order_relaxed:
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Monotonic);
+ break;
+ case AO_ABI_memory_order_consume:
+ case AO_ABI_memory_order_acquire:
+ if (IsStore)
+ break; // Avoid crashing on code with undefined behavior
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Acquire);
+ break;
+ case AO_ABI_memory_order_release:
+ if (IsLoad)
+ break; // Avoid crashing on code with undefined behavior
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Release);
+ break;
+ case AO_ABI_memory_order_acq_rel:
+ if (IsLoad || IsStore)
+ break; // Avoid crashing on code with undefined behavior
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::AcquireRelease);
+ break;
+ case AO_ABI_memory_order_seq_cst:
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::SequentiallyConsistent);
+ break;
+ default: // invalid order
+ // We should not ever get here normally, but it's hard to
+ // enforce that in general.
+ break;
+ }
+ if (E->getType()->isVoidType())
+ return RValue::get(0);
+ return convertTempToRValue(OrigDest, E->getType());
+ }
+
+ // Long case, when Order isn't obviously constant.
+
+ // Create all the relevant BB's
+ llvm::BasicBlock *MonotonicBB = 0, *AcquireBB = 0, *ReleaseBB = 0,
+ *AcqRelBB = 0, *SeqCstBB = 0;
+ MonotonicBB = createBasicBlock("monotonic", CurFn);
+ if (!IsStore)
+ AcquireBB = createBasicBlock("acquire", CurFn);
+ if (!IsLoad)
+ ReleaseBB = createBasicBlock("release", CurFn);
+ if (!IsLoad && !IsStore)
+ AcqRelBB = createBasicBlock("acqrel", CurFn);
+ SeqCstBB = createBasicBlock("seqcst", CurFn);
+ llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
+
+ // Create the switch for the split
+ // MonotonicBB is arbitrarily chosen as the default case; in practice, this
+ // doesn't matter unless someone is crazy enough to use something that
+ // doesn't fold to a constant for the ordering.
+ Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
+ llvm::SwitchInst *SI = Builder.CreateSwitch(Order, MonotonicBB);
+
+ // Emit all the different atomics
+ Builder.SetInsertPoint(MonotonicBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Monotonic);
+ Builder.CreateBr(ContBB);
+ if (!IsStore) {
+ Builder.SetInsertPoint(AcquireBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Acquire);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(1), AcquireBB);
+ SI->addCase(Builder.getInt32(2), AcquireBB);
+ }
+ if (!IsLoad) {
+ Builder.SetInsertPoint(ReleaseBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Release);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(3), ReleaseBB);
+ }
+ if (!IsLoad && !IsStore) {
+ Builder.SetInsertPoint(AcqRelBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::AcquireRelease);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(4), AcqRelBB);
+ }
+ Builder.SetInsertPoint(SeqCstBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::SequentiallyConsistent);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(5), SeqCstBB);
+
+ // Cleanup and return
+ Builder.SetInsertPoint(ContBB);
+ if (E->getType()->isVoidType())
+ return RValue::get(0);
+ return convertTempToRValue(OrigDest, E->getType());
+}
+
+llvm::Value *AtomicInfo::emitCastToAtomicIntPointer(llvm::Value *addr) const {
+ unsigned addrspace =
+ cast<llvm::PointerType>(addr->getType())->getAddressSpace();
+ llvm::IntegerType *ty =
+ llvm::IntegerType::get(CGF.getLLVMContext(), AtomicSizeInBits);
+ return CGF.Builder.CreateBitCast(addr, ty->getPointerTo(addrspace));
+}
+
+RValue AtomicInfo::convertTempToRValue(llvm::Value *addr,
+ AggValueSlot resultSlot) const {
+ if (EvaluationKind == TEK_Aggregate) {
+ // Nothing to do if the result is ignored.
+ if (resultSlot.isIgnored()) return resultSlot.asRValue();
+
+ assert(resultSlot.getAddr() == addr || hasPadding());
+
+ // In these cases, we should have emitted directly into the result slot.
+ if (!hasPadding() || resultSlot.isValueOfAtomic())
+ return resultSlot.asRValue();
+
+ // Otherwise, fall into the common path.
+ }
+
+ // Drill into the padding structure if we have one.
+ if (hasPadding())
+ addr = CGF.Builder.CreateStructGEP(addr, 0);
+
+ // If we're emitting to an aggregate, copy into the result slot.
+ if (EvaluationKind == TEK_Aggregate) {
+ CGF.EmitAggregateCopy(resultSlot.getAddr(), addr, getValueType(),
+ resultSlot.isVolatile());
+ return resultSlot.asRValue();
+ }
+
+ // Otherwise, just convert the temporary to an r-value using the
+ // normal conversion routine.
+ return CGF.convertTempToRValue(addr, getValueType());
+}
+
+/// Emit a load from an l-value of atomic type. Note that the r-value
+/// we produce is an r-value of the atomic *value* type.
+RValue CodeGenFunction::EmitAtomicLoad(LValue src, AggValueSlot resultSlot) {
+ AtomicInfo atomics(*this, src);
+
+ // Check whether we should use a library call.
+ if (atomics.shouldUseLibcall()) {
+ llvm::Value *tempAddr;
+ if (resultSlot.isValueOfAtomic()) {
+ assert(atomics.getEvaluationKind() == TEK_Aggregate);
+ tempAddr = resultSlot.getPaddedAtomicAddr();
+ } else if (!resultSlot.isIgnored() && !atomics.hasPadding()) {
+ assert(atomics.getEvaluationKind() == TEK_Aggregate);
+ tempAddr = resultSlot.getAddr();
+ } else {
+ tempAddr = CreateMemTemp(atomics.getAtomicType(), "atomic-load-temp");
+ }
+
+ // void __atomic_load(size_t size, void *mem, void *return, int order);
+ CallArgList args;
+ args.add(RValue::get(atomics.getAtomicSizeValue()),
+ getContext().getSizeType());
+ args.add(RValue::get(EmitCastToVoidPtr(src.getAddress())),
+ getContext().VoidPtrTy);
+ args.add(RValue::get(EmitCastToVoidPtr(tempAddr)),
+ getContext().VoidPtrTy);
+ args.add(RValue::get(llvm::ConstantInt::get(IntTy,
+ AO_ABI_memory_order_seq_cst)),
+ getContext().IntTy);
+ emitAtomicLibcall(*this, "__atomic_load", getContext().VoidTy, args);
+
+ // Produce the r-value.
+ return atomics.convertTempToRValue(tempAddr, resultSlot);
+ }
+
+ // Okay, we're doing this natively.
+ llvm::Value *addr = atomics.emitCastToAtomicIntPointer(src.getAddress());
+ llvm::LoadInst *load = Builder.CreateLoad(addr, "atomic-load");
+ load->setAtomic(llvm::SequentiallyConsistent);
+
+ // Other decoration.
+ load->setAlignment(src.getAlignment().getQuantity());
+ if (src.isVolatileQualified())
+ load->setVolatile(true);
+ if (src.getTBAAInfo())
+ CGM.DecorateInstruction(load, src.getTBAAInfo());
+
+ // Okay, turn that back into the original value type.
+ QualType valueType = atomics.getValueType();
+ llvm::Value *result = load;
+
+ // If we're ignoring an aggregate return, don't do anything.
+ if (atomics.getEvaluationKind() == TEK_Aggregate && resultSlot.isIgnored())
+ return RValue::getAggregate(0, false);
+
+ // The easiest way to do this this is to go through memory, but we
+ // try not to in some easy cases.
+ if (atomics.getEvaluationKind() == TEK_Scalar && !atomics.hasPadding()) {
+ llvm::Type *resultTy = CGM.getTypes().ConvertTypeForMem(valueType);
+ if (isa<llvm::IntegerType>(resultTy)) {
+ assert(result->getType() == resultTy);
+ result = EmitFromMemory(result, valueType);
+ } else if (isa<llvm::PointerType>(resultTy)) {
+ result = Builder.CreateIntToPtr(result, resultTy);
+ } else {
+ result = Builder.CreateBitCast(result, resultTy);
+ }
+ return RValue::get(result);
+ }
+
+ // Create a temporary. This needs to be big enough to hold the
+ // atomic integer.
+ llvm::Value *temp;
+ bool tempIsVolatile = false;
+ CharUnits tempAlignment;
+ if (atomics.getEvaluationKind() == TEK_Aggregate &&
+ (!atomics.hasPadding() || resultSlot.isValueOfAtomic())) {
+ assert(!resultSlot.isIgnored());
+ if (resultSlot.isValueOfAtomic()) {
+ temp = resultSlot.getPaddedAtomicAddr();
+ tempAlignment = atomics.getAtomicAlignment();
+ } else {
+ temp = resultSlot.getAddr();
+ tempAlignment = atomics.getValueAlignment();
+ }
+ tempIsVolatile = resultSlot.isVolatile();
+ } else {
+ temp = CreateMemTemp(atomics.getAtomicType(), "atomic-load-temp");
+ tempAlignment = atomics.getAtomicAlignment();
+ }
+
+ // Slam the integer into the temporary.
+ llvm::Value *castTemp = atomics.emitCastToAtomicIntPointer(temp);
+ Builder.CreateAlignedStore(result, castTemp, tempAlignment.getQuantity())
+ ->setVolatile(tempIsVolatile);
+
+ return atomics.convertTempToRValue(temp, resultSlot);
+}
+
+
+
+/// Copy an r-value into memory as part of storing to an atomic type.
+/// This needs to create a bit-pattern suitable for atomic operations.
+void AtomicInfo::emitCopyIntoMemory(RValue rvalue, LValue dest) const {
+ // If we have an r-value, the rvalue should be of the atomic type,
+ // which means that the caller is responsible for having zeroed
+ // any padding. Just do an aggregate copy of that type.
+ if (rvalue.isAggregate()) {
+ CGF.EmitAggregateCopy(dest.getAddress(),
+ rvalue.getAggregateAddr(),
+ getAtomicType(),
+ (rvalue.isVolatileQualified()
+ || dest.isVolatileQualified()),
+ dest.getAlignment());
+ return;
+ }
+
+ // Okay, otherwise we're copying stuff.
+
+ // Zero out the buffer if necessary.
+ emitMemSetZeroIfNecessary(dest);
+
+ // Drill past the padding if present.
+ dest = projectValue(dest);
+
+ // Okay, store the rvalue in.
+ if (rvalue.isScalar()) {
+ CGF.EmitStoreOfScalar(rvalue.getScalarVal(), dest, /*init*/ true);
+ } else {
+ CGF.EmitStoreOfComplex(rvalue.getComplexVal(), dest, /*init*/ true);
+ }
+}
+
+
+/// Materialize an r-value into memory for the purposes of storing it
+/// to an atomic type.
+llvm::Value *AtomicInfo::materializeRValue(RValue rvalue) const {
+ // Aggregate r-values are already in memory, and EmitAtomicStore
+ // requires them to be values of the atomic type.
+ if (rvalue.isAggregate())
+ return rvalue.getAggregateAddr();
+
+ // Otherwise, make a temporary and materialize into it.
+ llvm::Value *temp = CGF.CreateMemTemp(getAtomicType(), "atomic-store-temp");
+ LValue tempLV = CGF.MakeAddrLValue(temp, getAtomicType(), getAtomicAlignment());
+ emitCopyIntoMemory(rvalue, tempLV);
+ return temp;
+}
+
+/// Emit a store to an l-value of atomic type.
+///
+/// Note that the r-value is expected to be an r-value *of the atomic
+/// type*; this means that for aggregate r-values, it should include
+/// storage for any padding that was necessary.
+void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest,
+ bool isInit) {
+ // If this is an aggregate r-value, it should agree in type except
+ // maybe for address-space qualification.
+ assert(!rvalue.isAggregate() ||
+ rvalue.getAggregateAddr()->getType()->getPointerElementType()
+ == dest.getAddress()->getType()->getPointerElementType());
+
+ AtomicInfo atomics(*this, dest);
+
+ // If this is an initialization, just put the value there normally.
+ if (isInit) {
+ atomics.emitCopyIntoMemory(rvalue, dest);
+ return;
+ }
+
+ // Check whether we should use a library call.
+ if (atomics.shouldUseLibcall()) {
+ // Produce a source address.
+ llvm::Value *srcAddr = atomics.materializeRValue(rvalue);
+
+ // void __atomic_store(size_t size, void *mem, void *val, int order)
+ CallArgList args;
+ args.add(RValue::get(atomics.getAtomicSizeValue()),
+ getContext().getSizeType());
+ args.add(RValue::get(EmitCastToVoidPtr(dest.getAddress())),
+ getContext().VoidPtrTy);
+ args.add(RValue::get(EmitCastToVoidPtr(srcAddr)),
+ getContext().VoidPtrTy);
+ args.add(RValue::get(llvm::ConstantInt::get(IntTy,
+ AO_ABI_memory_order_seq_cst)),
+ getContext().IntTy);
+ emitAtomicLibcall(*this, "__atomic_store", getContext().VoidTy, args);
+ return;
+ }
+
+ // Okay, we're doing this natively.
+ llvm::Value *intValue;
+
+ // If we've got a scalar value of the right size, try to avoid going
+ // through memory.
+ if (rvalue.isScalar() && !atomics.hasPadding()) {
+ llvm::Value *value = rvalue.getScalarVal();
+ if (isa<llvm::IntegerType>(value->getType())) {
+ intValue = value;
+ } else {
+ llvm::IntegerType *inputIntTy =
+ llvm::IntegerType::get(getLLVMContext(), atomics.getValueSizeInBits());
+ if (isa<llvm::PointerType>(value->getType())) {
+ intValue = Builder.CreatePtrToInt(value, inputIntTy);
+ } else {
+ intValue = Builder.CreateBitCast(value, inputIntTy);
+ }
+ }
+
+ // Otherwise, we need to go through memory.
+ } else {
+ // Put the r-value in memory.
+ llvm::Value *addr = atomics.materializeRValue(rvalue);
+
+ // Cast the temporary to the atomic int type and pull a value out.
+ addr = atomics.emitCastToAtomicIntPointer(addr);
+ intValue = Builder.CreateAlignedLoad(addr,
+ atomics.getAtomicAlignment().getQuantity());
+ }
+
+ // Do the atomic store.
+ llvm::Value *addr = atomics.emitCastToAtomicIntPointer(dest.getAddress());
+ llvm::StoreInst *store = Builder.CreateStore(intValue, addr);
+
+ // Initializations don't need to be atomic.
+ if (!isInit) store->setAtomic(llvm::SequentiallyConsistent);
+
+ // Other decoration.
+ store->setAlignment(dest.getAlignment().getQuantity());
+ if (dest.isVolatileQualified())
+ store->setVolatile(true);
+ if (dest.getTBAAInfo())
+ CGM.DecorateInstruction(store, dest.getTBAAInfo());
+}
+
+void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) {
+ AtomicInfo atomics(*this, dest);
+
+ switch (atomics.getEvaluationKind()) {
+ case TEK_Scalar: {
+ llvm::Value *value = EmitScalarExpr(init);
+ atomics.emitCopyIntoMemory(RValue::get(value), dest);
+ return;
+ }
+
+ case TEK_Complex: {
+ ComplexPairTy value = EmitComplexExpr(init);
+ atomics.emitCopyIntoMemory(RValue::getComplex(value), dest);
+ return;
+ }
+
+ case TEK_Aggregate: {
+ // Memset the buffer first if there's any possibility of
+ // uninitialized internal bits.
+ atomics.emitMemSetZeroIfNecessary(dest);
+
+ // HACK: whether the initializer actually has an atomic type
+ // doesn't really seem reliable right now.
+ if (!init->getType()->isAtomicType()) {
+ dest = atomics.projectValue(dest);
+ }
+
+ // Evaluate the expression directly into the destination.
+ AggValueSlot slot = AggValueSlot::forLValue(dest,
+ AggValueSlot::IsNotDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
+ EmitAggExpr(init, slot);
+ return;
+ }
+ }
+ llvm_unreachable("bad evaluation kind");
+}
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 2d51a154ad..b9f466117c 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -20,6 +20,7 @@
#include "llvm/ADT/SmallSet.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Module.h"
+#include "llvm/Support/CallSite.h"
#include <algorithm>
#include <cstdio>
@@ -776,8 +777,16 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
// special; we'll simply emit it directly.
src = 0;
} else {
- // This is a [[type]]*.
- src = LocalDeclMap[variable];
+ // Just look it up in the locals map, which will give us back a
+ // [[type]]*. If that doesn't work, do the more elaborate DRE
+ // emission.
+ src = LocalDeclMap.lookup(variable);
+ if (!src) {
+ DeclRefExpr declRef(const_cast<VarDecl*>(variable),
+ /*refersToEnclosing*/ ci->isNested(), type,
+ VK_LValue, SourceLocation());
+ src = EmitDeclRefLValue(&declRef).getAddress();
+ }
}
// For byrefs, we just write the pointer to the byref struct into
@@ -1398,8 +1407,24 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
} else {
srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy);
llvm::Value *dstAddr = Builder.CreateBitCast(dstField, VoidPtrTy);
- Builder.CreateCall3(CGM.getBlockObjectAssign(), dstAddr, srcValue,
- llvm::ConstantInt::get(Int32Ty, flags.getBitMask()));
+ llvm::Value *args[] = {
+ dstAddr, srcValue, llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
+ };
+
+ bool copyCanThrow = false;
+ if (ci->isByRef() && variable->getType()->getAsCXXRecordDecl()) {
+ const Expr *copyExpr =
+ CGM.getContext().getBlockVarCopyInits(variable);
+ if (copyExpr) {
+ copyCanThrow = true; // FIXME: reuse the noexcept logic
+ }
+ }
+
+ if (copyCanThrow) {
+ EmitRuntimeCallOrInvoke(CGM.getBlockObjectAssign(), args);
+ } else {
+ EmitNounwindRuntimeCall(CGM.getBlockObjectAssign(), args);
+ }
}
}
}
@@ -1562,7 +1587,9 @@ public:
llvm::Value *flagsVal = llvm::ConstantInt::get(CGF.Int32Ty, flags);
llvm::Value *fn = CGF.CGM.getBlockObjectAssign();
- CGF.Builder.CreateCall3(fn, destField, srcValue, flagsVal);
+
+ llvm::Value *args[] = { destField, srcValue, flagsVal };
+ CGF.EmitNounwindRuntimeCall(fn, args);
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
@@ -2174,10 +2201,11 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
void CodeGenFunction::BuildBlockRelease(llvm::Value *V, BlockFieldFlags flags) {
llvm::Value *F = CGM.getBlockObjectDispose();
- llvm::Value *N;
- V = Builder.CreateBitCast(V, Int8PtrTy);
- N = llvm::ConstantInt::get(Int32Ty, flags.getBitMask());
- Builder.CreateCall2(F, V, N);
+ llvm::Value *args[] = {
+ Builder.CreateBitCast(V, Int8PtrTy),
+ llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
+ };
+ EmitNounwindRuntimeCall(F, args); // FIXME: throwing destructors?
}
namespace {
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 0d5be26a5e..e9c1431d30 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -160,7 +160,7 @@ static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) {
false);
llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(FT, FnName);
- return CGF.Builder.CreateCall(Fn, V, "abs");
+ return CGF.EmitNounwindRuntimeCall(Fn, V, "abs");
}
static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *Fn,
@@ -1500,9 +1500,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
ErrorUnsupported(E, "builtin function");
// Unknown builtin, for now just dump it out and return undef.
- if (hasAggregateLLVMType(E->getType()))
- return RValue::getAggregate(CreateMemTemp(E->getType()));
- return RValue::get(llvm::UndefValue::get(ConvertType(E->getType())));
+ return GetUndefRValue(E->getType());
}
Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
@@ -1639,7 +1637,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType());
llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
StringRef Name = FD->getName();
- return Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name), Ops);
+ return EmitNounwindRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name), Ops);
}
if (BuiltinID == ARM::BI__builtin_arm_ldrexd) {
diff --git a/lib/CodeGen/CGCUDANV.cpp b/lib/CodeGen/CGCUDANV.cpp
index ed70c7cfb2..0ebf1aaa44 100644
--- a/lib/CodeGen/CGCUDANV.cpp
+++ b/lib/CodeGen/CGCUDANV.cpp
@@ -104,7 +104,7 @@ void CGNVCUDARuntime::EmitDeviceStubBody(CodeGenFunction &CGF,
Args[2] = CGF.Builder.CreateIntCast(
llvm::ConstantExpr::getOffsetOf(ArgStackTy, I),
SizeTy, false);
- llvm::CallSite CS = CGF.EmitCallOrInvoke(cudaSetupArgFn, Args);
+ llvm::CallSite CS = CGF.EmitRuntimeCallOrInvoke(cudaSetupArgFn, Args);
llvm::Constant *Zero = llvm::ConstantInt::get(IntTy, 0);
llvm::Value *CSZero = CGF.Builder.CreateICmpEQ(CS.getInstruction(), Zero);
CGF.Builder.CreateCondBr(CSZero, NextBlock, EndBlock);
@@ -114,7 +114,7 @@ void CGNVCUDARuntime::EmitDeviceStubBody(CodeGenFunction &CGF,
// Emit the call to cudaLaunch
llvm::Constant *cudaLaunchFn = getLaunchFn();
llvm::Value *Arg = CGF.Builder.CreatePointerCast(CGF.CurFn, CharPtrTy);
- CGF.EmitCallOrInvoke(cudaLaunchFn, Arg);
+ CGF.EmitRuntimeCallOrInvoke(cudaLaunchFn, Arg);
CGF.EmitBranch(EndBlock);
CGF.EmitBlock(EndBlock);
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 3bcf7d0f50..fa5ce7fdca 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h"
@@ -992,7 +993,10 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>();
if (FPT && FPT->isNothrow(getContext()))
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
- if (Fn->isNoReturn())
+ // Don't use [[noreturn]] or _Noreturn for a call to a virtual function.
+ // These attributes are not inherited by overloads.
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn);
+ if (Fn->isNoReturn() && !(AttrOnCallSite && MD && MD->isVirtual()))
FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
}
@@ -1021,6 +1025,65 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
// Attributes that should go on the call site only.
if (!CodeGenOpts.SimplifyLibCalls)
FuncAttrs.addAttribute(llvm::Attribute::NoBuiltin);
+ } else {
+ // Attributes that should go on the function, but not the call site.
+ if (!CodeGenOpts.CodeModel.empty())
+ FuncAttrs.addAttribute("code-model", CodeGenOpts.CodeModel);
+ if (!CodeGenOpts.RelocationModel.empty())
+ FuncAttrs.addAttribute("relocation-model", CodeGenOpts.RelocationModel);
+
+ if (CodeGenOpts.FloatABI == "soft" || CodeGenOpts.FloatABI == "softfp")
+ FuncAttrs.addAttribute("float-abi", "soft");
+ else if (CodeGenOpts.FloatABI == "hard")
+ FuncAttrs.addAttribute("float-abi", "hard");
+
+ if (!CodeGenOpts.DisableFPElim) {
+ /* ignore */ ;
+ } else if (CodeGenOpts.OmitLeafFramePointer) {
+ FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf");
+ } else {
+ FuncAttrs.addAttribute("no-frame-pointer-elim");
+ FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf");
+ }
+
+ switch (CodeGenOpts.getFPContractMode()) {
+ case CodeGenOptions::FPC_Off:
+ FuncAttrs.addAttribute("fp-contract-model", "strict");
+ break;
+ case CodeGenOptions::FPC_On:
+ FuncAttrs.addAttribute("fp-contract-model", "standard");
+ break;
+ case CodeGenOptions::FPC_Fast:
+ FuncAttrs.addAttribute("fp-contract-model", "fast");
+ break;
+ }
+
+ if (CodeGenOpts.LessPreciseFPMAD)
+ FuncAttrs.addAttribute("less-precise-fpmad");
+ if (CodeGenOpts.NoInfsFPMath)
+ FuncAttrs.addAttribute("no-infs-fp-math");
+ if (CodeGenOpts.NoNaNsFPMath)
+ FuncAttrs.addAttribute("no-nans-fp-math");
+ if (CodeGenOpts.NoZeroInitializedInBSS)
+ FuncAttrs.addAttribute("no-zero-init-in-bss");
+ if (CodeGenOpts.UnsafeFPMath)
+ FuncAttrs.addAttribute("unsafe-fp-math");
+ if (CodeGenOpts.SoftFloat)
+ FuncAttrs.addAttribute("use-soft-float");
+ if (CodeGenOpts.StackAlignment)
+ FuncAttrs.addAttribute("stack-align-override",
+ llvm::utostr(CodeGenOpts.StackAlignment));
+ if (CodeGenOpts.StackRealignment)
+ FuncAttrs.addAttribute("realign-stack");
+ if (CodeGenOpts.DisableTailCalls)
+ FuncAttrs.addAttribute("disable-tail-calls");
+ if (!CodeGenOpts.TrapFuncName.empty())
+ FuncAttrs.addAttribute("trap-func-name", CodeGenOpts.TrapFuncName);
+ if (LangOpts.PIELevel != 0)
+ FuncAttrs.addAttribute("pie");
+ if (CodeGenOpts.SSPBufferSize)
+ FuncAttrs.addAttribute("ssp-buffers-size",
+ llvm::utostr(CodeGenOpts.SSPBufferSize));
}
QualType RetTy = FI.getReturnType();
@@ -1215,7 +1278,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
case ABIArgInfo::Indirect: {
llvm::Value *V = AI;
- if (hasAggregateLLVMType(Ty)) {
+ if (!hasScalarEvaluationKind(Ty)) {
// Aggregates and complex variables are accessed by reference. All we
// need to do is realign the value, if requested
if (ArgI.getIndirectRealign()) {
@@ -1348,7 +1411,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Match to what EmitParmDecl is expecting for this type.
- if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ if (CodeGenFunction::hasScalarEvaluationKind(Ty)) {
V = EmitLoadOfScalar(V, false, AlignmentToUse, Ty);
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
@@ -1377,7 +1440,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
case ABIArgInfo::Ignore:
// Initialize the local variable appropriately.
- if (hasAggregateLLVMType(Ty))
+ if (!hasScalarEvaluationKind(Ty))
EmitParmDecl(*Arg, CreateMemTemp(Ty), ArgNo);
else
EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType())),
@@ -1601,15 +1664,23 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
switch (RetAI.getKind()) {
case ABIArgInfo::Indirect: {
- unsigned Alignment = getContext().getTypeAlignInChars(RetTy).getQuantity();
- if (RetTy->isAnyComplexType()) {
- ComplexPairTy RT = LoadComplexFromAddr(ReturnValue, false);
- StoreComplexToAddr(RT, CurFn->arg_begin(), false);
- } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ switch (getEvaluationKind(RetTy)) {
+ case TEK_Complex: {
+ ComplexPairTy RT =
+ EmitLoadOfComplex(MakeNaturalAlignAddrLValue(ReturnValue, RetTy));
+ EmitStoreOfComplex(RT,
+ MakeNaturalAlignAddrLValue(CurFn->arg_begin(), RetTy),
+ /*isInit*/ true);
+ break;
+ }
+ case TEK_Aggregate:
// Do nothing; aggregrates get evaluated directly into the destination.
- } else {
- EmitStoreOfScalar(Builder.CreateLoad(ReturnValue), CurFn->arg_begin(),
- false, Alignment, RetTy);
+ break;
+ case TEK_Scalar:
+ EmitStoreOfScalar(Builder.CreateLoad(ReturnValue),
+ MakeNaturalAlignAddrLValue(CurFn->arg_begin(), RetTy),
+ /*isInit*/ true);
+ break;
}
break;
}
@@ -1686,10 +1757,10 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
// For the most part, we just need to load the alloca, except:
// 1) aggregate r-values are actually pointers to temporaries, and
- // 2) references to aggregates are pointers directly to the aggregate.
- // I don't know why references to non-aggregates are different here.
+ // 2) references to non-scalars are pointers directly to the aggregate.
+ // I don't know why references to scalars are different here.
if (const ReferenceType *ref = type->getAs<ReferenceType>()) {
- if (hasAggregateLLVMType(ref->getPointeeType()))
+ if (!hasScalarEvaluationKind(ref->getPointeeType()))
return args.add(RValue::getAggregate(local), type);
// Locals which are references to scalars are represented
@@ -1697,17 +1768,7 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
return args.add(RValue::get(Builder.CreateLoad(local)), type);
}
- if (type->isAnyComplexType()) {
- ComplexPairTy complex = LoadComplexFromAddr(local, /*volatile*/ false);
- return args.add(RValue::getComplex(complex), type);
- }
-
- if (hasAggregateLLVMType(type))
- return args.add(RValue::getAggregate(local), type);
-
- unsigned alignment = getContext().getDeclAlign(param).getQuantity();
- llvm::Value *value = EmitLoadOfScalar(local, false, alignment, type);
- return args.add(RValue::get(value), type);
+ args.add(convertTempToRValue(local, type), type);
}
static bool isProvablyNull(llvm::Value *addr) {
@@ -1872,7 +1933,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
type);
}
- if (hasAggregateLLVMType(type) && !E->getType()->isAnyComplexType() &&
+ if (hasAggregateEvaluationKind(type) &&
isa<ImplicitCastExpr>(E) &&
cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue) {
LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr());
@@ -1894,6 +1955,85 @@ CodeGenFunction::AddObjCARCExceptionMetadata(llvm::Instruction *Inst) {
CGM.getNoObjCARCExceptionsMetadata());
}
+/// Emits a call to the given no-arguments nounwind runtime function.
+llvm::CallInst *
+CodeGenFunction::EmitNounwindRuntimeCall(llvm::Value *callee,
+ const llvm::Twine &name) {
+ return EmitNounwindRuntimeCall(callee, ArrayRef<llvm::Value*>(), name);
+}
+
+/// Emits a call to the given nounwind runtime function.
+llvm::CallInst *
+CodeGenFunction::EmitNounwindRuntimeCall(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const llvm::Twine &name) {
+ llvm::CallInst *call = EmitRuntimeCall(callee, args, name);
+ call->setDoesNotThrow();
+ return call;
+}
+
+/// Emits a simple call (never an invoke) to the given no-arguments
+/// runtime function.
+llvm::CallInst *
+CodeGenFunction::EmitRuntimeCall(llvm::Value *callee,
+ const llvm::Twine &name) {
+ return EmitRuntimeCall(callee, ArrayRef<llvm::Value*>(), name);
+}
+
+/// Emits a simple call (never an invoke) to the given runtime
+/// function.
+llvm::CallInst *
+CodeGenFunction::EmitRuntimeCall(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const llvm::Twine &name) {
+ llvm::CallInst *call = Builder.CreateCall(callee, args, name);
+ call->setCallingConv(getRuntimeCC());
+ return call;
+}
+
+/// Emits a call or invoke to the given noreturn runtime function.
+void CodeGenFunction::EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args) {
+ if (getInvokeDest()) {
+ llvm::InvokeInst *invoke =
+ Builder.CreateInvoke(callee,
+ getUnreachableBlock(),
+ getInvokeDest(),
+ args);
+ invoke->setDoesNotReturn();
+ invoke->setCallingConv(getRuntimeCC());
+ } else {
+ llvm::CallInst *call = Builder.CreateCall(callee, args);
+ call->setDoesNotReturn();
+ call->setCallingConv(getRuntimeCC());
+ Builder.CreateUnreachable();
+ }
+}
+
+/// Emits a call or invoke instruction to the given nullary runtime
+/// function.
+llvm::CallSite
+CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::Value *callee,
+ const Twine &name) {
+ return EmitRuntimeCallOrInvoke(callee, ArrayRef<llvm::Value*>(), name);
+}
+
+/// Emits a call or invoke instruction to the given runtime function.
+llvm::CallSite
+CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const Twine &name) {
+ llvm::CallSite callSite = EmitCallOrInvoke(callee, args, name);
+ callSite.setCallingConv(getRuntimeCC());
+ return callSite;
+}
+
+llvm::CallSite
+CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
+ const Twine &Name) {
+ return EmitCallOrInvoke(Callee, ArrayRef<llvm::Value *>(), Name);
+}
+
/// Emits a call or invoke instruction to the given function, depending
/// on the current state of the EH stack.
llvm::CallSite
@@ -1919,12 +2059,6 @@ CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
return Inst;
}
-llvm::CallSite
-CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
- const Twine &Name) {
- return EmitCallOrInvoke(Callee, ArrayRef<llvm::Value *>(), Name);
-}
-
static void checkArgMatches(llvm::Value *Elt, unsigned &ArgNo,
llvm::FunctionType *FTy) {
if (ArgNo < FTy->getNumParams())
@@ -1943,15 +2077,7 @@ void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
llvm::Value *Addr = RV.getAggregateAddr();
for (unsigned Elt = 0; Elt < NumElts; ++Elt) {
llvm::Value *EltAddr = Builder.CreateConstGEP2_32(Addr, 0, Elt);
- LValue LV = MakeAddrLValue(EltAddr, EltTy);
- RValue EltRV;
- if (EltTy->isAnyComplexType())
- // FIXME: Volatile?
- EltRV = RValue::getComplex(LoadComplexFromAddr(LV.getAddress(), false));
- else if (CodeGenFunction::hasAggregateLLVMType(EltTy))
- EltRV = LV.asAggregateRValue();
- else
- EltRV = EmitLoadOfLValue(LV);
+ RValue EltRV = convertTempToRValue(EltAddr, EltTy);
ExpandTypeToArgs(EltTy, EltRV, Args, IRFuncTy);
}
} else if (const RecordType *RT = Ty->getAs<RecordType>()) {
@@ -2044,8 +2170,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
const ABIArgInfo &ArgInfo = info_it->info;
RValue RV = I->RV;
- unsigned TypeAlign =
- getContext().getTypeAlignInChars(I->Ty).getQuantity();
+ CharUnits TypeAlign = getContext().getTypeAlignInChars(I->Ty);
// Insert a padding argument to ensure proper alignment.
if (llvm::Type *PaddingType = ArgInfo.getPaddingType()) {
@@ -2061,28 +2186,36 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (ArgInfo.getIndirectAlign() > AI->getAlignment())
AI->setAlignment(ArgInfo.getIndirectAlign());
Args.push_back(AI);
+
+ LValue argLV =
+ MakeAddrLValue(Args.back(), I->Ty, TypeAlign);
if (RV.isScalar())
- EmitStoreOfScalar(RV.getScalarVal(), Args.back(), false,
- TypeAlign, I->Ty);
+ EmitStoreOfScalar(RV.getScalarVal(), argLV, /*init*/ true);
else
- StoreComplexToAddr(RV.getComplexVal(), Args.back(), false);
+ EmitStoreOfComplex(RV.getComplexVal(), argLV, /*init*/ true);
// Validate argument match.
checkArgMatches(AI, IRArgNo, IRFuncTy);
} else {
// We want to avoid creating an unnecessary temporary+copy here;
- // however, we need one in two cases:
+ // however, we need one in three cases:
// 1. If the argument is not byval, and we are required to copy the
// source. (This case doesn't occur on any common architecture.)
// 2. If the argument is byval, RV is not sufficiently aligned, and
// we cannot force it to be sufficiently aligned.
+ // 3. If the argument is byval, but RV is located in an address space
+ // different than that of the argument (0).
llvm::Value *Addr = RV.getAggregateAddr();
unsigned Align = ArgInfo.getIndirectAlign();
const llvm::DataLayout *TD = &CGM.getDataLayout();
+ const unsigned RVAddrSpace = Addr->getType()->getPointerAddressSpace();
+ const unsigned ArgAddrSpace = (IRArgNo < IRFuncTy->getNumParams() ?
+ IRFuncTy->getParamType(IRArgNo)->getPointerAddressSpace() : 0);
if ((!ArgInfo.getIndirectByVal() && I->NeedsCopy) ||
- (ArgInfo.getIndirectByVal() && TypeAlign < Align &&
- llvm::getOrEnforceKnownAlignment(Addr, Align, TD) < Align)) {
+ (ArgInfo.getIndirectByVal() && TypeAlign.getQuantity() < Align &&
+ llvm::getOrEnforceKnownAlignment(Addr, Align, TD) < Align) ||
+ (ArgInfo.getIndirectByVal() && (RVAddrSpace != ArgAddrSpace))) {
// Create an aligned temporary, and copy to it.
llvm::AllocaInst *AI = CreateMemTemp(I->Ty);
if (Align > AI->getAlignment())
@@ -2130,12 +2263,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// FIXME: Avoid the conversion through memory if possible.
llvm::Value *SrcPtr;
- if (RV.isScalar()) {
- SrcPtr = CreateMemTemp(I->Ty, "coerce");
- EmitStoreOfScalar(RV.getScalarVal(), SrcPtr, false, TypeAlign, I->Ty);
- } else if (RV.isComplex()) {
+ if (RV.isScalar() || RV.isComplex()) {
SrcPtr = CreateMemTemp(I->Ty, "coerce");
- StoreComplexToAddr(RV.getComplexVal(), SrcPtr, false);
+ LValue SrcLV = MakeAddrLValue(SrcPtr, I->Ty, TypeAlign);
+ if (RV.isScalar()) {
+ EmitStoreOfScalar(RV.getScalarVal(), SrcLV, /*init*/ true);
+ } else {
+ EmitStoreOfComplex(RV.getComplexVal(), SrcLV, /*init*/ true);
+ }
} else
SrcPtr = RV.getAggregateAddr();
@@ -2288,14 +2423,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
emitWritebacks(*this, CallArgs);
switch (RetAI.getKind()) {
- case ABIArgInfo::Indirect: {
- unsigned Alignment = getContext().getTypeAlignInChars(RetTy).getQuantity();
- if (RetTy->isAnyComplexType())
- return RValue::getComplex(LoadComplexFromAddr(Args[0], false));
- if (CodeGenFunction::hasAggregateLLVMType(RetTy))
- return RValue::getAggregate(Args[0]);
- return RValue::get(EmitLoadOfScalar(Args[0], false, Alignment, RetTy));
- }
+ case ABIArgInfo::Indirect:
+ return convertTempToRValue(Args[0], RetTy);
case ABIArgInfo::Ignore:
// If we are ignoring an argument that had a result, make sure to
@@ -2306,12 +2435,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
case ABIArgInfo::Direct: {
llvm::Type *RetIRTy = ConvertType(RetTy);
if (RetAI.getCoerceToType() == RetIRTy && RetAI.getDirectOffset() == 0) {
- if (RetTy->isAnyComplexType()) {
+ switch (getEvaluationKind(RetTy)) {
+ case TEK_Complex: {
llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
return RValue::getComplex(std::make_pair(Real, Imag));
}
- if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ case TEK_Aggregate: {
llvm::Value *DestPtr = ReturnValue.getValue();
bool DestIsVolatile = ReturnValue.isVolatile();
@@ -2322,13 +2452,16 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
BuildAggStore(*this, CI, DestPtr, DestIsVolatile, false);
return RValue::getAggregate(DestPtr);
}
-
- // If the argument doesn't match, perform a bitcast to coerce it. This
- // can happen due to trivial type mismatches.
- llvm::Value *V = CI;
- if (V->getType() != RetIRTy)
- V = Builder.CreateBitCast(V, RetIRTy);
- return RValue::get(V);
+ case TEK_Scalar: {
+ // If the argument doesn't match, perform a bitcast to coerce it. This
+ // can happen due to trivial type mismatches.
+ llvm::Value *V = CI;
+ if (V->getType() != RetIRTy)
+ V = Builder.CreateBitCast(V, RetIRTy);
+ return RValue::get(V);
+ }
+ }
+ llvm_unreachable("bad evaluation kind");
}
llvm::Value *DestPtr = ReturnValue.getValue();
@@ -2349,12 +2482,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this);
- unsigned Alignment = getContext().getTypeAlignInChars(RetTy).getQuantity();
- if (RetTy->isAnyComplexType())
- return RValue::getComplex(LoadComplexFromAddr(DestPtr, false));
- if (CodeGenFunction::hasAggregateLLVMType(RetTy))
- return RValue::getAggregate(DestPtr);
- return RValue::get(EmitLoadOfScalar(DestPtr, false, Alignment, RetTy));
+ return convertTempToRValue(DestPtr, RetTy);
}
case ABIArgInfo::Expand:
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index ac2dada083..287d164cb9 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -451,12 +451,14 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
LV.setAlignment(std::min(Align, LV.getAlignment()));
}
- if (!CGF.hasAggregateLLVMType(T)) {
+ switch (CGF.getEvaluationKind(T)) {
+ case TEK_Scalar:
CGF.EmitScalarInit(Init, /*decl*/ 0, LV, false);
- } else if (T->isAnyComplexType()) {
- CGF.EmitComplexExprIntoAddr(Init, LV.getAddress(),
- LV.isVolatileQualified());
- } else {
+ break;
+ case TEK_Complex:
+ CGF.EmitComplexExprIntoLValue(Init, LV, /*isInit*/ true);
+ break;
+ case TEK_Aggregate: {
AggValueSlot Slot =
AggValueSlot::forLValue(LV,
AggValueSlot::IsDestructed,
@@ -464,6 +466,8 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
AggValueSlot::IsNotAliased);
CGF.EmitAggExpr(Init, Slot);
+ break;
+ }
}
}
@@ -600,16 +604,19 @@ void CodeGenFunction::EmitInitializerForField(FieldDecl *Field,
LValue LHS, Expr *Init,
ArrayRef<VarDecl *> ArrayIndexes) {
QualType FieldType = Field->getType();
- if (!hasAggregateLLVMType(FieldType)) {
+ switch (getEvaluationKind(FieldType)) {
+ case TEK_Scalar:
if (LHS.isSimple()) {
EmitExprAsInit(Init, Field, LHS, false);
} else {
RValue RHS = RValue::get(EmitScalarExpr(Init));
EmitStoreThroughLValue(RHS, LHS);
}
- } else if (FieldType->isAnyComplexType()) {
- EmitComplexExprIntoAddr(Init, LHS.getAddress(), LHS.isVolatileQualified());
- } else {
+ break;
+ case TEK_Complex:
+ EmitComplexExprIntoLValue(Init, LHS, /*isInit*/ true);
+ break;
+ case TEK_Aggregate: {
llvm::Value *ArrayIndexVar = 0;
if (ArrayIndexes.size()) {
llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
@@ -638,6 +645,7 @@ void CodeGenFunction::EmitInitializerForField(FieldDecl *Field,
EmitAggMemberInitializer(*this, LHS, Init, ArrayIndexVar, FieldType,
ArrayIndexes, 0);
}
+ }
// Ensure that we destroy this object if an exception is thrown
// later in the constructor.
@@ -794,9 +802,7 @@ namespace {
const CGBitFieldInfo &BFInfo = RL.getBitFieldInfo(FirstField);
Alignment = CharUnits::fromQuantity(BFInfo.StorageAlignment);
} else {
- unsigned AlignBits =
- CGF.getContext().getTypeAlign(FirstField->getType());
- Alignment = CGF.getContext().toCharUnitsFromBits(AlignBits);
+ Alignment = CGF.getContext().getDeclAlign(FirstField);
}
assert((CGF.getContext().toCharUnitsFromBits(FirstFieldOffset) %
@@ -2175,7 +2181,7 @@ void CodeGenFunction::EmitForwardingCallToLambda(const CXXRecordDecl *lambda,
ReturnValueSlot returnSlot;
if (!resultType->isVoidType() &&
calleeFnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect &&
- hasAggregateLLVMType(calleeFnInfo.getReturnType()))
+ !hasScalarEvaluationKind(calleeFnInfo.getReturnType()))
returnSlot = ReturnValueSlot(ReturnValue, resultType.isVolatileQualified());
// We don't need to separately arrange the call arguments because
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index f9ea7e0a26..861d31fb7f 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -52,7 +52,8 @@ DominatingValue<RValue>::saved_type::save(CodeGenFunction &CGF, RValue rv) {
llvm::StructType::get(V.first->getType(), V.second->getType(),
(void*) 0);
llvm::Value *addr = CGF.CreateTempAlloca(ComplexTy, "saved-complex");
- CGF.StoreComplexToAddr(V, addr, /*volatile*/ false);
+ CGF.Builder.CreateStore(V.first, CGF.Builder.CreateStructGEP(addr, 0));
+ CGF.Builder.CreateStore(V.second, CGF.Builder.CreateStructGEP(addr, 1));
return saved_type(addr, ComplexAddress);
}
@@ -79,8 +80,13 @@ RValue DominatingValue<RValue>::saved_type::restore(CodeGenFunction &CGF) {
return RValue::getAggregate(Value);
case AggregateAddress:
return RValue::getAggregate(CGF.Builder.CreateLoad(Value));
- case ComplexAddress:
- return RValue::getComplex(CGF.LoadComplexFromAddr(Value, false));
+ case ComplexAddress: {
+ llvm::Value *real =
+ CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(Value, 0));
+ llvm::Value *imag =
+ CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(Value, 1));
+ return RValue::getComplex(real, imag);
+ }
}
llvm_unreachable("bad saved r-value kind");
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 970ba50b71..a139597c26 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -1314,7 +1314,7 @@ llvm::DIType CGDebugInfo::getOrCreateInterfaceType(QualType D,
SourceLocation Loc) {
assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
llvm::DIType T = getOrCreateType(D, getOrCreateFile(Loc));
- DBuilder.retainType(T);
+ RetainedTypes.push_back(D.getAsOpaquePtr());
return T;
}
@@ -1343,7 +1343,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
LexicalBlockStack.push_back(FwdDeclNode);
RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
- // Add this to the completed types cache since we're completing it.
+ // Add this to the completed-type cache while we're completing it recursively.
CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
// Convert all the elements.
@@ -1436,7 +1436,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// Otherwise, insert it into the CompletedTypeCache so that recursive uses
// will find it and we're emitting the complete type.
- CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl;
+ QualType QualTy = QualType(Ty, 0);
+ CompletedTypeCache[QualTy.getAsOpaquePtr()] = RealDecl;
// Push the struct on region stack.
llvm::TrackingVH<llvm::MDNode> FwdDeclNode(RealDecl);
@@ -1561,6 +1562,12 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
FwdDeclNode->replaceOperandWith(10, Elements);
+
+ // If the implementation is not yet set, we do not want to mark it
+ // as complete. An implementation may declare additional
+ // private ivars that we would miss otherwise.
+ if (ID->getImplementation() == 0)
+ CompletedTypeCache.erase(QualTy.getAsOpaquePtr());
LexicalBlockStack.pop_back();
return llvm::DIType(FwdDeclNode);
@@ -1771,6 +1778,13 @@ llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) {
Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
// Check for existing entry.
+ if (Ty->getTypeClass() == Type::ObjCInterface) {
+ llvm::Value *V = getCachedInterfaceTypeOrNull(Ty);
+ if (V)
+ return llvm::DIType(cast<llvm::MDNode>(V));
+ else return llvm::DIType();
+ }
+
llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
TypeCache.find(Ty.getAsOpaquePtr());
if (it != TypeCache.end()) {
@@ -1790,17 +1804,37 @@ llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) {
Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
// Check for existing entry.
+ llvm::Value *V = 0;
llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
CompletedTypeCache.find(Ty.getAsOpaquePtr());
- if (it != CompletedTypeCache.end()) {
- // Verify that the debug info still exists.
- if (llvm::Value *V = it->second)
- return llvm::DIType(cast<llvm::MDNode>(V));
+ if (it != CompletedTypeCache.end())
+ V = it->second;
+ else {
+ V = getCachedInterfaceTypeOrNull(Ty);
}
+ // Verify that any cached debug info still exists.
+ if (V != 0)
+ return llvm::DIType(cast<llvm::MDNode>(V));
+
return llvm::DIType();
}
+/// getCachedInterfaceTypeOrNull - Get the type from the interface
+/// cache, unless it needs to regenerated. Otherwise return null.
+llvm::Value *CGDebugInfo::getCachedInterfaceTypeOrNull(QualType Ty) {
+ // Is there a cached interface that hasn't changed?
+ llvm::DenseMap<void *, std::pair<llvm::WeakVH, unsigned > >
+ ::iterator it1 = ObjCInterfaceCache.find(Ty.getAsOpaquePtr());
+
+ if (it1 != ObjCInterfaceCache.end())
+ if (ObjCInterfaceDecl* Decl = getObjCInterfaceDecl(Ty))
+ if (Checksum(Decl) == it1->second.second)
+ // Return cached forward declaration.
+ return it1->second.first;
+
+ return 0;
+}
/// getOrCreateType - Get the type from the cache or create a new
/// one if necessary.
@@ -1818,21 +1852,63 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
// Otherwise create the type.
llvm::DIType Res = CreateTypeNode(Ty, Unit);
+ void* TyPtr = Ty.getAsOpaquePtr();
+
+ // And update the type cache.
+ TypeCache[TyPtr] = Res;
llvm::DIType TC = getTypeOrNull(Ty);
if (TC.Verify() && TC.isForwardDecl())
- ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(),
- static_cast<llvm::Value*>(TC)));
-
- // And update the type cache.
- TypeCache[Ty.getAsOpaquePtr()] = Res;
+ ReplaceMap.push_back(std::make_pair(TyPtr, static_cast<llvm::Value*>(TC)));
+ else if (ObjCInterfaceDecl* Decl = getObjCInterfaceDecl(Ty)) {
+ // Interface types may have elements added to them by a
+ // subsequent implementation or extension, so we keep them in
+ // the ObjCInterfaceCache together with a checksum. Instead of
+ // the (possibly) incomplete interace type, we return a forward
+ // declaration that gets RAUW'd in CGDebugInfo::finalize().
+ llvm::DenseMap<void *, std::pair<llvm::WeakVH, unsigned > >
+ ::iterator it = ObjCInterfaceCache.find(TyPtr);
+ if (it != ObjCInterfaceCache.end())
+ TC = llvm::DIType(cast<llvm::MDNode>(it->second.first));
+ else
+ TC = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ Decl->getName(), TheCU, Unit,
+ getLineNumber(Decl->getLocation()),
+ TheCU.getLanguage());
+ // Store the forward declaration in the cache.
+ ObjCInterfaceCache[TyPtr] = std::make_pair(TC, Checksum(Decl));
+
+ // Register the type for replacement in finalize().
+ ReplaceMap.push_back(std::make_pair(TyPtr, static_cast<llvm::Value*>(TC)));
+ return TC;
+ }
if (!Res.isForwardDecl())
- CompletedTypeCache[Ty.getAsOpaquePtr()] = Res;
+ CompletedTypeCache[TyPtr] = Res;
return Res;
}
+/// Currently the checksum merely consists of the number of ivars.
+unsigned CGDebugInfo::Checksum(const ObjCInterfaceDecl
+ *InterfaceDecl) {
+ unsigned IvarNo = 0;
+ for (const ObjCIvarDecl *Ivar = InterfaceDecl->all_declared_ivar_begin();
+ Ivar != 0; Ivar = Ivar->getNextIvar()) ++IvarNo;
+ return IvarNo;
+}
+
+ObjCInterfaceDecl *CGDebugInfo::getObjCInterfaceDecl(QualType Ty) {
+ switch (Ty->getTypeClass()) {
+ case Type::ObjCObjectPointer:
+ return getObjCInterfaceDecl(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
+ case Type::ObjCInterface:
+ return cast<ObjCInterfaceType>(Ty)->getDecl();
+ default:
+ return 0;
+ }
+}
+
/// CreateTypeNode - Create a new debug type node.
llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
// Handle qualifiers, which recursively handles what they refer to.
@@ -2878,10 +2954,17 @@ void CGDebugInfo::finalize() {
if (llvm::Value *V = it->second)
RepTy = llvm::DIType(cast<llvm::MDNode>(V));
}
-
+
if (Ty.Verify() && Ty.isForwardDecl() && RepTy.Verify()) {
Ty.replaceAllUsesWith(RepTy);
}
}
+
+ // We keep our own list of retained types, because we need to look
+ // up the final type in the type cache.
+ for (std::vector<void *>::const_iterator RI = RetainedTypes.begin(),
+ RE = RetainedTypes.end(); RI != RE; ++RI)
+ DBuilder.retainType(llvm::DIType(cast<llvm::MDNode>(TypeCache[*RI])));
+
DBuilder.finalize();
}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index fbbee0b3d2..2e896cfe22 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -32,6 +32,7 @@ namespace clang {
class CXXMethodDecl;
class VarDecl;
class ObjCInterfaceDecl;
+ class ObjCIvarDecl;
class ClassTemplateSpecializationDecl;
class GlobalDecl;
@@ -60,6 +61,14 @@ class CGDebugInfo {
/// TypeCache - Cache of previously constructed Types.
llvm::DenseMap<void *, llvm::WeakVH> TypeCache;
+ /// ObjCInterfaceCache - Cache of previously constructed interfaces
+ /// which may change. Storing a pair of DIType and checksum.
+ llvm::DenseMap<void *, std::pair<llvm::WeakVH, unsigned > >
+ ObjCInterfaceCache;
+
+ /// RetainedTypes - list of interfaces we want to keep even if orphaned.
+ std::vector<void *> RetainedTypes;
+
/// CompleteTypeCache - Cache of previously constructed complete RecordTypes.
llvm::DenseMap<void *, llvm::WeakVH> CompletedTypeCache;
@@ -89,6 +98,7 @@ class CGDebugInfo {
llvm::DenseMap<const Decl *, llvm::WeakVH> StaticDataMemberCache;
/// Helper functions for getOrCreateType.
+ unsigned Checksum(const ObjCInterfaceDecl *InterfaceDecl);
llvm::DIType CreateType(const BuiltinType *Ty);
llvm::DIType CreateType(const ComplexType *Ty);
llvm::DIType CreateQualifiedType(QualType Ty, llvm::DIFile F);
@@ -124,6 +134,7 @@ class CGDebugInfo {
const Type *Ty, QualType PointeeTy,
llvm::DIFile F);
+ llvm::Value *getCachedInterfaceTypeOrNull(const QualType Ty);
llvm::DIType getOrCreateStructPtrType(StringRef Name, llvm::DIType &Cache);
llvm::DISubprogram CreateCXXMemberFunction(const CXXMethodDecl *Method,
@@ -299,6 +310,10 @@ private:
/// CreateTypeNode - Create type metadata for a source language type.
llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F);
+ /// getObjCInterfaceDecl - return the underlying ObjCInterfaceDecl
+ /// if Ty is an ObjCInterface or a pointer to one.
+ ObjCInterfaceDecl* getObjCInterfaceDecl(QualType Ty);
+
/// CreateLimitedTypeNode - Create type metadata for a source language
/// type, but only partial types for records.
llvm::DIType CreateLimitedTypeNode(QualType Ty, llvm::DIFile F);
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 9c523149bd..0e001301ae 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -1115,21 +1115,33 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init,
if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
EmitStoreThroughLValue(rvalue, lvalue, true);
- } else if (!hasAggregateLLVMType(type)) {
+ return;
+ }
+ switch (getEvaluationKind(type)) {
+ case TEK_Scalar:
EmitScalarInit(init, D, lvalue, capturedByInit);
- } else if (type->isAnyComplexType()) {
+ return;
+ case TEK_Complex: {
ComplexPairTy complex = EmitComplexExpr(init);
if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
- StoreComplexToAddr(complex, lvalue.getAddress(), lvalue.isVolatile());
- } else {
- // TODO: how can we delay here if D is captured by its initializer?
- EmitAggExpr(init, AggValueSlot::forLValue(lvalue,
+ EmitStoreOfComplex(complex, lvalue, /*init*/ true);
+ return;
+ }
+ case TEK_Aggregate:
+ if (type->isAtomicType()) {
+ EmitAtomicInit(const_cast<Expr*>(init), lvalue);
+ } else {
+ // TODO: how can we delay here if D is captured by its initializer?
+ EmitAggExpr(init, AggValueSlot::forLValue(lvalue,
AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased));
+ }
MaybeEmitStdInitializerListCleanup(lvalue.getAddress(), init);
+ return;
}
+ llvm_unreachable("bad evaluation kind");
}
/// Enter a destroy cleanup for the given local variable.
@@ -1521,7 +1533,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
llvm::Value *DeclPtr;
// If this is an aggregate or variable sized value, reuse the input pointer.
if (!Ty->isConstantSizeType() ||
- CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ !CodeGenFunction::hasScalarEvaluationKind(Ty)) {
DeclPtr = Arg;
} else {
// Otherwise, create a temporary to hold the value.
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index a5884e35db..0448d31f40 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -34,7 +34,8 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
LValue lv = CGF.MakeAddrLValue(DeclPtr, type, alignment);
const Expr *Init = D.getInit();
- if (!CGF.hasAggregateLLVMType(type)) {
+ switch (CGF.getEvaluationKind(type)) {
+ case TEK_Scalar: {
CodeGenModule &CGM = CGF.CGM;
if (lv.isObjCStrong())
CGM.getObjCRuntime().EmitObjCGlobalAssign(CGF, CGF.EmitScalarExpr(Init),
@@ -44,13 +45,18 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
DeclPtr);
else
CGF.EmitScalarInit(Init, &D, lv, false);
- } else if (type->isAnyComplexType()) {
- CGF.EmitComplexExprIntoAddr(Init, DeclPtr, lv.isVolatile());
- } else {
+ return;
+ }
+ case TEK_Complex:
+ CGF.EmitComplexExprIntoLValue(Init, lv, /*isInit*/ true);
+ return;
+ case TEK_Aggregate:
CGF.EmitAggExpr(Init, AggValueSlot::forLValue(lv,AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased));
+ return;
}
+ llvm_unreachable("bad evaluation kind");
}
/// Emit code to cause the destruction of the given variable with
@@ -198,7 +204,7 @@ void CodeGenFunction::registerGlobalDtorWithAtExit(llvm::Constant *dtor,
if (llvm::Function *atexitFn = dyn_cast<llvm::Function>(atexit))
atexitFn->setDoesNotThrow();
- Builder.CreateCall(atexit, dtorStub)->setDoesNotThrow();
+ EmitNounwindRuntimeCall(atexit, dtorStub);
}
void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
@@ -229,6 +235,8 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
Fn->setSection(Section);
}
+ Fn->setCallingConv(CGM.getRuntimeCC());
+
if (!CGM.getLangOpts().Exceptions)
Fn->setDoesNotThrow();
@@ -392,7 +400,7 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
for (unsigned i = 0; i != NumDecls; ++i)
if (Decls[i])
- Builder.CreateCall(Decls[i]);
+ EmitRuntimeCall(Decls[i]);
Scope.ForceCleanup();
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 8dced6327b..36642bcc48 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -364,8 +364,7 @@ namespace {
llvm::Value *exn;
FreeException(llvm::Value *exn) : exn(exn) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
- CGF.Builder.CreateCall(getFreeExceptionFn(CGF.CGM), exn)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(getFreeExceptionFn(CGF.CGM), exn);
}
};
}
@@ -422,15 +421,8 @@ llvm::Value *CodeGenFunction::getSelectorFromSlot() {
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
if (!E->getSubExpr()) {
- if (getInvokeDest()) {
- Builder.CreateInvoke(getReThrowFn(CGM),
- getUnreachableBlock(),
- getInvokeDest())
- ->setDoesNotReturn();
- } else {
- Builder.CreateCall(getReThrowFn(CGM))->setDoesNotReturn();
- Builder.CreateUnreachable();
- }
+ EmitNoreturnRuntimeCallOrInvoke(getReThrowFn(CGM),
+ ArrayRef<llvm::Value*>());
// throw is an expression, and the expression emitters expect us
// to leave ourselves at a valid insertion point.
@@ -458,10 +450,9 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(CGM);
llvm::CallInst *ExceptionPtr =
- Builder.CreateCall(AllocExceptionFn,
- llvm::ConstantInt::get(SizeTy, TypeSize),
- "exception");
- ExceptionPtr->setDoesNotThrow();
+ EmitNounwindRuntimeCall(AllocExceptionFn,
+ llvm::ConstantInt::get(SizeTy, TypeSize),
+ "exception");
EmitAnyExprToExn(*this, E->getSubExpr(), ExceptionPtr);
@@ -482,18 +473,8 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
}
if (!Dtor) Dtor = llvm::Constant::getNullValue(Int8PtrTy);
- if (getInvokeDest()) {
- llvm::InvokeInst *ThrowCall =
- Builder.CreateInvoke3(getThrowFn(CGM),
- getUnreachableBlock(), getInvokeDest(),
- ExceptionPtr, TypeInfo, Dtor);
- ThrowCall->setDoesNotReturn();
- } else {
- llvm::CallInst *ThrowCall =
- Builder.CreateCall3(getThrowFn(CGM), ExceptionPtr, TypeInfo, Dtor);
- ThrowCall->setDoesNotReturn();
- Builder.CreateUnreachable();
- }
+ llvm::Value *args[] = { ExceptionPtr, TypeInfo, Dtor };
+ EmitNoreturnRuntimeCallOrInvoke(getThrowFn(CGM), args);
// throw is an expression, and the expression emitters expect us
// to leave ourselves at a valid insertion point.
@@ -563,7 +544,7 @@ static void emitFilterDispatchBlock(CodeGenFunction &CGF,
// according to the last landing pad the exception was thrown
// into. Seriously.
llvm::Value *exn = CGF.getExceptionFromSlot();
- CGF.Builder.CreateCall(getUnexpectedFn(CGF.CGM), exn)
+ CGF.EmitRuntimeCall(getUnexpectedFn(CGF.CGM), exn)
->setDoesNotReturn();
CGF.Builder.CreateUnreachable();
}
@@ -925,11 +906,11 @@ namespace {
void Emit(CodeGenFunction &CGF, Flags flags) {
if (!MightThrow) {
- CGF.Builder.CreateCall(getEndCatchFn(CGF.CGM))->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
return;
}
- CGF.EmitCallOrInvoke(getEndCatchFn(CGF.CGM));
+ CGF.EmitRuntimeCallOrInvoke(getEndCatchFn(CGF.CGM));
}
};
}
@@ -941,12 +922,12 @@ namespace {
static llvm::Value *CallBeginCatch(CodeGenFunction &CGF,
llvm::Value *Exn,
bool EndMightThrow) {
- llvm::CallInst *Call = CGF.Builder.CreateCall(getBeginCatchFn(CGF.CGM), Exn);
- Call->setDoesNotThrow();
+ llvm::CallInst *call =
+ CGF.EmitNounwindRuntimeCall(getBeginCatchFn(CGF.CGM), Exn);
CGF.EHStack.pushCleanup<CallEndCatch>(NormalAndEHCleanup, EndMightThrow);
- return Call;
+ return call;
}
/// A "special initializer" callback for initializing a catch
@@ -1021,10 +1002,9 @@ static void InitCatchParam(CodeGenFunction &CGF,
return;
}
- // Non-aggregates (plus complexes).
- bool IsComplex = false;
- if (!CGF.hasAggregateLLVMType(CatchType) ||
- (IsComplex = CatchType->isAnyComplexType())) {
+ // Scalars and complexes.
+ TypeEvaluationKind TEK = CGF.getEvaluationKind(CatchType);
+ if (TEK != TEK_Aggregate) {
llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, false);
// If the catch type is a pointer type, __cxa_begin_catch returns
@@ -1056,17 +1036,23 @@ static void InitCatchParam(CodeGenFunction &CGF,
llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
- if (IsComplex) {
- CGF.StoreComplexToAddr(CGF.LoadComplexFromAddr(Cast, /*volatile*/ false),
- ParamAddr, /*volatile*/ false);
- } else {
- unsigned Alignment =
- CGF.getContext().getDeclAlign(&CatchParam).getQuantity();
- llvm::Value *ExnLoad = CGF.Builder.CreateLoad(Cast, "exn.scalar");
- CGF.EmitStoreOfScalar(ExnLoad, ParamAddr, /*volatile*/ false, Alignment,
- CatchType);
+ LValue srcLV = CGF.MakeNaturalAlignAddrLValue(Cast, CatchType);
+ LValue destLV = CGF.MakeAddrLValue(ParamAddr, CatchType,
+ CGF.getContext().getDeclAlign(&CatchParam));
+ switch (TEK) {
+ case TEK_Complex:
+ CGF.EmitStoreOfComplex(CGF.EmitLoadOfComplex(srcLV), destLV,
+ /*init*/ true);
+ return;
+ case TEK_Scalar: {
+ llvm::Value *ExnLoad = CGF.EmitLoadOfScalar(srcLV);
+ CGF.EmitStoreOfScalar(ExnLoad, destLV, /*init*/ true);
+ return;
}
- return;
+ case TEK_Aggregate:
+ llvm_unreachable("evaluation kind filtered out!");
+ }
+ llvm_unreachable("bad evaluation kind");
}
assert(isa<RecordType>(CatchType) && "unexpected catch type!");
@@ -1086,8 +1072,7 @@ static void InitCatchParam(CodeGenFunction &CGF,
// We have to call __cxa_get_exception_ptr to get the adjusted
// pointer before copying.
llvm::CallInst *rawAdjustedExn =
- CGF.Builder.CreateCall(getGetExceptionPtrFn(CGF.CGM), Exn);
- rawAdjustedExn->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(getGetExceptionPtrFn(CGF.CGM), Exn);
// Cast that to the appropriate type.
llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy);
@@ -1310,7 +1295,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
// constructor function-try-block's catch handler (p14), so this
// really only applies to destructors.
if (doImplicitRethrow && HaveInsertPoint()) {
- EmitCallOrInvoke(getReThrowFn(CGM));
+ EmitRuntimeCallOrInvoke(getReThrowFn(CGM));
Builder.CreateUnreachable();
Builder.ClearInsertionPoint();
}
@@ -1342,7 +1327,7 @@ namespace {
CGF.Builder.CreateLoad(ForEHVar, "finally.endcatch");
CGF.Builder.CreateCondBr(ShouldEndCatch, EndCatchBB, CleanupContBB);
CGF.EmitBlock(EndCatchBB);
- CGF.EmitCallOrInvoke(EndCatchFn); // catch-all, so might throw
+ CGF.EmitRuntimeCallOrInvoke(EndCatchFn); // catch-all, so might throw
CGF.EmitBlock(CleanupContBB);
}
};
@@ -1387,9 +1372,10 @@ namespace {
CGF.EmitBlock(RethrowBB);
if (SavedExnVar) {
- CGF.EmitCallOrInvoke(RethrowFn, CGF.Builder.CreateLoad(SavedExnVar));
+ CGF.EmitRuntimeCallOrInvoke(RethrowFn,
+ CGF.Builder.CreateLoad(SavedExnVar));
} else {
- CGF.EmitCallOrInvoke(RethrowFn);
+ CGF.EmitRuntimeCallOrInvoke(RethrowFn);
}
CGF.Builder.CreateUnreachable();
@@ -1494,7 +1480,7 @@ void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) {
// If there's a begin-catch function, call it.
if (BeginCatchFn) {
exn = CGF.getExceptionFromSlot();
- CGF.Builder.CreateCall(BeginCatchFn, exn)->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(BeginCatchFn, exn);
}
// If we need to remember the exception pointer to rethrow later, do so.
@@ -1561,12 +1547,15 @@ static llvm::Constant *getClangCallTerminateFn(CodeGenModule &CGM) {
llvm::Value *exn = &*fn->arg_begin();
// Call __cxa_begin_catch(exn).
- builder.CreateCall(getBeginCatchFn(CGM), exn)->setDoesNotThrow();
+ llvm::CallInst *catchCall = builder.CreateCall(getBeginCatchFn(CGM), exn);
+ catchCall->setDoesNotThrow();
+ catchCall->setCallingConv(CGM.getRuntimeCC());
// Call std::terminate().
llvm::CallInst *termCall = builder.CreateCall(getTerminateFn(CGM));
termCall->setDoesNotThrow();
termCall->setDoesNotReturn();
+ termCall->setCallingConv(CGM.getRuntimeCC());
// std::terminate cannot return.
builder.CreateUnreachable();
@@ -1596,12 +1585,11 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
if (useClangCallTerminate(CGM)) {
// Extract out the exception pointer.
llvm::Value *exn = Builder.CreateExtractValue(LPadInst, 0);
- terminateCall = Builder.CreateCall(getClangCallTerminateFn(CGM), exn);
+ terminateCall = EmitNounwindRuntimeCall(getClangCallTerminateFn(CGM), exn);
} else {
- terminateCall = Builder.CreateCall(getTerminateFn(CGM));
+ terminateCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));
}
terminateCall->setDoesNotReturn();
- terminateCall->setDoesNotThrow();
Builder.CreateUnreachable();
// Restore the saved insertion state.
@@ -1620,9 +1608,8 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
// end of the function by FinishFunction.
TerminateHandler = createBasicBlock("terminate.handler");
Builder.SetInsertPoint(TerminateHandler);
- llvm::CallInst *TerminateCall = Builder.CreateCall(getTerminateFn(CGM));
+ llvm::CallInst *TerminateCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));
TerminateCall->setDoesNotReturn();
- TerminateCall->setDoesNotThrow();
Builder.CreateUnreachable();
// Restore the saved insertion state.
@@ -1646,8 +1633,8 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
// anything on the EH stack which needs our help.
const char *RethrowName = Personality.CatchallRethrowFn;
if (RethrowName != 0 && !isCleanup) {
- Builder.CreateCall(getCatchallRethrowFn(CGM, RethrowName),
- getExceptionFromSlot())
+ EmitRuntimeCall(getCatchallRethrowFn(CGM, RethrowName),
+ getExceptionFromSlot())
->setDoesNotReturn();
} else {
switch (CleanupHackLevel) {
@@ -1655,8 +1642,8 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
// In mandatory-catchall mode, we need to use
// _Unwind_Resume_or_Rethrow, or whatever the personality's
// equivalent is.
- Builder.CreateCall(getUnwindResumeOrRethrowFn(),
- getExceptionFromSlot())
+ EmitRuntimeCall(getUnwindResumeOrRethrowFn(),
+ getExceptionFromSlot())
->setDoesNotReturn();
break;
case CHL_MandatoryCleanup: {
@@ -1680,7 +1667,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
// In an idealized mode where we don't have to worry about the
// optimizer combining landing pads, we should just use
// _Unwind_Resume (or the personality's equivalent).
- Builder.CreateCall(getUnwindResumeFn(), getExceptionFromSlot())
+ EmitRuntimeCall(getUnwindResumeFn(), getExceptionFromSlot())
->setDoesNotReturn();
break;
}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 85662069ea..830b1218c1 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -114,15 +114,18 @@ void CodeGenFunction::EmitIgnoredExpr(const Expr *E) {
RValue CodeGenFunction::EmitAnyExpr(const Expr *E,
AggValueSlot aggSlot,
bool ignoreResult) {
- if (!hasAggregateLLVMType(E->getType()))
+ switch (getEvaluationKind(E->getType())) {
+ case TEK_Scalar:
return RValue::get(EmitScalarExpr(E, ignoreResult));
- else if (E->getType()->isAnyComplexType())
+ case TEK_Complex:
return RValue::getComplex(EmitComplexExpr(E, ignoreResult, ignoreResult));
-
- if (!ignoreResult && aggSlot.isIgnored())
- aggSlot = CreateAggTemp(E->getType(), "agg-temp");
- EmitAggExpr(E, aggSlot);
- return aggSlot.asRValue();
+ case TEK_Aggregate:
+ if (!ignoreResult && aggSlot.isIgnored())
+ aggSlot = CreateAggTemp(E->getType(), "agg-temp");
+ EmitAggExpr(E, aggSlot);
+ return aggSlot.asRValue();
+ }
+ llvm_unreachable("bad evaluation kind");
}
/// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result will
@@ -130,8 +133,7 @@ RValue CodeGenFunction::EmitAnyExpr(const Expr *E,
RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E) {
AggValueSlot AggSlot = AggValueSlot::ignored();
- if (hasAggregateLLVMType(E->getType()) &&
- !E->getType()->isAnyComplexType())
+ if (hasAggregateEvaluationKind(E->getType()))
AggSlot = CreateAggTemp(E->getType(), "agg.tmp");
return EmitAnyExpr(E, AggSlot);
}
@@ -143,19 +145,30 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
Qualifiers Quals,
bool IsInit) {
// FIXME: This function should take an LValue as an argument.
- if (E->getType()->isAnyComplexType()) {
- EmitComplexExprIntoAddr(E, Location, Quals.hasVolatile());
- } else if (hasAggregateLLVMType(E->getType())) {
+ switch (getEvaluationKind(E->getType())) {
+ case TEK_Complex:
+ EmitComplexExprIntoLValue(E,
+ MakeNaturalAlignAddrLValue(Location, E->getType()),
+ /*isInit*/ false);
+ return;
+
+ case TEK_Aggregate: {
CharUnits Alignment = getContext().getTypeAlignInChars(E->getType());
EmitAggExpr(E, AggValueSlot::forAddr(Location, Alignment, Quals,
AggValueSlot::IsDestructed_t(IsInit),
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsAliased_t(!IsInit)));
- } else {
+ return;
+ }
+
+ case TEK_Scalar: {
RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false));
LValue LV = MakeAddrLValue(Location, E->getType());
EmitStoreThroughLValue(RV, LV);
+ return;
}
+ }
+ llvm_unreachable("bad evaluation kind");
}
static llvm::Value *
@@ -288,8 +301,7 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
// Create a reference temporary if necessary.
AggValueSlot AggSlot = AggValueSlot::ignored();
- if (CGF.hasAggregateLLVMType(E->getType()) &&
- !E->getType()->isAnyComplexType()) {
+ if (CGF.hasAggregateEvaluationKind(E->getType())) {
ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(),
InitializedDecl);
CharUnits Alignment = CGF.getContext().getTypeAlignInChars(E->getType());
@@ -370,14 +382,12 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
InitializedDecl);
- unsigned Alignment =
- CGF.getContext().getTypeAlignInChars(E->getType()).getQuantity();
+ LValue tempLV = CGF.MakeNaturalAlignAddrLValue(ReferenceTemporary,
+ E->getType());
if (RV.isScalar())
- CGF.EmitStoreOfScalar(RV.getScalarVal(), ReferenceTemporary,
- /*Volatile=*/false, Alignment, E->getType());
+ CGF.EmitStoreOfScalar(RV.getScalarVal(), tempLV, /*init*/ true);
else
- CGF.StoreComplexToAddr(RV.getComplexVal(), ReferenceTemporary,
- /*Volatile=*/false);
+ CGF.EmitStoreOfComplex(RV.getComplexVal(), tempLV, /*init*/ true);
return ReferenceTemporary;
}
@@ -660,8 +670,8 @@ static bool isFlexibleArrayMemberExpr(const Expr *E) {
/// If Base is known to point to the start of an array, return the length of
/// that array. Return 0 if the length cannot be determined.
-llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, const Expr *Base,
- QualType &IndexedType) {
+static llvm::Value *getArrayIndexingBound(
+ CodeGenFunction &CGF, const Expr *Base, QualType &IndexedType) {
// For the vector indexing extension, the bound is the number of elements.
if (const VectorType *VT = Base->getType()->getAs<VectorType>()) {
IndexedType = Base->getType();
@@ -713,8 +723,7 @@ void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
CodeGenFunction::ComplexPairTy CodeGenFunction::
EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre) {
- ComplexPairTy InVal = LoadComplexFromAddr(LV.getAddress(),
- LV.isVolatileQualified());
+ ComplexPairTy InVal = EmitLoadOfComplex(LV);
llvm::Value *NextVal;
if (isa<llvm::IntegerType>(InVal.first->getType())) {
@@ -737,7 +746,7 @@ EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
ComplexPairTy IncVal(NextVal, InVal.second);
// Store the updated result through the lvalue.
- StoreComplexToAddr(IncVal, LV.getAddress(), LV.isVolatileQualified());
+ EmitStoreOfComplex(IncVal, LV, /*init*/ false);
// If this is a postinc, return the value read from memory, otherwise use the
// updated value.
@@ -752,9 +761,11 @@ EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
RValue CodeGenFunction::GetUndefRValue(QualType Ty) {
if (Ty->isVoidType())
return RValue::get(0);
-
- if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
- llvm::Type *EltTy = ConvertType(CTy->getElementType());
+
+ switch (getEvaluationKind(Ty)) {
+ case TEK_Complex: {
+ llvm::Type *EltTy =
+ ConvertType(Ty->castAs<ComplexType>()->getElementType());
llvm::Value *U = llvm::UndefValue::get(EltTy);
return RValue::getComplex(std::make_pair(U, U));
}
@@ -762,12 +773,15 @@ RValue CodeGenFunction::GetUndefRValue(QualType Ty) {
// If this is a use of an undefined aggregate type, the aggregate must have an
// identifiable address. Just because the contents of the value are undefined
// doesn't mean that the address can't be taken and compared.
- if (hasAggregateLLVMType(Ty)) {
+ case TEK_Aggregate: {
llvm::Value *DestPtr = CreateMemTemp(Ty, "undef.agg.tmp");
return RValue::getAggregate(DestPtr);
}
-
- return RValue::get(llvm::UndefValue::get(ConvertType(Ty)));
+
+ case TEK_Scalar:
+ return RValue::get(llvm::UndefValue::get(ConvertType(Ty)));
+ }
+ llvm_unreachable("bad evaluation kind");
}
RValue CodeGenFunction::EmitUnsupportedRValue(const Expr *E,
@@ -1093,7 +1107,6 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
unsigned Alignment, QualType Ty,
llvm::MDNode *TBAAInfo) {
-
// For better performance, handle vector loads differently.
if (Ty->isVectorType()) {
llvm::Value *V;
@@ -1131,6 +1144,14 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
return EmitFromMemory(V, Ty);
}
}
+
+ // Atomic operations have to be done on integral types.
+ if (Ty->isAtomicType()) {
+ LValue lvalue = LValue::MakeAddr(Addr, Ty,
+ CharUnits::fromQuantity(Alignment),
+ getContext(), TBAAInfo);
+ return EmitAtomicLoad(lvalue).getScalarVal();
+ }
llvm::LoadInst *Load = Builder.CreateLoad(Addr);
if (Volatile)
@@ -1139,9 +1160,6 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
Load->setAlignment(Alignment);
if (TBAAInfo)
CGM.DecorateInstruction(Load, TBAAInfo);
- // If this is an atomic type, all normal reads must be atomic
- if (Ty->isAtomicType())
- Load->setAtomic(llvm::SequentiallyConsistent);
if ((SanOpts->Bool && hasBooleanRepresentation(Ty)) ||
(SanOpts->Enum && Ty->getAs<EnumType>())) {
@@ -1237,18 +1255,25 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
}
Value = EmitToMemory(Value, Ty);
-
+
+ if (Ty->isAtomicType()) {
+ EmitAtomicStore(RValue::get(Value),
+ LValue::MakeAddr(Addr, Ty,
+ CharUnits::fromQuantity(Alignment),
+ getContext(), TBAAInfo),
+ isInit);
+ return;
+ }
+
llvm::StoreInst *Store = Builder.CreateStore(Value, Addr, Volatile);
if (Alignment)
Store->setAlignment(Alignment);
if (TBAAInfo)
CGM.DecorateInstruction(Store, TBAAInfo);
- if (!isInit && Ty->isAtomicType())
- Store->setAtomic(llvm::SequentiallyConsistent);
}
void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue,
- bool isInit) {
+ bool isInit) {
EmitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(),
lvalue.getAlignment().getQuantity(), lvalue.getType(),
lvalue.getTBAAInfo(), isInit);
@@ -2155,12 +2180,11 @@ void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
llvm::AttributeSet::get(getLLVMContext(),
llvm::AttributeSet::FunctionIndex,
B));
- llvm::CallInst *HandlerCall = Builder.CreateCall(Fn, Args);
+ llvm::CallInst *HandlerCall = EmitNounwindRuntimeCall(Fn, Args);
if (Recover) {
Builder.CreateBr(Cont);
} else {
HandlerCall->setDoesNotReturn();
- HandlerCall->setDoesNotThrow();
Builder.CreateUnreachable();
}
@@ -2580,8 +2604,7 @@ LValue CodeGenFunction::
EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
if (!expr->isGLValue()) {
// ?: here should be an aggregate.
- assert((hasAggregateLLVMType(expr->getType()) &&
- !expr->getType()->isAnyComplexType()) &&
+ assert(hasAggregateEvaluationKind(expr->getType()) &&
"Unexpected conditional operator!");
return EmitAggExprToLValue(expr);
}
@@ -2809,14 +2832,15 @@ RValue CodeGenFunction::EmitRValueForField(LValue LV,
const FieldDecl *FD) {
QualType FT = FD->getType();
LValue FieldLV = EmitLValueForField(LV, FD);
- if (FT->isAnyComplexType())
- return RValue::getComplex(
- LoadComplexFromAddr(FieldLV.getAddress(),
- FieldLV.isVolatileQualified()));
- else if (CodeGenFunction::hasAggregateLLVMType(FT))
+ switch (getEvaluationKind(FT)) {
+ case TEK_Complex:
+ return RValue::getComplex(EmitLoadOfComplex(FieldLV));
+ case TEK_Aggregate:
return FieldLV.asAggregateRValue();
-
- return EmitLoadOfLValue(FieldLV);
+ case TEK_Scalar:
+ return EmitLoadOfLValue(FieldLV);
+ }
+ llvm_unreachable("bad evaluation kind");
}
//===--------------------------------------------------------------------===//
@@ -2923,8 +2947,9 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
// Note that in all of these cases, __block variables need the RHS
// evaluated first just in case the variable gets moved by the RHS.
-
- if (!hasAggregateLLVMType(E->getType())) {
+
+ switch (getEvaluationKind(E->getType())) {
+ case TEK_Scalar: {
switch (E->getLHS()->getType().getObjCLifetime()) {
case Qualifiers::OCL_Strong:
return EmitARCStoreStrong(E, /*ignored*/ false).first;
@@ -2945,10 +2970,13 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
return LV;
}
- if (E->getType()->isAnyComplexType())
+ case TEK_Complex:
return EmitComplexAssignmentLValue(E);
- return EmitAggExprToLValue(E);
+ case TEK_Aggregate:
+ return EmitAggExprToLValue(E);
+ }
+ llvm_unreachable("bad evaluation kind");
}
LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
@@ -3021,7 +3049,7 @@ LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) {
LValue CodeGenFunction::EmitObjCSelectorLValue(const ObjCSelectorExpr *E) {
llvm::Value *V =
- CGM.getObjCRuntime().GetSelector(Builder, E->getSelector(), true);
+ CGM.getObjCRuntime().GetSelector(*this, E->getSelector(), true);
return MakeAddrLValue(V, E->getType());
}
@@ -3135,475 +3163,20 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) {
return MakeAddrLValue(AddV, MPT->getPointeeType());
}
-static void
-EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest,
- llvm::Value *Ptr, llvm::Value *Val1, llvm::Value *Val2,
- uint64_t Size, unsigned Align, llvm::AtomicOrdering Order) {
- llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
- llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
-
- switch (E->getOp()) {
- case AtomicExpr::AO__c11_atomic_init:
- llvm_unreachable("Already handled!");
-
- case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
- case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
- case AtomicExpr::AO__atomic_compare_exchange:
- case AtomicExpr::AO__atomic_compare_exchange_n: {
- // Note that cmpxchg only supports specifying one ordering and
- // doesn't support weak cmpxchg, at least at the moment.
- llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
- LoadVal1->setAlignment(Align);
- llvm::LoadInst *LoadVal2 = CGF.Builder.CreateLoad(Val2);
- LoadVal2->setAlignment(Align);
- llvm::AtomicCmpXchgInst *CXI =
- CGF.Builder.CreateAtomicCmpXchg(Ptr, LoadVal1, LoadVal2, Order);
- CXI->setVolatile(E->isVolatile());
- llvm::StoreInst *StoreVal1 = CGF.Builder.CreateStore(CXI, Val1);
- StoreVal1->setAlignment(Align);
- llvm::Value *Cmp = CGF.Builder.CreateICmpEQ(CXI, LoadVal1);
- CGF.EmitStoreOfScalar(Cmp, CGF.MakeAddrLValue(Dest, E->getType()));
- return;
- }
-
- case AtomicExpr::AO__c11_atomic_load:
- case AtomicExpr::AO__atomic_load_n:
- case AtomicExpr::AO__atomic_load: {
- llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
- Load->setAtomic(Order);
- Load->setAlignment(Size);
- Load->setVolatile(E->isVolatile());
- llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Load, Dest);
- StoreDest->setAlignment(Align);
- return;
- }
-
- case AtomicExpr::AO__c11_atomic_store:
- case AtomicExpr::AO__atomic_store:
- case AtomicExpr::AO__atomic_store_n: {
- assert(!Dest && "Store does not return a value");
- llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
- LoadVal1->setAlignment(Align);
- llvm::StoreInst *Store = CGF.Builder.CreateStore(LoadVal1, Ptr);
- Store->setAtomic(Order);
- Store->setAlignment(Size);
- Store->setVolatile(E->isVolatile());
- return;
+/// Given the address of a temporary variable, produce an r-value of
+/// its type.
+RValue CodeGenFunction::convertTempToRValue(llvm::Value *addr,
+ QualType type) {
+ LValue lvalue = MakeNaturalAlignAddrLValue(addr, type);
+ switch (getEvaluationKind(type)) {
+ case TEK_Complex:
+ return RValue::getComplex(EmitLoadOfComplex(lvalue));
+ case TEK_Aggregate:
+ return lvalue.asAggregateRValue();
+ case TEK_Scalar:
+ return RValue::get(EmitLoadOfScalar(lvalue));
}
-
- case AtomicExpr::AO__c11_atomic_exchange:
- case AtomicExpr::AO__atomic_exchange_n:
- case AtomicExpr::AO__atomic_exchange:
- Op = llvm::AtomicRMWInst::Xchg;
- break;
-
- case AtomicExpr::AO__atomic_add_fetch:
- PostOp = llvm::Instruction::Add;
- // Fall through.
- case AtomicExpr::AO__c11_atomic_fetch_add:
- case AtomicExpr::AO__atomic_fetch_add:
- Op = llvm::AtomicRMWInst::Add;
- break;
-
- case AtomicExpr::AO__atomic_sub_fetch:
- PostOp = llvm::Instruction::Sub;
- // Fall through.
- case AtomicExpr::AO__c11_atomic_fetch_sub:
- case AtomicExpr::AO__atomic_fetch_sub:
- Op = llvm::AtomicRMWInst::Sub;
- break;
-
- case AtomicExpr::AO__atomic_and_fetch:
- PostOp = llvm::Instruction::And;
- // Fall through.
- case AtomicExpr::AO__c11_atomic_fetch_and:
- case AtomicExpr::AO__atomic_fetch_and:
- Op = llvm::AtomicRMWInst::And;
- break;
-
- case AtomicExpr::AO__atomic_or_fetch:
- PostOp = llvm::Instruction::Or;
- // Fall through.
- case AtomicExpr::AO__c11_atomic_fetch_or:
- case AtomicExpr::AO__atomic_fetch_or:
- Op = llvm::AtomicRMWInst::Or;
- break;
-
- case AtomicExpr::AO__atomic_xor_fetch:
- PostOp = llvm::Instruction::Xor;
- // Fall through.
- case AtomicExpr::AO__c11_atomic_fetch_xor:
- case AtomicExpr::AO__atomic_fetch_xor:
- Op = llvm::AtomicRMWInst::Xor;
- break;
-
- case AtomicExpr::AO__atomic_nand_fetch:
- PostOp = llvm::Instruction::And;
- // Fall through.
- case AtomicExpr::AO__atomic_fetch_nand:
- Op = llvm::AtomicRMWInst::Nand;
- break;
- }
-
- llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
- LoadVal1->setAlignment(Align);
- llvm::AtomicRMWInst *RMWI =
- CGF.Builder.CreateAtomicRMW(Op, Ptr, LoadVal1, Order);
- RMWI->setVolatile(E->isVolatile());
-
- // For __atomic_*_fetch operations, perform the operation again to
- // determine the value which was written.
- llvm::Value *Result = RMWI;
- if (PostOp)
- Result = CGF.Builder.CreateBinOp(PostOp, RMWI, LoadVal1);
- if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch)
- Result = CGF.Builder.CreateNot(Result);
- llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Result, Dest);
- StoreDest->setAlignment(Align);
-}
-
-// This function emits any expression (scalar, complex, or aggregate)
-// into a temporary alloca.
-static llvm::Value *
-EmitValToTemp(CodeGenFunction &CGF, Expr *E) {
- llvm::Value *DeclPtr = CGF.CreateMemTemp(E->getType(), ".atomictmp");
- CGF.EmitAnyExprToMem(E, DeclPtr, E->getType().getQualifiers(),
- /*Init*/ true);
- return DeclPtr;
-}
-
-static RValue ConvertTempToRValue(CodeGenFunction &CGF, QualType Ty,
- llvm::Value *Dest) {
- if (Ty->isAnyComplexType())
- return RValue::getComplex(CGF.LoadComplexFromAddr(Dest, false));
- if (CGF.hasAggregateLLVMType(Ty))
- return RValue::getAggregate(Dest);
- return RValue::get(CGF.EmitLoadOfScalar(CGF.MakeAddrLValue(Dest, Ty)));
-}
-
-RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
- QualType AtomicTy = E->getPtr()->getType()->getPointeeType();
- QualType MemTy = AtomicTy;
- if (const AtomicType *AT = AtomicTy->getAs<AtomicType>())
- MemTy = AT->getValueType();
- CharUnits sizeChars = getContext().getTypeSizeInChars(AtomicTy);
- uint64_t Size = sizeChars.getQuantity();
- CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy);
- unsigned Align = alignChars.getQuantity();
- unsigned MaxInlineWidthInBits =
- getContext().getTargetInfo().getMaxAtomicInlineWidth();
- bool UseLibcall = (Size != Align ||
- getContext().toBits(sizeChars) > MaxInlineWidthInBits);
-
- llvm::Value *Ptr, *Order, *OrderFail = 0, *Val1 = 0, *Val2 = 0;
- Ptr = EmitScalarExpr(E->getPtr());
-
- if (E->getOp() == AtomicExpr::AO__c11_atomic_init) {
- assert(!Dest && "Init does not return a value");
- if (!hasAggregateLLVMType(E->getVal1()->getType())) {
- QualType PointeeType
- = E->getPtr()->getType()->getAs<PointerType>()->getPointeeType();
- EmitScalarInit(EmitScalarExpr(E->getVal1()),
- LValue::MakeAddr(Ptr, PointeeType, alignChars,
- getContext()));
- } else if (E->getType()->isAnyComplexType()) {
- EmitComplexExprIntoAddr(E->getVal1(), Ptr, E->isVolatile());
- } else {
- AggValueSlot Slot = AggValueSlot::forAddr(Ptr, alignChars,
- AtomicTy.getQualifiers(),
- AggValueSlot::IsNotDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased);
- EmitAggExpr(E->getVal1(), Slot);
- }
- return RValue::get(0);
- }
-
- Order = EmitScalarExpr(E->getOrder());
-
- switch (E->getOp()) {
- case AtomicExpr::AO__c11_atomic_init:
- llvm_unreachable("Already handled!");
-
- case AtomicExpr::AO__c11_atomic_load:
- case AtomicExpr::AO__atomic_load_n:
- break;
-
- case AtomicExpr::AO__atomic_load:
- Dest = EmitScalarExpr(E->getVal1());
- break;
-
- case AtomicExpr::AO__atomic_store:
- Val1 = EmitScalarExpr(E->getVal1());
- break;
-
- case AtomicExpr::AO__atomic_exchange:
- Val1 = EmitScalarExpr(E->getVal1());
- Dest = EmitScalarExpr(E->getVal2());
- break;
-
- case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
- case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
- case AtomicExpr::AO__atomic_compare_exchange_n:
- case AtomicExpr::AO__atomic_compare_exchange:
- Val1 = EmitScalarExpr(E->getVal1());
- if (E->getOp() == AtomicExpr::AO__atomic_compare_exchange)
- Val2 = EmitScalarExpr(E->getVal2());
- else
- Val2 = EmitValToTemp(*this, E->getVal2());
- OrderFail = EmitScalarExpr(E->getOrderFail());
- // Evaluate and discard the 'weak' argument.
- if (E->getNumSubExprs() == 6)
- EmitScalarExpr(E->getWeak());
- break;
-
- case AtomicExpr::AO__c11_atomic_fetch_add:
- case AtomicExpr::AO__c11_atomic_fetch_sub:
- if (MemTy->isPointerType()) {
- // For pointer arithmetic, we're required to do a bit of math:
- // adding 1 to an int* is not the same as adding 1 to a uintptr_t.
- // ... but only for the C11 builtins. The GNU builtins expect the
- // user to multiply by sizeof(T).
- QualType Val1Ty = E->getVal1()->getType();
- llvm::Value *Val1Scalar = EmitScalarExpr(E->getVal1());
- CharUnits PointeeIncAmt =
- getContext().getTypeSizeInChars(MemTy->getPointeeType());
- Val1Scalar = Builder.CreateMul(Val1Scalar, CGM.getSize(PointeeIncAmt));
- Val1 = CreateMemTemp(Val1Ty, ".atomictmp");
- EmitStoreOfScalar(Val1Scalar, MakeAddrLValue(Val1, Val1Ty));
- break;
- }
- // Fall through.
- case AtomicExpr::AO__atomic_fetch_add:
- case AtomicExpr::AO__atomic_fetch_sub:
- case AtomicExpr::AO__atomic_add_fetch:
- case AtomicExpr::AO__atomic_sub_fetch:
- case AtomicExpr::AO__c11_atomic_store:
- case AtomicExpr::AO__c11_atomic_exchange:
- case AtomicExpr::AO__atomic_store_n:
- case AtomicExpr::AO__atomic_exchange_n:
- case AtomicExpr::AO__c11_atomic_fetch_and:
- case AtomicExpr::AO__c11_atomic_fetch_or:
- case AtomicExpr::AO__c11_atomic_fetch_xor:
- case AtomicExpr::AO__atomic_fetch_and:
- case AtomicExpr::AO__atomic_fetch_or:
- case AtomicExpr::AO__atomic_fetch_xor:
- case AtomicExpr::AO__atomic_fetch_nand:
- case AtomicExpr::AO__atomic_and_fetch:
- case AtomicExpr::AO__atomic_or_fetch:
- case AtomicExpr::AO__atomic_xor_fetch:
- case AtomicExpr::AO__atomic_nand_fetch:
- Val1 = EmitValToTemp(*this, E->getVal1());
- break;
- }
-
- if (!E->getType()->isVoidType() && !Dest)
- Dest = CreateMemTemp(E->getType(), ".atomicdst");
-
- // Use a library call. See: http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary .
- if (UseLibcall) {
-
- SmallVector<QualType, 5> Params;
- CallArgList Args;
- // Size is always the first parameter
- Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
- getContext().getSizeType());
- // Atomic address is always the second parameter
- Args.add(RValue::get(EmitCastToVoidPtr(Ptr)),
- getContext().VoidPtrTy);
-
- const char* LibCallName;
- QualType RetTy = getContext().VoidTy;
- switch (E->getOp()) {
- // There is only one libcall for compare an exchange, because there is no
- // optimisation benefit possible from a libcall version of a weak compare
- // and exchange.
- // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
- // void *desired, int success, int failure)
- case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
- case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
- case AtomicExpr::AO__atomic_compare_exchange:
- case AtomicExpr::AO__atomic_compare_exchange_n:
- LibCallName = "__atomic_compare_exchange";
- RetTy = getContext().BoolTy;
- Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
- getContext().VoidPtrTy);
- Args.add(RValue::get(EmitCastToVoidPtr(Val2)),
- getContext().VoidPtrTy);
- Args.add(RValue::get(Order),
- getContext().IntTy);
- Order = OrderFail;
- break;
- // void __atomic_exchange(size_t size, void *mem, void *val, void *return,
- // int order)
- case AtomicExpr::AO__c11_atomic_exchange:
- case AtomicExpr::AO__atomic_exchange_n:
- case AtomicExpr::AO__atomic_exchange:
- LibCallName = "__atomic_exchange";
- Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
- getContext().VoidPtrTy);
- Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
- getContext().VoidPtrTy);
- break;
- // void __atomic_store(size_t size, void *mem, void *val, int order)
- case AtomicExpr::AO__c11_atomic_store:
- case AtomicExpr::AO__atomic_store:
- case AtomicExpr::AO__atomic_store_n:
- LibCallName = "__atomic_store";
- Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
- getContext().VoidPtrTy);
- break;
- // void __atomic_load(size_t size, void *mem, void *return, int order)
- case AtomicExpr::AO__c11_atomic_load:
- case AtomicExpr::AO__atomic_load:
- case AtomicExpr::AO__atomic_load_n:
- LibCallName = "__atomic_load";
- Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
- getContext().VoidPtrTy);
- break;
-#if 0
- // These are only defined for 1-16 byte integers. It is not clear what
- // their semantics would be on anything else...
- case AtomicExpr::Add: LibCallName = "__atomic_fetch_add_generic"; break;
- case AtomicExpr::Sub: LibCallName = "__atomic_fetch_sub_generic"; break;
- case AtomicExpr::And: LibCallName = "__atomic_fetch_and_generic"; break;
- case AtomicExpr::Or: LibCallName = "__atomic_fetch_or_generic"; break;
- case AtomicExpr::Xor: LibCallName = "__atomic_fetch_xor_generic"; break;
-#endif
- default: return EmitUnsupportedRValue(E, "atomic library call");
- }
- // order is always the last parameter
- Args.add(RValue::get(Order),
- getContext().IntTy);
-
- const CGFunctionInfo &FuncInfo =
- CGM.getTypes().arrangeFreeFunctionCall(RetTy, Args,
- FunctionType::ExtInfo(), RequiredArgs::All);
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo);
- llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
- RValue Res = EmitCall(FuncInfo, Func, ReturnValueSlot(), Args);
- if (E->isCmpXChg())
- return Res;
- if (E->getType()->isVoidType())
- return RValue::get(0);
- return ConvertTempToRValue(*this, E->getType(), Dest);
- }
-
- bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store ||
- E->getOp() == AtomicExpr::AO__atomic_store ||
- E->getOp() == AtomicExpr::AO__atomic_store_n;
- bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load ||
- E->getOp() == AtomicExpr::AO__atomic_load ||
- E->getOp() == AtomicExpr::AO__atomic_load_n;
-
- llvm::Type *IPtrTy =
- llvm::IntegerType::get(getLLVMContext(), Size * 8)->getPointerTo();
- llvm::Value *OrigDest = Dest;
- Ptr = Builder.CreateBitCast(Ptr, IPtrTy);
- if (Val1) Val1 = Builder.CreateBitCast(Val1, IPtrTy);
- if (Val2) Val2 = Builder.CreateBitCast(Val2, IPtrTy);
- if (Dest && !E->isCmpXChg()) Dest = Builder.CreateBitCast(Dest, IPtrTy);
-
- if (isa<llvm::ConstantInt>(Order)) {
- int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
- switch (ord) {
- case 0: // memory_order_relaxed
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Monotonic);
- break;
- case 1: // memory_order_consume
- case 2: // memory_order_acquire
- if (IsStore)
- break; // Avoid crashing on code with undefined behavior
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Acquire);
- break;
- case 3: // memory_order_release
- if (IsLoad)
- break; // Avoid crashing on code with undefined behavior
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Release);
- break;
- case 4: // memory_order_acq_rel
- if (IsLoad || IsStore)
- break; // Avoid crashing on code with undefined behavior
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::AcquireRelease);
- break;
- case 5: // memory_order_seq_cst
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::SequentiallyConsistent);
- break;
- default: // invalid order
- // We should not ever get here normally, but it's hard to
- // enforce that in general.
- break;
- }
- if (E->getType()->isVoidType())
- return RValue::get(0);
- return ConvertTempToRValue(*this, E->getType(), OrigDest);
- }
-
- // Long case, when Order isn't obviously constant.
-
- // Create all the relevant BB's
- llvm::BasicBlock *MonotonicBB = 0, *AcquireBB = 0, *ReleaseBB = 0,
- *AcqRelBB = 0, *SeqCstBB = 0;
- MonotonicBB = createBasicBlock("monotonic", CurFn);
- if (!IsStore)
- AcquireBB = createBasicBlock("acquire", CurFn);
- if (!IsLoad)
- ReleaseBB = createBasicBlock("release", CurFn);
- if (!IsLoad && !IsStore)
- AcqRelBB = createBasicBlock("acqrel", CurFn);
- SeqCstBB = createBasicBlock("seqcst", CurFn);
- llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
-
- // Create the switch for the split
- // MonotonicBB is arbitrarily chosen as the default case; in practice, this
- // doesn't matter unless someone is crazy enough to use something that
- // doesn't fold to a constant for the ordering.
- Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
- llvm::SwitchInst *SI = Builder.CreateSwitch(Order, MonotonicBB);
-
- // Emit all the different atomics
- Builder.SetInsertPoint(MonotonicBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Monotonic);
- Builder.CreateBr(ContBB);
- if (!IsStore) {
- Builder.SetInsertPoint(AcquireBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Acquire);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(1), AcquireBB);
- SI->addCase(Builder.getInt32(2), AcquireBB);
- }
- if (!IsLoad) {
- Builder.SetInsertPoint(ReleaseBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Release);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(3), ReleaseBB);
- }
- if (!IsLoad && !IsStore) {
- Builder.SetInsertPoint(AcqRelBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::AcquireRelease);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(4), AcqRelBB);
- }
- Builder.SetInsertPoint(SeqCstBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::SequentiallyConsistent);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(5), SeqCstBB);
-
- // Cleanup and return
- Builder.SetInsertPoint(ContBB);
- if (E->getType()->isVoidType())
- return RValue::get(0);
- return ConvertTempToRValue(*this, E->getType(), OrigDest);
+ llvm_unreachable("bad evaluation kind");
}
void CodeGenFunction::SetFPAccuracy(llvm::Value *Val, float Accuracy) {
@@ -3647,8 +3220,7 @@ static LValueOrRValue emitPseudoObjectExpr(CodeGenFunction &CGF,
typedef CodeGenFunction::OpaqueValueMappingData OVMA;
OVMA opaqueData;
if (ov == resultExpr && ov->isRValue() && !forLValue &&
- CodeGenFunction::hasAggregateLLVMType(ov->getType()) &&
- !ov->getType()->isAnyComplexType()) {
+ CodeGenFunction::hasAggregateEvaluationKind(ov->getType())) {
CGF.EmitAggExpr(ov->getSourceExpr(), slot);
LValue LV = CGF.MakeAddrLValue(slot.getAddr(), ov->getType());
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 8c64e8a6e7..1ac13c01ed 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -29,6 +29,14 @@ using namespace CodeGen;
// Aggregate Expression Emitter
//===----------------------------------------------------------------------===//
+llvm::Value *AggValueSlot::getPaddedAtomicAddr() const {
+ assert(isValueOfAtomic());
+ llvm::GEPOperator *op = cast<llvm::GEPOperator>(getAddr());
+ assert(op->getNumIndices() == 2);
+ assert(op->hasAllZeroIndices());
+ return op->getPointerOperand();
+}
+
namespace {
class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
CodeGenFunction &CGF;
@@ -190,6 +198,38 @@ public:
CGF.EmitAtomicExpr(E, EnsureSlot(E->getType()).getAddr());
}
};
+
+/// A helper class for emitting expressions into the value sub-object
+/// of a padded atomic type.
+class ValueDestForAtomic {
+ AggValueSlot Dest;
+public:
+ ValueDestForAtomic(CodeGenFunction &CGF, AggValueSlot dest, QualType type)
+ : Dest(dest) {
+ assert(!Dest.isValueOfAtomic());
+ if (!Dest.isIgnored() && CGF.CGM.isPaddedAtomicType(type)) {
+ llvm::Value *valueAddr = CGF.Builder.CreateStructGEP(Dest.getAddr(), 0);
+ Dest = AggValueSlot::forAddr(valueAddr,
+ Dest.getAlignment(),
+ Dest.getQualifiers(),
+ Dest.isExternallyDestructed(),
+ Dest.requiresGCollection(),
+ Dest.isPotentiallyAliased(),
+ Dest.isZeroed(),
+ AggValueSlot::IsValueOfAtomic);
+ }
+ }
+
+ const AggValueSlot &getDest() const { return Dest; }
+
+ ~ValueDestForAtomic() {
+ // Kill the GEP if we made one and it didn't end up used.
+ if (Dest.isValueOfAtomic()) {
+ llvm::Instruction *addr = cast<llvm::GetElementPtrInst>(Dest.getAddr());
+ if (addr->use_empty()) addr->eraseFromParent();
+ }
+ }
+};
} // end anonymous namespace.
//===----------------------------------------------------------------------===//
@@ -201,6 +241,14 @@ public:
/// then loads the result into DestPtr.
void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) {
LValue LV = CGF.EmitLValue(E);
+
+ // If the type of the l-value is atomic, then do an atomic load.
+ if (LV.getType()->isAtomicType()) {
+ ValueDestForAtomic valueDest(CGF, Dest, LV.getType());
+ CGF.EmitAtomicLoad(LV, valueDest.getDest());
+ return;
+ }
+
EmitFinalDestCopy(E->getType(), LV);
}
@@ -531,12 +579,10 @@ void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
void
AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
- if (E->getType().isPODType(CGF.getContext())) {
+ if (Dest.isPotentiallyAliased() &&
+ E->getType().isPODType(CGF.getContext())) {
// For a POD type, just emit a load of the lvalue + a copy, because our
// compound literal might alias the destination.
- // FIXME: This is a band-aid; the real problem appears to be in our handling
- // of assignments, where we store directly into the LHS without checking
- // whether anything in the RHS aliases.
EmitAggLoadOfLValue(E);
return;
}
@@ -545,6 +591,20 @@ AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
CGF.EmitAggExpr(E->getInitializer(), Slot);
}
+/// Attempt to look through various unimportant expressions to find a
+/// cast of the given kind.
+static Expr *findPeephole(Expr *op, CastKind kind) {
+ while (true) {
+ op = op->IgnoreParens();
+ if (CastExpr *castE = dyn_cast<CastExpr>(op)) {
+ if (castE->getCastKind() == kind)
+ return castE->getSubExpr();
+ if (castE->getCastKind() == CK_NoOp)
+ continue;
+ }
+ return 0;
+ }
+}
void AggExprEmitter::VisitCastExpr(CastExpr *E) {
switch (E->getCastKind()) {
@@ -584,6 +644,75 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
"should have been unpacked before we got here");
}
+ case CK_NonAtomicToAtomic:
+ case CK_AtomicToNonAtomic: {
+ bool isToAtomic = (E->getCastKind() == CK_NonAtomicToAtomic);
+
+ // Determine the atomic and value types.
+ QualType atomicType = E->getSubExpr()->getType();
+ QualType valueType = E->getType();
+ if (isToAtomic) std::swap(atomicType, valueType);
+
+ assert(atomicType->isAtomicType());
+ assert(CGF.getContext().hasSameUnqualifiedType(valueType,
+ atomicType->castAs<AtomicType>()->getValueType()));
+
+ // Just recurse normally if we're ignoring the result or the
+ // atomic type doesn't change representation.
+ if (Dest.isIgnored() || !CGF.CGM.isPaddedAtomicType(atomicType)) {
+ return Visit(E->getSubExpr());
+ }
+
+ CastKind peepholeTarget =
+ (isToAtomic ? CK_AtomicToNonAtomic : CK_NonAtomicToAtomic);
+
+ // These two cases are reverses of each other; try to peephole them.
+ if (Expr *op = findPeephole(E->getSubExpr(), peepholeTarget)) {
+ assert(CGF.getContext().hasSameUnqualifiedType(op->getType(),
+ E->getType()) &&
+ "peephole significantly changed types?");
+ return Visit(op);
+ }
+
+ // If we're converting an r-value of non-atomic type to an r-value
+ // of atomic type, just make an atomic temporary, emit into that,
+ // and then copy the value out. (FIXME: do we need to
+ // zero-initialize it first?)
+ if (isToAtomic) {
+ ValueDestForAtomic valueDest(CGF, Dest, atomicType);
+ CGF.EmitAggExpr(E->getSubExpr(), valueDest.getDest());
+ return;
+ }
+
+ // Otherwise, we're converting an atomic type to a non-atomic type.
+
+ // If the dest is a value-of-atomic subobject, drill back out.
+ if (Dest.isValueOfAtomic()) {
+ AggValueSlot atomicSlot =
+ AggValueSlot::forAddr(Dest.getPaddedAtomicAddr(),
+ Dest.getAlignment(),
+ Dest.getQualifiers(),
+ Dest.isExternallyDestructed(),
+ Dest.requiresGCollection(),
+ Dest.isPotentiallyAliased(),
+ Dest.isZeroed(),
+ AggValueSlot::IsNotValueOfAtomic);
+ CGF.EmitAggExpr(E->getSubExpr(), atomicSlot);
+ return;
+ }
+
+ // Otherwise, make an atomic temporary, emit into that, and then
+ // copy the value out.
+ AggValueSlot atomicSlot =
+ CGF.CreateAggTemp(atomicType, "atomic-to-nonatomic.temp");
+ CGF.EmitAggExpr(E->getSubExpr(), atomicSlot);
+
+ llvm::Value *valueAddr =
+ Builder.CreateStructGEP(atomicSlot.getAddr(), 0);
+ RValue rvalue = RValue::getAggregate(valueAddr, atomicSlot.isVolatile());
+ return EmitFinalDestCopy(valueType, rvalue);
+ }
+
case CK_LValueToRValue:
// If we're loading from a volatile type, force the destination
// into existence.
@@ -591,11 +720,10 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
EnsureDest(E->getType());
return Visit(E->getSubExpr());
}
+
// fallthrough
case CK_NoOp:
- case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
case CK_UserDefinedConversion:
case CK_ConstructorConversion:
assert(CGF.getContext().hasSameUnqualifiedType(E->getSubExpr()->getType(),
@@ -777,6 +905,12 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
// Now emit the LHS and copy into it.
LValue LHS = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
+ // That copy is an atomic copy if the LHS is atomic.
+ if (LHS.getType()->isAtomicType()) {
+ CGF.EmitAtomicStore(Dest.asRValue(), LHS, /*isInit*/ false);
+ return;
+ }
+
EmitCopy(E->getLHS()->getType(),
AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
needsGC(E->getLHS()->getType()),
@@ -787,6 +921,15 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
LValue LHS = CGF.EmitLValue(E->getLHS());
+ // If we have an atomic type, evaluate into the destination and then
+ // do an atomic copy.
+ if (LHS.getType()->isAtomicType()) {
+ EnsureDest(E->getRHS()->getType());
+ Visit(E->getRHS());
+ CGF.EmitAtomicStore(Dest.asRValue(), LHS, /*isInit*/ false);
+ return;
+ }
+
// Codegen the RHS so that it stores directly into the LHS.
AggValueSlot LHSSlot =
AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
@@ -937,24 +1080,34 @@ AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
// FIXME: Are initializers affected by volatile?
if (Dest.isZeroed() && isSimpleZero(E, CGF)) {
// Storing "i32 0" to a zero'd memory location is a noop.
+ return;
} else if (isa<ImplicitValueInitExpr>(E) || isa<CXXScalarValueInitExpr>(E)) {
- EmitNullInitializationToLValue(LV);
+ return EmitNullInitializationToLValue(LV);
} else if (type->isReferenceType()) {
RValue RV = CGF.EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0);
- CGF.EmitStoreThroughLValue(RV, LV);
- } else if (type->isAnyComplexType()) {
- CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
- } else if (CGF.hasAggregateLLVMType(type)) {
+ return CGF.EmitStoreThroughLValue(RV, LV);
+ }
+
+ switch (CGF.getEvaluationKind(type)) {
+ case TEK_Complex:
+ CGF.EmitComplexExprIntoLValue(E, LV, /*isInit*/ true);
+ return;
+ case TEK_Aggregate:
CGF.EmitAggExpr(E, AggValueSlot::forLValue(LV,
AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased,
Dest.isZeroed()));
- } else if (LV.isSimple()) {
- CGF.EmitScalarInit(E, /*D=*/0, LV, /*Captured=*/false);
- } else {
- CGF.EmitStoreThroughLValue(RValue::get(CGF.EmitScalarExpr(E)), LV);
+ return;
+ case TEK_Scalar:
+ if (LV.isSimple()) {
+ CGF.EmitScalarInit(E, /*D=*/0, LV, /*Captured=*/false);
+ } else {
+ CGF.EmitStoreThroughLValue(RValue::get(CGF.EmitScalarExpr(E)), LV);
+ }
+ return;
}
+ llvm_unreachable("bad evaluation kind");
}
void AggExprEmitter::EmitNullInitializationToLValue(LValue lv) {
@@ -965,7 +1118,7 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue lv) {
if (Dest.isZeroed() && CGF.getTypes().isZeroInitializable(type))
return;
- if (!CGF.hasAggregateLLVMType(type)) {
+ if (CGF.hasScalarEvaluationKind(type)) {
// For non-aggregates, we can store the appropriate null constant.
llvm::Value *null = CGF.CGM.EmitNullConstant(type);
// Note that the following is not equivalent to
@@ -1256,7 +1409,7 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
/// the value of the aggregate expression is not needed. If VolatileDest is
/// true, DestPtr cannot be 0.
void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot) {
- assert(E && hasAggregateLLVMType(E->getType()) &&
+ assert(E && hasAggregateEvaluationKind(E->getType()) &&
"Invalid aggregate expression to emit");
assert((Slot.getAddr() != 0 || Slot.isIgnored()) &&
"slot has bits but no address");
@@ -1268,7 +1421,7 @@ void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot) {
}
LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
- assert(hasAggregateLLVMType(E->getType()) && "Invalid argument!");
+ assert(hasAggregateEvaluationKind(E->getType()) && "Invalid argument!");
llvm::Value *Temp = CreateMemTemp(E->getType());
LValue LV = MakeAddrLValue(Temp, E->getType());
EmitAggExpr(E, AggValueSlot::forLValue(LV, AggValueSlot::IsNotDestructed,
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index e09e06c8e2..13ae8bb01a 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -820,14 +820,18 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
QualType AllocType, llvm::Value *NewPtr) {
CharUnits Alignment = CGF.getContext().getTypeAlignInChars(AllocType);
- if (!CGF.hasAggregateLLVMType(AllocType))
+ switch (CGF.getEvaluationKind(AllocType)) {
+ case TEK_Scalar:
CGF.EmitScalarInit(Init, 0, CGF.MakeAddrLValue(NewPtr, AllocType,
Alignment),
false);
- else if (AllocType->isAnyComplexType())
- CGF.EmitComplexExprIntoAddr(Init, NewPtr,
- AllocType.isVolatileQualified());
- else {
+ return;
+ case TEK_Complex:
+ CGF.EmitComplexExprIntoLValue(Init, CGF.MakeAddrLValue(NewPtr, AllocType,
+ Alignment),
+ /*isInit*/ true);
+ return;
+ case TEK_Aggregate: {
AggValueSlot Slot
= AggValueSlot::forAddr(NewPtr, Alignment, AllocType.getQualifiers(),
AggValueSlot::IsDestructed,
@@ -836,7 +840,10 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
CGF.EmitAggExpr(Init, Slot);
CGF.MaybeEmitStdInitializerListCleanup(NewPtr, Init);
+ return;
}
+ }
+ llvm_unreachable("bad evaluation kind");
}
void
@@ -1617,7 +1624,7 @@ static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) {
static void EmitBadTypeidCall(CodeGenFunction &CGF) {
llvm::Value *Fn = getBadTypeidFn(CGF);
- CGF.EmitCallOrInvoke(Fn).setDoesNotReturn();
+ CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
CGF.Builder.CreateUnreachable();
}
@@ -1710,7 +1717,7 @@ static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {
static void EmitBadCastCall(CodeGenFunction &CGF) {
llvm::Value *Fn = getBadCastFn(CGF);
- CGF.EmitCallOrInvoke(Fn).setDoesNotReturn();
+ CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
CGF.Builder.CreateUnreachable();
}
@@ -1825,8 +1832,9 @@ EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
// Emit the call to __dynamic_cast.
Value = CGF.EmitCastToVoidPtr(Value);
- Value = CGF.Builder.CreateCall4(getDynamicCastFn(CGF), Value,
- SrcRTTI, DestRTTI, OffsetHint);
+
+ llvm::Value *args[] = { Value, SrcRTTI, DestRTTI, OffsetHint };
+ Value = CGF.EmitNounwindRuntimeCall(getDynamicCastFn(CGF), args);
Value = CGF.Builder.CreateBitCast(Value, DestLTy);
/// C++ [expr.dynamic.cast]p9:
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 0a53d4f127..5fc73aa790 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -27,12 +27,21 @@ using namespace CodeGen;
typedef CodeGenFunction::ComplexPairTy ComplexPairTy;
+/// Return the complex type that we are meant to emit.
+static const ComplexType *getComplexType(QualType type) {
+ type = type.getCanonicalType();
+ if (const ComplexType *comp = dyn_cast<ComplexType>(type)) {
+ return comp;
+ } else {
+ return cast<ComplexType>(cast<AtomicType>(type)->getValueType());
+ }
+}
+
namespace {
class ComplexExprEmitter
: public StmtVisitor<ComplexExprEmitter, ComplexPairTy> {
CodeGenFunction &CGF;
CGBuilderTy &Builder;
- // True is we should ignore the value of a
bool IgnoreReal;
bool IgnoreImag;
public:
@@ -63,25 +72,11 @@ public:
return EmitLoadOfLValue(CGF.EmitLValue(E));
}
- ComplexPairTy EmitLoadOfLValue(LValue LV) {
- assert(LV.isSimple() && "complex l-value must be simple");
- return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified());
- }
-
- /// EmitLoadOfComplex - Given a pointer to a complex value, emit code to load
- /// the real and imaginary pieces.
- ComplexPairTy EmitLoadOfComplex(llvm::Value *SrcPtr, bool isVolatile);
-
- /// EmitStoreThroughLValue - Given an l-value of complex type, store
- /// a complex number into it.
- void EmitStoreThroughLValue(ComplexPairTy Val, LValue LV) {
- assert(LV.isSimple() && "complex l-value must be simple");
- return EmitStoreOfComplex(Val, LV.getAddress(), LV.isVolatileQualified());
- }
+ ComplexPairTy EmitLoadOfLValue(LValue LV);
/// EmitStoreOfComplex - Store the specified real/imag parts into the
/// specified value pointer.
- void EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *ResPtr, bool isVol);
+ void EmitStoreOfComplex(ComplexPairTy Val, LValue LV, bool isInit);
/// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType.
ComplexPairTy EmitComplexToComplexCast(ComplexPairTy Val, QualType SrcType,
@@ -194,13 +189,13 @@ public:
}
ComplexPairTy VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
assert(E->getType()->isAnyComplexType() && "Expected complex type!");
- QualType Elem = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType Elem = E->getType()->castAs<ComplexType>()->getElementType();
llvm::Constant *Null = llvm::Constant::getNullValue(CGF.ConvertType(Elem));
return ComplexPairTy(Null, Null);
}
ComplexPairTy VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
assert(E->getType()->isAnyComplexType() && "Expected complex type!");
- QualType Elem = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType Elem = E->getType()->castAs<ComplexType>()->getElementType();
llvm::Constant *Null =
llvm::Constant::getNullValue(CGF.ConvertType(Elem));
return ComplexPairTy(Null, Null);
@@ -286,10 +281,16 @@ public:
// Utilities
//===----------------------------------------------------------------------===//
-/// EmitLoadOfComplex - Given an RValue reference for a complex, emit code to
+/// EmitLoadOfLValue - Given an RValue reference for a complex, emit code to
/// load the real and imaginary pieces, returning them as Real/Imag.
-ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr,
- bool isVolatile) {
+ComplexPairTy ComplexExprEmitter::EmitLoadOfLValue(LValue lvalue) {
+ assert(lvalue.isSimple() && "non-simple complex l-value?");
+ if (lvalue.getType()->isAtomicType())
+ return CGF.EmitAtomicLoad(lvalue).getComplexVal();
+
+ llvm::Value *SrcPtr = lvalue.getAddress();
+ bool isVolatile = lvalue.isVolatileQualified();
+
llvm::Value *Real=0, *Imag=0;
if (!IgnoreReal || isVolatile) {
@@ -308,13 +309,19 @@ ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr,
/// EmitStoreOfComplex - Store the specified real/imag parts into the
/// specified value pointer.
-void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr,
- bool isVolatile) {
+void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val,
+ LValue lvalue,
+ bool isInit) {
+ if (lvalue.getType()->isAtomicType())
+ return CGF.EmitAtomicStore(RValue::getComplex(Val), lvalue, isInit);
+
+ llvm::Value *Ptr = lvalue.getAddress();
llvm::Value *RealPtr = Builder.CreateStructGEP(Ptr, 0, "real");
llvm::Value *ImagPtr = Builder.CreateStructGEP(Ptr, 1, "imag");
- Builder.CreateStore(Val.first, RealPtr, isVolatile);
- Builder.CreateStore(Val.second, ImagPtr, isVolatile);
+ // TODO: alignment
+ Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified());
+ Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified());
}
@@ -326,7 +333,7 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr,
ComplexPairTy ComplexExprEmitter::VisitExpr(Expr *E) {
CGF.ErrorUnsupported(E, "complex expression");
llvm::Type *EltTy =
- CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType());
+ CGF.ConvertType(getComplexType(E->getType())->getElementType());
llvm::Value *U = llvm::UndefValue::get(EltTy);
return ComplexPairTy(U, U);
}
@@ -355,8 +362,8 @@ ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val,
QualType SrcType,
QualType DestType) {
// Get the src/dest element type.
- SrcType = SrcType->getAs<ComplexType>()->getElementType();
- DestType = DestType->getAs<ComplexType>()->getElementType();
+ SrcType = SrcType->castAs<ComplexType>()->getElementType();
+ DestType = DestType->castAs<ComplexType>()->getElementType();
// C99 6.3.1.6: When a value of complex type is converted to another
// complex type, both the real and imaginary parts follow the conversion
@@ -381,11 +388,12 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
return Visit(Op);
case CK_LValueBitCast: {
- llvm::Value *V = CGF.EmitLValue(Op).getAddress();
+ LValue origLV = CGF.EmitLValue(Op);
+ llvm::Value *V = origLV.getAddress();
V = Builder.CreateBitCast(V,
CGF.ConvertType(CGF.getContext().getPointerType(DestTy)));
- // FIXME: Are the qualifiers correct here?
- return EmitLoadOfComplex(V, DestTy.isVolatileQualified());
+ return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy,
+ origLV.getAlignment()));
}
case CK_BitCast:
@@ -436,7 +444,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
llvm::Value *Elt = CGF.EmitScalarExpr(Op);
// Convert the input element to the element type of the complex.
- DestTy = DestTy->getAs<ComplexType>()->getElementType();
+ DestTy = DestTy->castAs<ComplexType>()->getElementType();
Elt = CGF.EmitScalarConversion(Elt, Op->getType(), DestTy);
// Return (realval, 0).
@@ -569,7 +577,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
llvm::Value *Tmp8 = Builder.CreateMul(LHSr, RHSi); // a*d
llvm::Value *Tmp9 = Builder.CreateSub(Tmp7, Tmp8); // bc-ad
- if (Op.Ty->getAs<ComplexType>()->getElementType()->isUnsignedIntegerType()) {
+ if (Op.Ty->castAs<ComplexType>()->getElementType()->isUnsignedIntegerType()) {
DSTr = Builder.CreateUDiv(Tmp3, Tmp6);
DSTi = Builder.CreateUDiv(Tmp9, Tmp6);
} else {
@@ -629,7 +637,7 @@ EmitCompoundAssignLValue(const CompoundAssignOperator *E,
Val = Result;
// Store the result value into the LHS lvalue.
- EmitStoreThroughLValue(Result, LHS);
+ EmitStoreOfComplex(Result, LHS, /*isInit*/ false);
return LHS;
}
@@ -649,7 +657,7 @@ EmitCompoundAssign(const CompoundAssignOperator *E,
if (!LV.isVolatileQualified())
return Val;
- return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified());
+ return EmitLoadOfLValue(LV);
}
LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E,
@@ -667,7 +675,7 @@ LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E,
LValue LHS = CGF.EmitLValue(E->getLHS());
// Store the result value into the LHS lvalue.
- EmitStoreThroughLValue(Val, LHS);
+ EmitStoreOfComplex(Val, LHS, /*isInit*/ false);
return LHS;
}
@@ -684,7 +692,7 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
if (!LV.isVolatileQualified())
return Val;
- return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified());
+ return EmitLoadOfLValue(LV);
}
ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) {
@@ -755,7 +763,7 @@ ComplexPairTy ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) {
// Empty init list intializes to null
assert(E->getNumInits() == 0 && "Unexpected number of inits");
- QualType Ty = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType Ty = E->getType()->castAs<ComplexType>()->getElementType();
llvm::Type* LTy = CGF.ConvertType(Ty);
llvm::Value* zeroConstant = llvm::Constant::getNullValue(LTy);
return ComplexPairTy(zeroConstant, zeroConstant);
@@ -768,13 +776,13 @@ ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
if (!ArgPtr) {
CGF.ErrorUnsupported(E, "complex va_arg expression");
llvm::Type *EltTy =
- CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType());
+ CGF.ConvertType(E->getType()->castAs<ComplexType>()->getElementType());
llvm::Value *U = llvm::UndefValue::get(EltTy);
return ComplexPairTy(U, U);
}
- // FIXME Volatility.
- return EmitLoadOfComplex(ArgPtr, false);
+ return EmitLoadOfLValue(
+ CGF.MakeNaturalAlignAddrLValue(ArgPtr, E->getType()));
}
//===----------------------------------------------------------------------===//
@@ -785,36 +793,31 @@ ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
/// complex type, ignoring the result.
ComplexPairTy CodeGenFunction::EmitComplexExpr(const Expr *E, bool IgnoreReal,
bool IgnoreImag) {
- assert(E && E->getType()->isAnyComplexType() &&
+ assert(E && getComplexType(E->getType()) &&
"Invalid complex expression to emit");
return ComplexExprEmitter(*this, IgnoreReal, IgnoreImag)
.Visit(const_cast<Expr*>(E));
}
-/// EmitComplexExprIntoAddr - Emit the computation of the specified expression
-/// of complex type, storing into the specified Value*.
-void CodeGenFunction::EmitComplexExprIntoAddr(const Expr *E,
- llvm::Value *DestAddr,
- bool DestIsVolatile) {
- assert(E && E->getType()->isAnyComplexType() &&
+void CodeGenFunction::EmitComplexExprIntoLValue(const Expr *E, LValue dest,
+ bool isInit) {
+ assert(E && getComplexType(E->getType()) &&
"Invalid complex expression to emit");
ComplexExprEmitter Emitter(*this);
ComplexPairTy Val = Emitter.Visit(const_cast<Expr*>(E));
- Emitter.EmitStoreOfComplex(Val, DestAddr, DestIsVolatile);
+ Emitter.EmitStoreOfComplex(Val, dest, isInit);
}
-/// StoreComplexToAddr - Store a complex number into the specified address.
-void CodeGenFunction::StoreComplexToAddr(ComplexPairTy V,
- llvm::Value *DestAddr,
- bool DestIsVolatile) {
- ComplexExprEmitter(*this).EmitStoreOfComplex(V, DestAddr, DestIsVolatile);
+/// EmitStoreOfComplex - Store a complex number into the specified l-value.
+void CodeGenFunction::EmitStoreOfComplex(ComplexPairTy V, LValue dest,
+ bool isInit) {
+ ComplexExprEmitter(*this).EmitStoreOfComplex(V, dest, isInit);
}
-/// LoadComplexFromAddr - Load a complex number from the specified address.
-ComplexPairTy CodeGenFunction::LoadComplexFromAddr(llvm::Value *SrcAddr,
- bool SrcIsVolatile) {
- return ComplexExprEmitter(*this).EmitLoadOfComplex(SrcAddr, SrcIsVolatile);
+/// EmitLoadOfComplex - Load a complex number from the specified address.
+ComplexPairTy CodeGenFunction::EmitLoadOfComplex(LValue src) {
+ return ComplexExprEmitter(*this).EmitLoadOfLValue(src);
}
LValue CodeGenFunction::EmitComplexAssignmentLValue(const BinaryOperator *E) {
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 4344f94045..e3e5d66605 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -1214,6 +1214,8 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
if (I < NumInitElts)
C = EmitConstantValueForMemory(Value.getArrayInitializedElt(I),
CAT->getElementType(), CGF);
+ else
+ assert(Filler && "Missing filler for implicit elements of initializer");
if (I == 0)
CommonElementType = C->getType();
else if (C->getType() != CommonElementType)
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 3ec4040a64..56b150ad38 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -775,7 +775,7 @@ Value *ScalarExprEmitter::
EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
QualType SrcTy, QualType DstTy) {
// Get the source element type.
- SrcTy = SrcTy->getAs<ComplexType>()->getElementType();
+ SrcTy = SrcTy->castAs<ComplexType>()->getElementType();
// Handle conversions to bool first, they are special: comparisons against 0.
if (DstTy->isBooleanType()) {
@@ -1444,21 +1444,60 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre) {
QualType type = E->getSubExpr()->getType();
- llvm::Value *value = EmitLoadOfLValue(LV);
- llvm::Value *input = value;
llvm::PHINode *atomicPHI = 0;
+ llvm::Value *value;
+ llvm::Value *input;
int amount = (isInc ? 1 : -1);
if (const AtomicType *atomicTy = type->getAs<AtomicType>()) {
+ type = atomicTy->getValueType();
+ if (isInc && type->isBooleanType()) {
+ llvm::Value *True = CGF.EmitToMemory(Builder.getTrue(), type);
+ if (isPre) {
+ Builder.Insert(new llvm::StoreInst(True,
+ LV.getAddress(), LV.isVolatileQualified(),
+ LV.getAlignment().getQuantity(),
+ llvm::SequentiallyConsistent));
+ return Builder.getTrue();
+ }
+ // For atomic bool increment, we just store true and return it for
+ // preincrement, do an atomic swap with true for postincrement
+ return Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg,
+ LV.getAddress(), True, llvm::SequentiallyConsistent);
+ }
+ // Special case for atomic increment / decrement on integers, emit
+ // atomicrmw instructions. We skip this if we want to be doing overflow
+ // checking, and fall into the slow path with the atomic cmpxchg loop.
+ if (!type->isBooleanType() && type->isIntegerType() &&
+ !(type->isUnsignedIntegerType() &&
+ CGF.SanOpts->UnsignedIntegerOverflow) &&
+ CGF.getLangOpts().getSignedOverflowBehavior() !=
+ LangOptions::SOB_Trapping) {
+ llvm::AtomicRMWInst::BinOp aop = isInc ? llvm::AtomicRMWInst::Add :
+ llvm::AtomicRMWInst::Sub;
+ llvm::Instruction::BinaryOps op = isInc ? llvm::Instruction::Add :
+ llvm::Instruction::Sub;
+ llvm::Value *amt = CGF.EmitToMemory(
+ llvm::ConstantInt::get(ConvertType(type), 1, true), type);
+ llvm::Value *old = Builder.CreateAtomicRMW(aop,
+ LV.getAddress(), amt, llvm::SequentiallyConsistent);
+ return isPre ? Builder.CreateBinOp(op, old, amt) : old;
+ }
+ value = EmitLoadOfLValue(LV);
+ input = value;
+ // For every other atomic operation, we need to emit a load-op-cmpxchg loop
llvm::BasicBlock *startBB = Builder.GetInsertBlock();
llvm::BasicBlock *opBB = CGF.createBasicBlock("atomic_op", CGF.CurFn);
+ value = CGF.EmitToMemory(value, type);
Builder.CreateBr(opBB);
Builder.SetInsertPoint(opBB);
atomicPHI = Builder.CreatePHI(value->getType(), 2);
atomicPHI->addIncoming(value, startBB);
- type = atomicTy->getValueType();
value = atomicPHI;
+ } else {
+ value = EmitLoadOfLValue(LV);
+ input = value;
}
// Special case of integer increment that we have to check first: bool++.
@@ -1596,7 +1635,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::BasicBlock *opBB = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
llvm::Value *old = Builder.CreateAtomicCmpXchg(LV.getAddress(), atomicPHI,
- value, llvm::SequentiallyConsistent);
+ CGF.EmitToMemory(value, type), llvm::SequentiallyConsistent);
atomicPHI->addIncoming(old, opBB);
llvm::Value *success = Builder.CreateICmpEQ(old, atomicPHI);
Builder.CreateCondBr(success, contBB, opBB);
@@ -1872,20 +1911,63 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
OpInfo.E = E;
// Load/convert the LHS.
LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
- OpInfo.LHS = EmitLoadOfLValue(LHSLV);
llvm::PHINode *atomicPHI = 0;
- if (LHSTy->isAtomicType()) {
+ if (const AtomicType *atomicTy = LHSTy->getAs<AtomicType>()) {
+ QualType type = atomicTy->getValueType();
+ if (!type->isBooleanType() && type->isIntegerType() &&
+ !(type->isUnsignedIntegerType() &&
+ CGF.SanOpts->UnsignedIntegerOverflow) &&
+ CGF.getLangOpts().getSignedOverflowBehavior() !=
+ LangOptions::SOB_Trapping) {
+ llvm::AtomicRMWInst::BinOp aop = llvm::AtomicRMWInst::BAD_BINOP;
+ switch (OpInfo.Opcode) {
+ // We don't have atomicrmw operands for *, %, /, <<, >>
+ case BO_MulAssign: case BO_DivAssign:
+ case BO_RemAssign:
+ case BO_ShlAssign:
+ case BO_ShrAssign:
+ break;
+ case BO_AddAssign:
+ aop = llvm::AtomicRMWInst::Add;
+ break;
+ case BO_SubAssign:
+ aop = llvm::AtomicRMWInst::Sub;
+ break;
+ case BO_AndAssign:
+ aop = llvm::AtomicRMWInst::And;
+ break;
+ case BO_XorAssign:
+ aop = llvm::AtomicRMWInst::Xor;
+ break;
+ case BO_OrAssign:
+ aop = llvm::AtomicRMWInst::Or;
+ break;
+ default:
+ llvm_unreachable("Invalid compound assignment type");
+ }
+ if (aop != llvm::AtomicRMWInst::BAD_BINOP) {
+ llvm::Value *amt = CGF.EmitToMemory(EmitScalarConversion(OpInfo.RHS,
+ E->getRHS()->getType(), LHSTy), LHSTy);
+ Builder.CreateAtomicRMW(aop, LHSLV.getAddress(), amt,
+ llvm::SequentiallyConsistent);
+ return LHSLV;
+ }
+ }
// FIXME: For floating point types, we should be saving and restoring the
// floating point environment in the loop.
llvm::BasicBlock *startBB = Builder.GetInsertBlock();
llvm::BasicBlock *opBB = CGF.createBasicBlock("atomic_op", CGF.CurFn);
+ OpInfo.LHS = EmitLoadOfLValue(LHSLV);
+ OpInfo.LHS = CGF.EmitToMemory(OpInfo.LHS, type);
Builder.CreateBr(opBB);
Builder.SetInsertPoint(opBB);
atomicPHI = Builder.CreatePHI(OpInfo.LHS->getType(), 2);
atomicPHI->addIncoming(OpInfo.LHS, startBB);
OpInfo.LHS = atomicPHI;
}
+ else
+ OpInfo.LHS = EmitLoadOfLValue(LHSLV);
OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy,
E->getComputationLHSType());
@@ -1900,7 +1982,7 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
llvm::BasicBlock *opBB = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
llvm::Value *old = Builder.CreateAtomicCmpXchg(LHSLV.getAddress(), atomicPHI,
- Result, llvm::SequentiallyConsistent);
+ CGF.EmitToMemory(Result, LHSTy), llvm::SequentiallyConsistent);
atomicPHI->addIncoming(old, opBB);
llvm::Value *success = Builder.CreateICmpEQ(old, atomicPHI);
Builder.CreateCondBr(success, contBB, opBB);
@@ -2091,9 +2173,14 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
// Call the handler with the two arguments, the operation, and the size of
// the result.
- llvm::Value *handlerResult = Builder.CreateCall4(handler, lhs, rhs,
- Builder.getInt8(OpID),
- Builder.getInt8(cast<llvm::IntegerType>(opTy)->getBitWidth()));
+ llvm::Value *handlerArgs[] = {
+ lhs,
+ rhs,
+ Builder.getInt8(OpID),
+ Builder.getInt8(cast<llvm::IntegerType>(opTy)->getBitWidth())
+ };
+ llvm::Value *handlerResult =
+ CGF.EmitNounwindRuntimeCall(handler, handlerArgs);
// Truncate the result back to the desired size.
handlerResult = Builder.CreateTrunc(handlerResult, opTy);
@@ -3073,7 +3160,7 @@ Value *ScalarExprEmitter::VisitAtomicExpr(AtomicExpr *E) {
/// EmitScalarExpr - Emit the computation of the specified expression of scalar
/// type, ignoring the result.
Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign) {
- assert(E && !hasAggregateLLVMType(E->getType()) &&
+ assert(E && hasScalarEvaluationKind(E->getType()) &&
"Invalid scalar expression to emit");
if (isa<CXXDefaultArgExpr>(E))
@@ -3089,7 +3176,7 @@ Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign) {
/// specified destination type, both of which are LLVM scalar types.
Value *CodeGenFunction::EmitScalarConversion(Value *Src, QualType SrcTy,
QualType DstTy) {
- assert(!hasAggregateLLVMType(SrcTy) && !hasAggregateLLVMType(DstTy) &&
+ assert(hasScalarEvaluationKind(SrcTy) && hasScalarEvaluationKind(DstTy) &&
"Invalid scalar expression to emit");
return ScalarExprEmitter(*this).EmitScalarConversion(Src, SrcTy, DstTy);
}
@@ -3100,7 +3187,7 @@ Value *CodeGenFunction::EmitScalarConversion(Value *Src, QualType SrcTy,
Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src,
QualType SrcTy,
QualType DstTy) {
- assert(SrcTy->isAnyComplexType() && !hasAggregateLLVMType(DstTy) &&
+ assert(SrcTy->isAnyComplexType() && hasScalarEvaluationKind(DstTy) &&
"Invalid complex -> scalar conversion");
return ScalarExprEmitter(*this).EmitComplexToScalarConversion(Src, SrcTy,
DstTy);
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index b2f5aa3ef1..ad7d62951a 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -70,7 +70,7 @@ CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) {
// messaged (avoids pulling it out of the result type).
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
const ObjCInterfaceDecl *ClassDecl = BoxingMethod->getClassInterface();
- llvm::Value *Receiver = Runtime.GetClass(Builder, ClassDecl);
+ llvm::Value *Receiver = Runtime.GetClass(*this, ClassDecl);
const ParmVarDecl *argDecl = *BoxingMethod->param_begin();
QualType ArgQT = argDecl->getType().getUnqualifiedType();
@@ -163,7 +163,7 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
ObjCInterfaceDecl *Class
= InterfacePointerType->getObjectType()->getInterface();
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
- llvm::Value *Receiver = Runtime.GetClass(Builder, Class);
+ llvm::Value *Receiver = Runtime.GetClass(*this, Class);
// Generate the message send.
RValue result
@@ -191,12 +191,12 @@ llvm::Value *CodeGenFunction::EmitObjCSelectorExpr(const ObjCSelectorExpr *E) {
// Note that this implementation allows for non-constant strings to be passed
// as arguments to @selector(). Currently, the only thing preventing this
// behaviour is the type checking in the front end.
- return CGM.getObjCRuntime().GetSelector(Builder, E->getSelector());
+ return CGM.getObjCRuntime().GetSelector(*this, E->getSelector());
}
llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) {
// FIXME: This should pass the Decl not the name.
- return CGM.getObjCRuntime().GenerateProtocolRef(Builder, E->getProtocol());
+ return CGM.getObjCRuntime().GenerateProtocolRef(*this, E->getProtocol());
}
/// \brief Adjust the type of the result of an Objective-C message send
@@ -310,7 +310,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
assert(ObjTy && "Invalid Objective-C class message send");
OID = ObjTy->getInterface();
assert(OID && "Invalid Objective-C class message send");
- Receiver = Runtime.GetClass(Builder, OID);
+ Receiver = Runtime.GetClass(*this, OID);
isClassMessage = true;
break;
}
@@ -895,16 +895,21 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
QualType ivarType = ivar->getType();
- if (ivarType->isAnyComplexType()) {
- ComplexPairTy pair = LoadComplexFromAddr(LV.getAddress(),
- LV.isVolatileQualified());
- StoreComplexToAddr(pair, ReturnValue, LV.isVolatileQualified());
- } else if (hasAggregateLLVMType(ivarType)) {
+ switch (getEvaluationKind(ivarType)) {
+ case TEK_Complex: {
+ ComplexPairTy pair = EmitLoadOfComplex(LV);
+ EmitStoreOfComplex(pair,
+ MakeNaturalAlignAddrLValue(ReturnValue, ivarType),
+ /*init*/ true);
+ return;
+ }
+ case TEK_Aggregate:
// The return value slot is guaranteed to not be aliased, but
// that's not necessarily the same as "on the stack", so
// we still potentially need objc_memmove_collectable.
EmitAggregateCopy(ReturnValue, LV.getAddress(), ivarType);
- } else {
+ return;
+ case TEK_Scalar: {
llvm::Value *value;
if (propType->isReferenceType()) {
value = LV.getAddress();
@@ -926,8 +931,10 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
}
EmitReturnOfRValue(RValue::get(value), propType);
+ return;
}
- return;
+ }
+ llvm_unreachable("bad evaluation kind");
}
}
@@ -1732,9 +1739,8 @@ static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
if (isa<llvm::ConstantPointerNull>(value)) return value;
if (!fn) {
- std::vector<llvm::Type*> args(1, CGF.Int8PtrTy);
llvm::FunctionType *fnType =
- llvm::FunctionType::get(CGF.Int8PtrTy, args, false);
+ llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
@@ -1743,8 +1749,7 @@ static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
// Call the function.
- llvm::CallInst *call = CGF.Builder.CreateCall(fn, value);
- call->setDoesNotThrow();
+ llvm::CallInst *call = CGF.EmitNounwindRuntimeCall(fn, value);
if (isTailCall)
call->setTailCall();
@@ -1759,9 +1764,8 @@ static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF,
llvm::Constant *&fn,
StringRef fnName) {
if (!fn) {
- std::vector<llvm::Type*> args(1, CGF.Int8PtrPtrTy);
llvm::FunctionType *fnType =
- llvm::FunctionType::get(CGF.Int8PtrTy, args, false);
+ llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrPtrTy, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
@@ -1770,11 +1774,9 @@ static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF,
addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
// Call the function.
- llvm::CallInst *call = CGF.Builder.CreateCall(fn, addr);
- call->setDoesNotThrow();
+ llvm::Value *result = CGF.EmitNounwindRuntimeCall(fn, addr);
// Cast the result back to a dereference of the original type.
- llvm::Value *result = call;
if (origType != CGF.Int8PtrPtrTy)
result = CGF.Builder.CreateBitCast(result,
cast<llvm::PointerType>(origType)->getElementType());
@@ -1803,11 +1805,11 @@ static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF,
llvm::Type *origType = value->getType();
- addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
- value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
-
- llvm::CallInst *result = CGF.Builder.CreateCall2(fn, addr, value);
- result->setDoesNotThrow();
+ llvm::Value *args[] = {
+ CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy),
+ CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy)
+ };
+ llvm::CallInst *result = CGF.EmitNounwindRuntimeCall(fn, args);
if (ignored) return 0;
@@ -1824,17 +1826,18 @@ static void emitARCCopyOperation(CodeGenFunction &CGF,
assert(dst->getType() == src->getType());
if (!fn) {
- std::vector<llvm::Type*> argTypes(2, CGF.Int8PtrPtrTy);
+ llvm::Type *argTypes[] = { CGF.Int8PtrPtrTy, CGF.Int8PtrPtrTy };
+
llvm::FunctionType *fnType
= llvm::FunctionType::get(CGF.Builder.getVoidTy(), argTypes, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
- dst = CGF.Builder.CreateBitCast(dst, CGF.Int8PtrPtrTy);
- src = CGF.Builder.CreateBitCast(src, CGF.Int8PtrPtrTy);
-
- llvm::CallInst *result = CGF.Builder.CreateCall2(fn, dst, src);
- result->setDoesNotThrow();
+ llvm::Value *args[] = {
+ CGF.Builder.CreateBitCast(dst, CGF.Int8PtrPtrTy),
+ CGF.Builder.CreateBitCast(src, CGF.Int8PtrPtrTy)
+ };
+ CGF.EmitNounwindRuntimeCall(fn, args);
}
/// Produce the code to do a retain. Based on the type, calls one of:
@@ -1942,9 +1945,8 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
llvm::Constant *&fn = CGM.getARCEntrypoints().objc_release;
if (!fn) {
- std::vector<llvm::Type*> args(1, Int8PtrTy);
llvm::FunctionType *fnType =
- llvm::FunctionType::get(Builder.getVoidTy(), args, false);
+ llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
fn = createARCRuntimeFunction(CGM, fnType, "objc_release");
}
@@ -1952,8 +1954,7 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
value = Builder.CreateBitCast(value, Int8PtrTy);
// Call objc_release.
- llvm::CallInst *call = Builder.CreateCall(fn, value);
- call->setDoesNotThrow();
+ llvm::CallInst *call = EmitNounwindRuntimeCall(fn, value);
if (!precise) {
SmallVector<llvm::Value*,1> args;
@@ -2000,10 +2001,11 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(llvm::Value *addr,
fn = createARCRuntimeFunction(CGM, fnType, "objc_storeStrong");
}
- addr = Builder.CreateBitCast(addr, Int8PtrPtrTy);
- llvm::Value *castValue = Builder.CreateBitCast(value, Int8PtrTy);
-
- Builder.CreateCall2(fn, addr, castValue)->setDoesNotThrow();
+ llvm::Value *args[] = {
+ Builder.CreateBitCast(addr, Int8PtrPtrTy),
+ Builder.CreateBitCast(value, Int8PtrTy)
+ };
+ EmitNounwindRuntimeCall(fn, args);
if (ignored) return 0;
return value;
@@ -2151,17 +2153,15 @@ void CodeGenFunction::EmitARCInitWeak(llvm::Value *addr, llvm::Value *value) {
void CodeGenFunction::EmitARCDestroyWeak(llvm::Value *addr) {
llvm::Constant *&fn = CGM.getARCEntrypoints().objc_destroyWeak;
if (!fn) {
- std::vector<llvm::Type*> args(1, Int8PtrPtrTy);
llvm::FunctionType *fnType =
- llvm::FunctionType::get(Builder.getVoidTy(), args, false);
+ llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrPtrTy, false);
fn = createARCRuntimeFunction(CGM, fnType, "objc_destroyWeak");
}
// Cast the argument to 'id*'.
addr = Builder.CreateBitCast(addr, Int8PtrPtrTy);
- llvm::CallInst *call = Builder.CreateCall(fn, addr);
- call->setDoesNotThrow();
+ EmitNounwindRuntimeCall(fn, addr);
}
/// void \@objc_moveWeak(i8** %dest, i8** %src)
@@ -2192,10 +2192,7 @@ llvm::Value *CodeGenFunction::EmitObjCAutoreleasePoolPush() {
fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPush");
}
- llvm::CallInst *call = Builder.CreateCall(fn);
- call->setDoesNotThrow();
-
- return call;
+ return EmitNounwindRuntimeCall(fn);
}
/// Produce the code to do a primitive release.
@@ -2205,17 +2202,15 @@ void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) {
llvm::Constant *&fn = CGM.getRREntrypoints().objc_autoreleasePoolPop;
if (!fn) {
- std::vector<llvm::Type*> args(1, Int8PtrTy);
llvm::FunctionType *fnType =
- llvm::FunctionType::get(Builder.getVoidTy(), args, false);
+ llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
// We don't want to use a weak import here; instead we should not
// fall into this path.
fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPop");
}
- llvm::CallInst *call = Builder.CreateCall(fn, value);
- call->setDoesNotThrow();
+ EmitNounwindRuntimeCall(fn, value);
}
/// Produce the code to do an MRR version objc_autoreleasepool_push.
@@ -2225,7 +2220,7 @@ void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) {
///
llvm::Value *CodeGenFunction::EmitObjCMRRAutoreleasePoolPush() {
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
- llvm::Value *Receiver = Runtime.EmitNSAutoreleasePoolClassRef(Builder);
+ llvm::Value *Receiver = Runtime.EmitNSAutoreleasePoolClassRef(*this);
// [NSAutoreleasePool alloc]
IdentifierInfo *II = &CGM.getContext().Idents.get("alloc");
Selector AllocSel = getContext().Selectors.getSelector(0, &II);
@@ -2800,7 +2795,7 @@ void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
/* side effects */ true);
object = Builder.CreateBitCast(object, VoidPtrTy);
- Builder.CreateCall(extender, object)->setDoesNotThrow();
+ EmitNounwindRuntimeCall(extender, object);
}
/// GenerateObjCAtomicSetterCopyHelperFunction - Given a c++ object type with
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 44734dfe99..fbf8a1abb0 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -225,7 +225,7 @@ protected:
/// Returns a property name and encoding string.
llvm::Constant *MakePropertyEncodingString(const ObjCPropertyDecl *PD,
const Decl *Container) {
- ObjCRuntime R = CGM.getLangOpts().ObjCRuntime;
+ const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime;
if ((R.getKind() == ObjCRuntime::GNUstep) &&
(R.getVersion() >= VersionTuple(1, 6))) {
std::string NameAndAttributes;
@@ -236,15 +236,44 @@ protected:
NameAndAttributes += TypeStr;
NameAndAttributes += '\0';
NameAndAttributes += PD->getNameAsString();
+ NameAndAttributes += '\0';
return llvm::ConstantExpr::getGetElementPtr(
CGM.GetAddrOfConstantString(NameAndAttributes), Zeros);
}
return MakeConstantString(PD->getNameAsString());
}
+ /// Push the property attributes into two structure fields.
+ void PushPropertyAttributes(std::vector<llvm::Constant*> &Fields,
+ ObjCPropertyDecl *property, bool isSynthesized=true, bool
+ isDynamic=true) {
+ int attrs = property->getPropertyAttributes();
+ // For read-only properties, clear the copy and retain flags
+ if (attrs & ObjCPropertyDecl::OBJC_PR_readonly) {
+ attrs &= ~ObjCPropertyDecl::OBJC_PR_copy;
+ attrs &= ~ObjCPropertyDecl::OBJC_PR_retain;
+ attrs &= ~ObjCPropertyDecl::OBJC_PR_weak;
+ attrs &= ~ObjCPropertyDecl::OBJC_PR_strong;
+ }
+ // The first flags field has the same attribute values as clang uses internally
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty, attrs & 0xff));
+ attrs >>= 8;
+ attrs <<= 2;
+ // For protocol properties, synthesized and dynamic have no meaning, so we
+ // reuse these flags to indicate that this is a protocol property (both set
+ // has no meaning, as a property can't be both synthesized and dynamic)
+ attrs |= isSynthesized ? (1<<0) : 0;
+ attrs |= isDynamic ? (1<<1) : 0;
+ // The second field is the next four fields left shifted by two, with the
+ // low bit set to indicate whether the field is synthesized or dynamic.
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty, attrs & 0xff));
+ // Two padding fields
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0));
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0));
+ }
/// Ensures that the value has the required type, by inserting a bitcast if
/// required. This function lets us avoid inserting bitcasts that are
/// redundant.
- llvm::Value* EnforceType(CGBuilderTy B, llvm::Value *V, llvm::Type *Ty){
+ llvm::Value* EnforceType(CGBuilderTy &B, llvm::Value *V, llvm::Type *Ty) {
if (V->getType() == Ty) return V;
return B.CreateBitCast(V, Ty);
}
@@ -407,7 +436,7 @@ private:
ArrayRef<llvm::Constant *> MethodTypes);
/// Returns a selector with the specified type encoding. An empty string is
/// used to return an untyped selector (with the types field set to NULL).
- llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
+ llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
const std::string &TypeEncoding, bool lval);
/// Returns the variable used to store the offset of an instance variable.
llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
@@ -417,7 +446,7 @@ private:
protected:
void EmitClassRef(const std::string &className);
/// Emits a pointer to the named class
- virtual llvm::Value *GetClassNamed(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClassNamed(CodeGenFunction &CGF,
const std::string &Name, bool isWeak);
/// Looks up the method for sending a message to the specified object. This
/// mechanism differs between the GCC and GNU runtimes, so this method must be
@@ -470,11 +499,11 @@ public:
bool IsClassMessage,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
- virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *OID);
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
bool lval = false);
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF, const ObjCMethodDecl
*Method);
virtual llvm::Constant *GetEHType(QualType T);
@@ -483,7 +512,7 @@ public:
virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD);
- virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD);
virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
virtual llvm::Function *ModuleInitFunction();
@@ -528,7 +557,7 @@ public:
virtual llvm::Value *EmitIvarOffset(CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
- virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
+ virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF);
virtual llvm::Constant *BuildGCBlockLayout(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
return NULLPtr;
@@ -572,7 +601,7 @@ protected:
llvm::Value *args[] = {
EnforceType(Builder, Receiver, IdTy),
EnforceType(Builder, cmd, SelectorTy) };
- llvm::CallSite imp = CGF.EmitCallOrInvoke(MsgLookupFn, args);
+ llvm::CallSite imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args);
imp->setMetadata(msgSendMDKind, node);
return imp.getInstruction();
}
@@ -582,7 +611,7 @@ protected:
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
PtrToObjCSuperTy), cmd};
- return Builder.CreateCall(MsgLookupSuperFn, lookupArgs);
+ return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs);
}
public:
CGObjCGCC(CodeGenModule &Mod) : CGObjCGNU(Mod, 8, 2) {
@@ -649,7 +678,7 @@ class CGObjCGNUstep : public CGObjCGNU {
EnforceType(Builder, ReceiverPtr, PtrToIdTy),
EnforceType(Builder, cmd, SelectorTy),
EnforceType(Builder, self, IdTy) };
- llvm::CallSite slot = CGF.EmitCallOrInvoke(LookupFn, args);
+ llvm::CallSite slot = CGF.EmitRuntimeCallOrInvoke(LookupFn, args);
slot.setOnlyReadsMemory();
slot->setMetadata(msgSendMDKind, node);
@@ -668,14 +697,15 @@ class CGObjCGNUstep : public CGObjCGNU {
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
- llvm::CallInst *slot = Builder.CreateCall(SlotLookupSuperFn, lookupArgs);
+ llvm::CallInst *slot =
+ CGF.EmitNounwindRuntimeCall(SlotLookupSuperFn, lookupArgs);
slot->setOnlyReadsMemory();
return Builder.CreateLoad(Builder.CreateStructGEP(slot, 4));
}
public:
CGObjCGNUstep(CodeGenModule &Mod) : CGObjCGNU(Mod, 9, 3) {
- ObjCRuntime R = CGM.getLangOpts().ObjCRuntime;
+ const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime;
llvm::StructType *SlotStructTy = llvm::StructType::get(PtrTy,
PtrTy, PtrTy, IntTy, IMPTy, NULL);
@@ -780,7 +810,7 @@ protected:
llvm::Value *args[] = {
EnforceType(Builder, Receiver, IdTy),
EnforceType(Builder, cmd, SelectorTy) };
- llvm::CallSite imp = CGF.EmitCallOrInvoke(MsgLookupFn, args);
+ llvm::CallSite imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args);
imp->setMetadata(msgSendMDKind, node);
return imp.getInstruction();
}
@@ -791,13 +821,13 @@ protected:
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
PtrToObjCSuperTy), cmd};
- return Builder.CreateCall(MsgLookupSuperFn, lookupArgs);
+ return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs);
}
- virtual llvm::Value *GetClassNamed(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClassNamed(CodeGenFunction &CGF,
const std::string &Name, bool isWeak) {
if (isWeak)
- return CGObjCGNU::GetClassNamed(Builder, Name, isWeak);
+ return CGObjCGNU::GetClassNamed(CGF, Name, isWeak);
EmitClassRef(Name);
@@ -977,7 +1007,7 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
}
}
-llvm::Value *CGObjCGNU::GetClassNamed(CGBuilderTy &Builder,
+llvm::Value *CGObjCGNU::GetClassNamed(CodeGenFunction &CGF,
const std::string &Name,
bool isWeak) {
llvm::Value *ClassName = CGM.GetAddrOfConstantCString(Name);
@@ -990,25 +1020,25 @@ llvm::Value *CGObjCGNU::GetClassNamed(CGBuilderTy &Builder,
// with memoized versions or with static references if it's safe to do so.
if (!isWeak)
EmitClassRef(Name);
- ClassName = Builder.CreateStructGEP(ClassName, 0);
+ ClassName = CGF.Builder.CreateStructGEP(ClassName, 0);
llvm::Constant *ClassLookupFn =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, PtrToInt8Ty, true),
"objc_lookup_class");
- return Builder.CreateCall(ClassLookupFn, ClassName);
+ return CGF.EmitNounwindRuntimeCall(ClassLookupFn, ClassName);
}
// This has to perform the lookup every time, since posing and related
// techniques can modify the name -> class mapping.
-llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder,
+llvm::Value *CGObjCGNU::GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *OID) {
- return GetClassNamed(Builder, OID->getNameAsString(), OID->isWeakImported());
+ return GetClassNamed(CGF, OID->getNameAsString(), OID->isWeakImported());
}
-llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
- return GetClassNamed(Builder, "NSAutoreleasePool", false);
+llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
+ return GetClassNamed(CGF, "NSAutoreleasePool", false);
}
-llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel,
+llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel,
const std::string &TypeEncoding, bool lval) {
SmallVector<TypedSelector, 2> &Types = SelectorTable[Sel];
@@ -1031,23 +1061,23 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel,
}
if (lval) {
- llvm::Value *tmp = Builder.CreateAlloca(SelValue->getType());
- Builder.CreateStore(SelValue, tmp);
+ llvm::Value *tmp = CGF.CreateTempAlloca(SelValue->getType());
+ CGF.Builder.CreateStore(SelValue, tmp);
return tmp;
}
return SelValue;
}
-llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel,
+llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel,
bool lval) {
- return GetSelector(Builder, Sel, std::string(), lval);
+ return GetSelector(CGF, Sel, std::string(), lval);
}
-llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
- *Method) {
+llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF,
+ const ObjCMethodDecl *Method) {
std::string SelTypes;
CGM.getContext().getObjCEncodingForMethodDecl(Method, SelTypes);
- return GetSelector(Builder, Method->getSelector(), SelTypes, false);
+ return GetSelector(CGF, Method->getSelector(), SelTypes, false);
}
llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
@@ -1197,7 +1227,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
}
}
- llvm::Value *cmd = GetSelector(Builder, Sel);
+ llvm::Value *cmd = GetSelector(CGF, Sel);
CallArgList ActualArgs;
@@ -1332,9 +1362,9 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
llvm::Value *cmd;
if (Method)
- cmd = GetSelector(Builder, Method);
+ cmd = GetSelector(CGF, Method);
else
- cmd = GetSelector(Builder, Sel);
+ cmd = GetSelector(CGF, Sel);
cmd = EnforceType(Builder, cmd, SelectorTy);
Receiver = EnforceType(Builder, Receiver, IdTy);
@@ -1677,12 +1707,12 @@ llvm::Constant *CGObjCGNU::GenerateProtocolList(ArrayRef<std::string>Protocols){
return MakeGlobal(ProtocolListTy, Elements, ".objc_protocol_list");
}
-llvm::Value *CGObjCGNU::GenerateProtocolRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCGNU::GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD) {
llvm::Value *protocol = ExistingProtocols[PD->getNameAsString()];
llvm::Type *T =
CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType());
- return Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T));
+ return CGF.Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T));
}
llvm::Constant *CGObjCGNU::GenerateEmptyProtocol(
@@ -1786,8 +1816,8 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
// simplify the runtime library by allowing it to use the same data
// structures for protocol metadata everywhere.
llvm::StructType *PropertyMetadataTy = llvm::StructType::get(
- PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty,
- PtrToInt8Ty, NULL);
+ PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty,
+ PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, NULL);
std::vector<llvm::Constant*> Properties;
std::vector<llvm::Constant*> OptionalProperties;
@@ -1799,12 +1829,9 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
std::vector<llvm::Constant*> Fields;
ObjCPropertyDecl *property = *iter;
+ Fields.push_back(MakePropertyEncodingString(property, 0));
+ PushPropertyAttributes(Fields, property);
- Fields.push_back(MakePropertyEncodingString(property, PD));
-
- Fields.push_back(llvm::ConstantInt::get(Int8Ty,
- property->getPropertyAttributes()));
- Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0));
if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) {
std::string TypeStr;
Context.getObjCEncodingForMethodDecl(getter,TypeStr);
@@ -2034,15 +2061,13 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI
SmallVectorImpl<Selector> &InstanceMethodSels,
SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes) {
ASTContext &Context = CGM.getContext();
- //
- // Property metadata: name, attributes, isSynthesized, setter name, setter
- // types, getter name, getter types.
+ // Property metadata: name, attributes, attributes2, padding1, padding2,
+ // setter name, setter types, getter name, getter types.
llvm::StructType *PropertyMetadataTy = llvm::StructType::get(
- PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty,
- PtrToInt8Ty, NULL);
+ PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty,
+ PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, NULL);
std::vector<llvm::Constant*> Properties;
-
// Add all of the property methods need adding to the method list and to the
// property metadata list.
for (ObjCImplDecl::propimpl_iterator
@@ -2053,11 +2078,11 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI
ObjCPropertyImplDecl *propertyImpl = *iter;
bool isSynthesized = (propertyImpl->getPropertyImplementation() ==
ObjCPropertyImplDecl::Synthesize);
+ bool isDynamic = (propertyImpl->getPropertyImplementation() ==
+ ObjCPropertyImplDecl::Dynamic);
Fields.push_back(MakePropertyEncodingString(property, OID));
- Fields.push_back(llvm::ConstantInt::get(Int8Ty,
- property->getPropertyAttributes()));
- Fields.push_back(llvm::ConstantInt::get(Int8Ty, isSynthesized));
+ PushPropertyAttributes(Fields, property, isSynthesized, isDynamic);
if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) {
std::string TypeStr;
Context.getObjCEncodingForMethodDecl(getter,TypeStr);
@@ -2663,7 +2688,7 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
}
ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy);
llvm::CallSite Throw =
- CGF.EmitCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
+ CGF.EmitRuntimeCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
Throw.setDoesNotReturn();
CGF.Builder.CreateUnreachable();
if (ClearInsertionPoint)
@@ -2672,14 +2697,14 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGenFunction &CGF,
llvm::Value *AddrWeakObj) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
AddrWeakObj = EnforceType(B, AddrWeakObj, PtrToIdTy);
return B.CreateCall(WeakReadFn, AddrWeakObj);
}
void CGObjCGNU::EmitObjCWeakAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
src = EnforceType(B, src, IdTy);
dst = EnforceType(B, dst, PtrToIdTy);
B.CreateCall2(WeakAssignFn, src, dst);
@@ -2688,7 +2713,7 @@ void CGObjCGNU::EmitObjCWeakAssign(CodeGenFunction &CGF,
void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
bool threadlocal) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
src = EnforceType(B, src, IdTy);
dst = EnforceType(B, dst, PtrToIdTy);
if (!threadlocal)
@@ -2701,7 +2726,7 @@ void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF,
void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
llvm::Value *ivarOffset) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
src = EnforceType(B, src, IdTy);
dst = EnforceType(B, dst, IdTy);
B.CreateCall3(IvarAssignFn, src, dst, ivarOffset);
@@ -2709,7 +2734,7 @@ void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF,
void CGObjCGNU::EmitObjCStrongCastAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
src = EnforceType(B, src, IdTy);
dst = EnforceType(B, dst, PtrToIdTy);
B.CreateCall2(StrongCastAssignFn, src, dst);
@@ -2719,7 +2744,7 @@ void CGObjCGNU::EmitGCMemmoveCollectable(CodeGenFunction &CGF,
llvm::Value *DestPtr,
llvm::Value *SrcPtr,
llvm::Value *Size) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
DestPtr = EnforceType(B, DestPtr, PtrTy);
SrcPtr = EnforceType(B, SrcPtr, PtrTy);
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index bea30a1367..975f9ac4af 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -1086,13 +1086,13 @@ private:
/// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given class.
- llvm::Value *EmitClassRef(CGBuilderTy &Builder,
+ llvm::Value *EmitClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
- llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
+ llvm::Value *EmitClassRefFromId(CodeGenFunction &CGF,
IdentifierInfo *II);
- llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
+ llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF);
/// EmitSuperClassRef - Emits reference to class's main metadata class.
llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID);
@@ -1170,7 +1170,7 @@ private:
/// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
/// for the given selector.
- llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel,
+ llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel,
bool lval=false);
public:
@@ -1199,15 +1199,15 @@ public:
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
- virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
bool lval = false);
/// The NeXT/Apple runtimes do not support typed selectors; just emit an
/// untyped one.
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
const ObjCMethodDecl *Method);
virtual llvm::Constant *GetEHType(QualType T);
@@ -1218,7 +1218,7 @@ public:
virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) {}
- virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD);
virtual llvm::Constant *GetPropertyGetFunction();
@@ -1370,22 +1370,22 @@ private:
/// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given class reference.
- llvm::Value *EmitClassRef(CGBuilderTy &Builder,
+ llvm::Value *EmitClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
- llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
+ llvm::Value *EmitClassRefFromId(CodeGenFunction &CGF,
IdentifierInfo *II);
- llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
+ llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF);
/// EmitSuperClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given super class reference.
- llvm::Value *EmitSuperClassRef(CGBuilderTy &Builder,
+ llvm::Value *EmitSuperClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
/// EmitMetaClassRef - Return a Value * of the address of _class_t
/// meta-data
- llvm::Value *EmitMetaClassRef(CGBuilderTy &Builder,
+ llvm::Value *EmitMetaClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
/// ObjCIvarOffsetVariable - Returns the ivar offset variable for
@@ -1397,7 +1397,7 @@ private:
/// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
/// for the given selector.
- llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel,
+ llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel,
bool lval=false);
/// GetInterfaceEHType - Get the cached ehtype for the given Objective-C
@@ -1477,18 +1477,18 @@ public:
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
- virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
bool lvalue = false)
- { return EmitSelector(Builder, Sel, lvalue); }
+ { return EmitSelector(CGF, Sel, lvalue); }
/// The NeXT/Apple runtimes do not support typed selectors; just emit an
/// untyped one.
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
const ObjCMethodDecl *Method)
- { return EmitSelector(Builder, Method->getSelector()); }
+ { return EmitSelector(CGF, Method->getSelector()); }
virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
@@ -1496,7 +1496,7 @@ public:
virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) {}
- virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD);
virtual llvm::Constant *GetEHType(QualType T);
@@ -1715,19 +1715,19 @@ CGObjCMac::CGObjCMac(CodeGen::CodeGenModule &cgm) : CGObjCCommonMac(cgm),
/// GetClass - Return a reference to the class for the given interface
/// decl.
-llvm::Value *CGObjCMac::GetClass(CGBuilderTy &Builder,
+llvm::Value *CGObjCMac::GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
- return EmitClassRef(Builder, ID);
+ return EmitClassRef(CGF, ID);
}
/// GetSelector - Return the pointer to the unique'd string for this selector.
-llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, Selector Sel,
+llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, Selector Sel,
bool lval) {
- return EmitSelector(Builder, Sel, lval);
+ return EmitSelector(CGF, Sel, lval);
}
-llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
+llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, const ObjCMethodDecl
*Method) {
- return EmitSelector(Builder, Method->getSelector());
+ return EmitSelector(CGF, Method->getSelector());
}
llvm::Constant *CGObjCMac::GetEHType(QualType T) {
@@ -1810,7 +1810,7 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
// _metaclass_ for the current class, pointed at by
// the class's "isa" pointer. The following assumes that
// isa" is the first ivar in a class (which it must be).
- Target = EmitClassRef(CGF.Builder, Class->getSuperClass());
+ Target = EmitClassRef(CGF, Class->getSuperClass());
Target = CGF.Builder.CreateStructGEP(Target, 0);
Target = CGF.Builder.CreateLoad(Target);
} else {
@@ -1821,7 +1821,7 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
}
}
else if (isCategoryImpl)
- Target = EmitClassRef(CGF.Builder, Class->getSuperClass());
+ Target = EmitClassRef(CGF, Class->getSuperClass());
else {
llvm::Value *ClassPtr = EmitSuperClassRef(Class);
ClassPtr = CGF.Builder.CreateStructGEP(ClassPtr, 1);
@@ -1835,7 +1835,7 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
CGF.Builder.CreateStore(Target,
CGF.Builder.CreateStructGEP(ObjCSuper, 1));
return EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ EmitSelector(CGF, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method, ObjCTypes);
}
@@ -1850,7 +1850,7 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
return EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ EmitSelector(CGF, Sel),
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method, ObjCTypes);
}
@@ -2532,7 +2532,7 @@ llvm::Constant *CGObjCCommonMac::BuildByrefLayout(CodeGen::CodeGenModule &CGM,
return nullPtr;
}
-llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCMac::GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD) {
// FIXME: I don't understand why gcc generates this, or where it is
// resolved. Investigate. Its also wasteful to look this up over and over.
@@ -3511,8 +3511,8 @@ namespace {
FinallyCallExit, FinallyNoCallExit);
CGF.EmitBlock(FinallyCallExit);
- CGF.Builder.CreateCall(ObjCTypes.getExceptionTryExitFn(), ExceptionData)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryExitFn(),
+ ExceptionData);
CGF.EmitBlock(FinallyNoCallExit);
@@ -3538,8 +3538,7 @@ namespace {
// Emit objc_sync_exit(expr); as finally's sole statement for
// @synchronized.
llvm::Value *SyncArg = CGF.Builder.CreateLoad(SyncArgSlot);
- CGF.Builder.CreateCall(ObjCTypes.getSyncExitFn(), SyncArg)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getSyncExitFn(), SyncArg);
}
}
};
@@ -3616,12 +3615,14 @@ FragileHazards::FragileHazards(CodeGenFunction &CGF) : CGF(CGF) {
void FragileHazards::emitWriteHazard() {
if (Locals.empty()) return;
- CGF.Builder.CreateCall(WriteHazard, Locals)->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(WriteHazard, Locals);
}
void FragileHazards::emitReadHazard(CGBuilderTy &Builder) {
assert(!Locals.empty());
- Builder.CreateCall(ReadHazard, Locals)->setDoesNotThrow();
+ llvm::CallInst *call = Builder.CreateCall(ReadHazard, Locals);
+ call->setDoesNotThrow();
+ call->setCallingConv(CGF.getRuntimeCC());
}
/// Emit read hazards in all the protected blocks, i.e. all the blocks
@@ -3826,8 +3827,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::Value *SyncArg =
CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy);
- CGF.Builder.CreateCall(ObjCTypes.getSyncEnterFn(), SyncArg)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getSyncEnterFn(), SyncArg);
SyncArgSlot = CGF.CreateTempAlloca(SyncArg->getType(), "sync.arg");
CGF.Builder.CreateStore(SyncArg, SyncArgSlot);
@@ -3869,8 +3869,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Enter a try block:
// - Call objc_exception_try_enter to push ExceptionData on top of
// the EH stack.
- CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData);
// - Call setjmp on the exception data buffer.
llvm::Constant *Zero = llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0);
@@ -3878,8 +3877,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::Value *SetJmpBuffer =
CGF.Builder.CreateGEP(ExceptionData, GEPIndexes, "setjmp_buffer");
llvm::CallInst *SetJmpResult =
- CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result");
- SetJmpResult->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result");
SetJmpResult->setCanReturnTwice();
// If setjmp returned 0, enter the protected block; otherwise,
@@ -3916,9 +3914,8 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Retrieve the exception object. We may emit multiple blocks but
// nothing can cross this so the value is already in SSA form.
llvm::CallInst *Caught =
- CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData, "caught");
- Caught->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
+ ExceptionData, "caught");
// Push the exception to rethrow onto the EH value stack for the
// benefit of any @throws in the handlers.
@@ -3939,13 +3936,12 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Enter a new exception try block (in case a @catch block
// throws an exception).
- CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(),
+ ExceptionData);
llvm::CallInst *SetJmpResult =
- CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer,
- "setjmp.result");
- SetJmpResult->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getSetJmpFn(),
+ SetJmpBuffer, "setjmp.result");
SetJmpResult->setCanReturnTwice();
llvm::Value *Threw =
@@ -4013,12 +4009,12 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
assert(IDecl && "Catch parameter must have Objective-C type!");
// Check if the @catch block matches the exception object.
- llvm::Value *Class = EmitClassRef(CGF.Builder, IDecl);
+ llvm::Value *Class = EmitClassRef(CGF, IDecl);
+ llvm::Value *matchArgs[] = { Class, Caught };
llvm::CallInst *Match =
- CGF.Builder.CreateCall2(ObjCTypes.getExceptionMatchFn(),
- Class, Caught, "match");
- Match->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionMatchFn(),
+ matchArgs, "match");
llvm::BasicBlock *MatchedBlock = CGF.createBasicBlock("match");
llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch.next");
@@ -4075,9 +4071,8 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// propagating-exception slot.
assert(PropagatingExnVar);
llvm::CallInst *NewCaught =
- CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData, "caught");
- NewCaught->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
+ ExceptionData, "caught");
CGF.Builder.CreateStore(NewCaught, PropagatingExnVar);
// Don't pop the catch handler; the throw already did.
@@ -4108,14 +4103,13 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Otherwise, just look in the buffer for the exception to throw.
} else {
llvm::CallInst *Caught =
- CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData);
- Caught->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
+ ExceptionData);
PropagatingExn = Caught;
}
- CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), PropagatingExn)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionThrowFn(),
+ PropagatingExn);
CGF.Builder.CreateUnreachable();
}
@@ -4137,7 +4131,7 @@ void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
ExceptionAsObject = CGF.ObjCEHValueStack.back();
}
- CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject)
+ CGF.EmitRuntimeCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject)
->setDoesNotReturn();
CGF.Builder.CreateUnreachable();
@@ -4155,8 +4149,9 @@ llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType();
AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj,
ObjCTypes.PtrObjectPtrTy);
- llvm::Value *read_weak = CGF.Builder.CreateCall(ObjCTypes.getGcReadWeakFn(),
- AddrWeakObj, "weakread");
+ llvm::Value *read_weak =
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(),
+ AddrWeakObj, "weakread");
read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
return read_weak;
}
@@ -4176,8 +4171,9 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignWeakFn(),
- src, dst, "weakassign");
+ llvm::Value *args[] = { src, dst };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(),
+ args, "weakassign");
return;
}
@@ -4197,12 +4193,13 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
+ llvm::Value *args[] = { src, dst };
if (!threadlocal)
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(),
- src, dst, "globalassign");
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(),
+ args, "globalassign");
else
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignThreadLocalFn(),
- src, dst, "threadlocalassign");
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignThreadLocalFn(),
+ args, "threadlocalassign");
return;
}
@@ -4223,8 +4220,8 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall3(ObjCTypes.getGcAssignIvarFn(),
- src, dst, ivarOffset);
+ llvm::Value *args[] = { src, dst, ivarOffset };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args);
return;
}
@@ -4243,8 +4240,9 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignStrongCastFn(),
- src, dst, "weakassign");
+ llvm::Value *args[] = { src, dst };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(),
+ args, "weakassign");
return;
}
@@ -4254,9 +4252,8 @@ void CGObjCMac::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
llvm::Value *size) {
SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
- CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(),
- DestPtr, SrcPtr, size);
- return;
+ llvm::Value *args[] = { DestPtr, SrcPtr, size };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args);
}
/// EmitObjCValueForIvar - Code Gen for ivar reference.
@@ -4420,8 +4417,8 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() {
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy);
}
-llvm::Value *CGObjCMac::EmitClassRefFromId(CGBuilderTy &Builder,
- IdentifierInfo *II) {
+llvm::Value *CGObjCMac::EmitClassRefFromId(CodeGenFunction &CGF,
+ IdentifierInfo *II) {
LazySymbols.insert(II);
llvm::GlobalVariable *&Entry = ClassReferences[II];
@@ -4436,20 +4433,20 @@ llvm::Value *CGObjCMac::EmitClassRefFromId(CGBuilderTy &Builder,
4, true);
}
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
}
-llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCMac::EmitClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
- return EmitClassRefFromId(Builder, ID->getIdentifier());
+ return EmitClassRefFromId(CGF, ID->getIdentifier());
}
-llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
+llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
- return EmitClassRefFromId(Builder, II);
+ return EmitClassRefFromId(CGF, II);
}
-llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel,
+llvm::Value *CGObjCMac::EmitSelector(CodeGenFunction &CGF, Selector Sel,
bool lvalue) {
llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
@@ -4466,7 +4463,7 @@ llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel,
if (lvalue)
return Entry;
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
}
llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) {
@@ -5928,7 +5925,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
/// It generates a weak reference to l_OBJC_PROTOCOL_REFERENCE_$_Proto1
/// which will hold address of the protocol meta-data.
///
-llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD) {
// This routine is called for @protocol only. So, we must build definition
@@ -5943,7 +5940,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName);
if (PTGV)
- return Builder.CreateLoad(PTGV);
+ return CGF.Builder.CreateLoad(PTGV);
PTGV = new llvm::GlobalVariable(
CGM.getModule(),
Init->getType(), false,
@@ -5953,7 +5950,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
PTGV->setSection("__DATA, __objc_protorefs, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.AddUsedGlobal(PTGV);
- return Builder.CreateLoad(PTGV);
+ return CGF.Builder.CreateLoad(PTGV);
}
/// GenerateCategory - Build metadata for a category implementation.
@@ -6635,7 +6632,7 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method)
: EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ EmitSelector(CGF, Sel),
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method, ObjCTypes);
}
@@ -6653,7 +6650,7 @@ CGObjCNonFragileABIMac::GetClassGlobal(const std::string &Name) {
return GV;
}
-llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF,
IdentifierInfo *II) {
llvm::GlobalVariable *&Entry = ClassReferences[II];
@@ -6672,22 +6669,22 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder,
CGM.AddUsedGlobal(Entry);
}
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
}
-llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
- return EmitClassRefFromId(Builder, ID->getIdentifier());
+ return EmitClassRefFromId(CGF, ID->getIdentifier());
}
llvm::Value *CGObjCNonFragileABIMac::EmitNSAutoreleasePoolClassRef(
- CGBuilderTy &Builder) {
+ CodeGenFunction &CGF) {
IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
- return EmitClassRefFromId(Builder, II);
+ return EmitClassRefFromId(CGF, II);
}
llvm::Value *
-CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
+CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
llvm::GlobalVariable *&Entry = SuperClassReferences[ID->getIdentifier()];
@@ -6706,17 +6703,17 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
CGM.AddUsedGlobal(Entry);
}
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
}
/// EmitMetaClassRef - Return a Value * of the address of _class_t
/// meta-data
///
-llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()];
if (Entry)
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
std::string MetaClassName(getMetaclassSymbolPrefix() + ID->getNameAsString());
llvm::GlobalVariable *MetaClassGV = GetClassGlobal(MetaClassName);
@@ -6732,12 +6729,12 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
}
/// GetClass - Return a reference to the class for the given interface
/// decl.
-llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
if (ID->isWeakImported()) {
std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
@@ -6745,7 +6742,7 @@ llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder,
ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
}
- return EmitClassRef(Builder, ID);
+ return EmitClassRef(CGF, ID);
}
/// Generates a message send where the super is the receiver. This is
@@ -6776,9 +6773,9 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
// If this is a class message the metaclass is passed as the target.
llvm::Value *Target;
if (IsClassMessage)
- Target = EmitMetaClassRef(CGF.Builder, Class);
+ Target = EmitMetaClassRef(CGF, Class);
else
- Target = EmitSuperClassRef(CGF.Builder, Class);
+ Target = EmitSuperClassRef(CGF, Class);
// FIXME: We shouldn't need to do this cast, rectify the ASTContext and
// ObjCTypes types.
@@ -6793,12 +6790,12 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method)
: EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ EmitSelector(CGF, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method, ObjCTypes);
}
-llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF,
Selector Sel, bool lval) {
llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
@@ -6817,7 +6814,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
if (lval)
return Entry;
- llvm::LoadInst* LI = Builder.CreateLoad(Entry);
+ llvm::LoadInst* LI = CGF.Builder.CreateLoad(Entry);
LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
llvm::MDNode::get(VMContext,
@@ -6841,9 +6838,8 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall3(ObjCTypes.getGcAssignIvarFn(),
- src, dst, ivarOffset);
- return;
+ llvm::Value *args[] = { src, dst, ivarOffset };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args);
}
/// EmitObjCStrongCastAssign - Code gen for assigning to a __strong cast object.
@@ -6862,9 +6858,9 @@ void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignStrongCastFn(),
- src, dst, "weakassign");
- return;
+ llvm::Value *args[] = { src, dst };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(),
+ args, "weakassign");
}
void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable(
@@ -6874,9 +6870,8 @@ void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable(
llvm::Value *Size) {
SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
- CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(),
- DestPtr, SrcPtr, Size);
- return;
+ llvm::Value *args[] = { DestPtr, SrcPtr, Size };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args);
}
/// EmitObjCWeakRead - Code gen for loading value of a __weak
@@ -6888,8 +6883,9 @@ llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead(
llvm::Type* DestTy =
cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType();
AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *read_weak = CGF.Builder.CreateCall(ObjCTypes.getGcReadWeakFn(),
- AddrWeakObj, "weakread");
+ llvm::Value *read_weak =
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(),
+ AddrWeakObj, "weakread");
read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
return read_weak;
}
@@ -6909,9 +6905,9 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignWeakFn(),
- src, dst, "weakassign");
- return;
+ llvm::Value *args[] = { src, dst };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(),
+ args, "weakassign");
}
/// EmitObjCGlobalAssign - Code gen for assigning to a __strong object.
@@ -6930,13 +6926,13 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
+ llvm::Value *args[] = { src, dst };
if (!threadlocal)
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(),
- src, dst, "globalassign");
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(),
+ args, "globalassign");
else
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignThreadLocalFn(),
- src, dst, "threadlocalassign");
- return;
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignThreadLocalFn(),
+ args, "threadlocalassign");
}
void
@@ -6987,10 +6983,10 @@ void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
if (const Expr *ThrowExpr = S.getThrowExpr()) {
llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
Exception = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy);
- CGF.EmitCallOrInvoke(ObjCTypes.getExceptionThrowFn(), Exception)
+ CGF.EmitRuntimeCallOrInvoke(ObjCTypes.getExceptionThrowFn(), Exception)
.setDoesNotReturn();
} else {
- CGF.EmitCallOrInvoke(ObjCTypes.getExceptionRethrowFn())
+ CGF.EmitRuntimeCallOrInvoke(ObjCTypes.getExceptionRethrowFn())
.setDoesNotReturn();
}
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index 85470455af..abd10a29c9 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -163,7 +163,7 @@ namespace {
return;
}
- CGF.EmitCallOrInvoke(Fn);
+ CGF.EmitRuntimeCallOrInvoke(Fn);
}
};
}
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index cbd255d7ff..7f030f2341 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -119,11 +119,11 @@ public:
/// Get a selector for the specified name and type values. The
/// return value should have the LLVM type for pointer-to
/// ASTContext::getObjCSelType().
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
Selector Sel, bool lval=false) = 0;
/// Get a typed selector.
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
const ObjCMethodDecl *Method) = 0;
/// Get the type constant to catch for the given ObjC pointer type.
@@ -179,7 +179,7 @@ public:
/// Emit the code to return the named protocol as an object, as in a
/// \@protocol expression.
- virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *OPD) = 0;
/// Generate the named protocol. Protocols contain method metadata but no
@@ -218,11 +218,11 @@ public:
/// GetClass - Return a reference to the class for the given
/// interface decl.
- virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *OID) = 0;
- virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
+ virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
llvm_unreachable("autoreleasepool unsupported in this ABI");
}
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index a293f1d2e7..9e7ddfbdc1 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -741,7 +741,9 @@ void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
} else if (RV.isAggregate()) {
EmitAggregateCopy(ReturnValue, RV.getAggregateAddr(), Ty);
} else {
- StoreComplexToAddr(RV.getComplexVal(), ReturnValue, false);
+ EmitStoreOfComplex(RV.getComplexVal(),
+ MakeNaturalAlignAddrLValue(ReturnValue, Ty),
+ /*init*/ true);
}
EmitBranchThroughCleanup(ReturnBlock);
}
@@ -788,16 +790,26 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
// rather than the value.
RValue Result = EmitReferenceBindingToExpr(RV, /*InitializedDecl=*/0);
Builder.CreateStore(Result.getScalarVal(), ReturnValue);
- } else if (!hasAggregateLLVMType(RV->getType())) {
- Builder.CreateStore(EmitScalarExpr(RV), ReturnValue);
- } else if (RV->getType()->isAnyComplexType()) {
- EmitComplexExprIntoAddr(RV, ReturnValue, false);
} else {
- CharUnits Alignment = getContext().getTypeAlignInChars(RV->getType());
- EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Alignment, Qualifiers(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased));
+ switch (getEvaluationKind(RV->getType())) {
+ case TEK_Scalar:
+ Builder.CreateStore(EmitScalarExpr(RV), ReturnValue);
+ break;
+ case TEK_Complex:
+ EmitComplexExprIntoLValue(RV,
+ MakeNaturalAlignAddrLValue(ReturnValue, RV->getType()),
+ /*isInit*/ true);
+ break;
+ case TEK_Aggregate: {
+ CharUnits Alignment = getContext().getTypeAlignInChars(RV->getType());
+ EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Alignment,
+ Qualifiers(),
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased));
+ break;
+ }
+ }
}
cleanupScope.ForceCleanup();
@@ -1355,7 +1367,7 @@ CodeGenFunction::EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
std::string &ConstraintStr) {
llvm::Value *Arg;
if (Info.allowsRegister() || !Info.allowsMemory()) {
- if (!CodeGenFunction::hasAggregateLLVMType(InputType)) {
+ if (CodeGenFunction::hasScalarEvaluationKind(InputType)) {
Arg = EmitLoadOfLValue(InputValue).getScalarVal();
} else {
llvm::Type *Ty = ConvertType(InputType);
@@ -1384,7 +1396,7 @@ llvm::Value* CodeGenFunction::EmitAsmInput(
const Expr *InputExpr,
std::string &ConstraintStr) {
if (Info.allowsRegister() || !Info.allowsMemory())
- if (!CodeGenFunction::hasAggregateLLVMType(InputExpr->getType()))
+ if (CodeGenFunction::hasScalarEvaluationKind(InputExpr->getType()))
return EmitScalarExpr(InputExpr);
InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
@@ -1479,7 +1491,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// If this is a register output, then make the inline asm return it
// by-value. If this is a memory result, return the value by-reference.
- if (!Info.allowsMemory() && !hasAggregateLLVMType(OutExpr->getType())) {
+ if (!Info.allowsMemory() && hasScalarEvaluationKind(OutExpr->getType())) {
Constraints += "=" + OutputConstraint;
ResultRegQualTys.push_back(OutExpr->getType());
ResultRegDests.push_back(Dest);
@@ -1647,8 +1659,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
/* IsAlignStack */ false, AsmDialect);
llvm::CallInst *Result = Builder.CreateCall(IA, Args);
Result->addAttribute(llvm::AttributeSet::FunctionIndex,
- llvm::Attribute::get(getLLVMContext(),
- llvm::Attribute::NoUnwind));
+ llvm::Attribute::NoUnwind);
// Slap the source location of the inline asm into a !srcloc metadata on the
// call. FIXME: Handle metadata for MS-style inline asms.
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index b7ddc97a8a..069cd5f9e7 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -361,7 +361,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
ReturnValueSlot Slot;
if (!ResultType->isVoidType() &&
FnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect &&
- hasAggregateLLVMType(CurFnInfo->getReturnType()))
+ !hasScalarEvaluationKind(CurFnInfo->getReturnType()))
Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified());
// Now emit our call.
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index 01dee1f628..6b0c271a08 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -18,11 +18,11 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Type.h"
-#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Value.h"
namespace llvm {
class Constant;
- class Value;
+ class MDNode;
}
namespace clang {
@@ -350,11 +350,23 @@ class AggValueSlot {
/// evaluating an expression which constructs such an object.
bool AliasedFlag : 1;
+ /// ValueOfAtomicFlag - This is set to true if the slot is the value
+ /// subobject of an object the size of an _Atomic(T). The specific
+ /// guarantees this makes are:
+ /// - the address is guaranteed to be a getelementptr into the
+ /// padding struct and
+ /// - it is okay to store something the width of an _Atomic(T)
+ /// into the address.
+ /// Tracking this allows us to avoid some obviously unnecessary
+ /// memcpys.
+ bool ValueOfAtomicFlag : 1;
+
public:
enum IsAliased_t { IsNotAliased, IsAliased };
enum IsDestructed_t { IsNotDestructed, IsDestructed };
enum IsZeroed_t { IsNotZeroed, IsZeroed };
enum NeedsGCBarriers_t { DoesNotNeedGCBarriers, NeedsGCBarriers };
+ enum IsValueOfAtomic_t { IsNotValueOfAtomic, IsValueOfAtomic };
/// ignored - Returns an aggregate value slot indicating that the
/// aggregate value is being ignored.
@@ -378,7 +390,9 @@ public:
IsDestructed_t isDestructed,
NeedsGCBarriers_t needsGC,
IsAliased_t isAliased,
- IsZeroed_t isZeroed = IsNotZeroed) {
+ IsZeroed_t isZeroed = IsNotZeroed,
+ IsValueOfAtomic_t isValueOfAtomic
+ = IsNotValueOfAtomic) {
AggValueSlot AV;
AV.Addr = addr;
AV.Alignment = align.getQuantity();
@@ -387,6 +401,7 @@ public:
AV.ObjCGCFlag = needsGC;
AV.ZeroedFlag = isZeroed;
AV.AliasedFlag = isAliased;
+ AV.ValueOfAtomicFlag = isValueOfAtomic;
return AV;
}
@@ -394,9 +409,12 @@ public:
IsDestructed_t isDestructed,
NeedsGCBarriers_t needsGC,
IsAliased_t isAliased,
- IsZeroed_t isZeroed = IsNotZeroed) {
+ IsZeroed_t isZeroed = IsNotZeroed,
+ IsValueOfAtomic_t isValueOfAtomic
+ = IsNotValueOfAtomic) {
return forAddr(LV.getAddress(), LV.getAlignment(),
- LV.getQuals(), isDestructed, needsGC, isAliased, isZeroed);
+ LV.getQuals(), isDestructed, needsGC, isAliased, isZeroed,
+ isValueOfAtomic);
}
IsDestructed_t isExternallyDestructed() const {
@@ -428,6 +446,12 @@ public:
return Addr;
}
+ IsValueOfAtomic_t isValueOfAtomic() const {
+ return IsValueOfAtomic_t(ValueOfAtomicFlag);
+ }
+
+ llvm::Value *getPaddedAtomicAddr() const;
+
bool isIgnored() const {
return Addr == 0;
}
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 76be85f939..98008ccde6 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -10,6 +10,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangCodeGen
BackendUtil.cpp
+ CGAtomic.cpp
CGBlocks.cpp
CGBuiltin.cpp
CGCall.cpp
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index e2a18d3eb9..27ef65fa94 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -77,45 +77,53 @@ llvm::Type *CodeGenFunction::ConvertType(QualType T) {
return CGM.getTypes().ConvertType(T);
}
-bool CodeGenFunction::hasAggregateLLVMType(QualType type) {
- switch (type.getCanonicalType()->getTypeClass()) {
+TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
+ type = type.getCanonicalType();
+ while (true) {
+ switch (type->getTypeClass()) {
#define TYPE(name, parent)
#define ABSTRACT_TYPE(name, parent)
#define NON_CANONICAL_TYPE(name, parent) case Type::name:
#define DEPENDENT_TYPE(name, parent) case Type::name:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(name, parent) case Type::name:
#include "clang/AST/TypeNodes.def"
- llvm_unreachable("non-canonical or dependent type in IR-generation");
-
- case Type::Builtin:
- case Type::Pointer:
- case Type::BlockPointer:
- case Type::LValueReference:
- case Type::RValueReference:
- case Type::MemberPointer:
- case Type::Vector:
- case Type::ExtVector:
- case Type::FunctionProto:
- case Type::FunctionNoProto:
- case Type::Enum:
- case Type::ObjCObjectPointer:
- return false;
+ llvm_unreachable("non-canonical or dependent type in IR-generation");
- // Complexes, arrays, records, and Objective-C objects.
- case Type::Complex:
- case Type::ConstantArray:
- case Type::IncompleteArray:
- case Type::VariableArray:
- case Type::Record:
- case Type::ObjCObject:
- case Type::ObjCInterface:
- return true;
+ // Various scalar types.
+ case Type::Builtin:
+ case Type::Pointer:
+ case Type::BlockPointer:
+ case Type::LValueReference:
+ case Type::RValueReference:
+ case Type::MemberPointer:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ case Type::Enum:
+ case Type::ObjCObjectPointer:
+ return TEK_Scalar;
+
+ // Complexes.
+ case Type::Complex:
+ return TEK_Complex;
- // In IRGen, atomic types are just the underlying type
- case Type::Atomic:
- return hasAggregateLLVMType(type->getAs<AtomicType>()->getValueType());
+ // Arrays, records, and Objective-C objects.
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::Record:
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ return TEK_Aggregate;
+
+ // We operate on atomic values according to their underlying type.
+ case Type::Atomic:
+ type = cast<AtomicType>(type)->getValueType();
+ continue;
+ }
+ llvm_unreachable("unknown type kind!");
}
- llvm_unreachable("unknown type kind!");
}
void CodeGenFunction::EmitReturnBlock() {
@@ -258,9 +266,12 @@ void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) {
llvm::ConstantInt::get(Int32Ty, 0),
"callsite");
- Builder.CreateCall2(F,
- llvm::ConstantExpr::getBitCast(CurFn, PointerTy),
- CallSite);
+ llvm::Value *args[] = {
+ llvm::ConstantExpr::getBitCast(CurFn, PointerTy),
+ CallSite
+ };
+
+ EmitNounwindRuntimeCall(F, args);
}
void CodeGenFunction::EmitMCountInstrumentation() {
@@ -268,7 +279,7 @@ void CodeGenFunction::EmitMCountInstrumentation() {
llvm::Constant *MCountFn = CGM.CreateRuntimeFunction(FTy,
Target.getMCountName());
- Builder.CreateCall(MCountFn);
+ EmitNounwindRuntimeCall(MCountFn);
}
// OpenCL v1.2 s5.6.4.6 allows the compiler to store kernel argument
@@ -312,6 +323,23 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
if (CGM.getCodeGenOpts().EmitOpenCLArgMetadata)
GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs);
+ if (FD->hasAttr<VecTypeHintAttr>()) {
+ VecTypeHintAttr *attr = FD->getAttr<VecTypeHintAttr>();
+ QualType hintQTy = attr->getTypeHint();
+ const ExtVectorType *hintEltQTy = hintQTy->getAs<ExtVectorType>();
+ bool isSignedInteger =
+ hintQTy->isSignedIntegerType() ||
+ (hintEltQTy && hintEltQTy->getElementType()->isSignedIntegerType());
+ llvm::Value *attrMDArgs[] = {
+ llvm::MDString::get(Context, "vec_type_hint"),
+ llvm::UndefValue::get(CGM.getTypes().ConvertType(attr->getTypeHint())),
+ llvm::ConstantInt::get(
+ llvm::IntegerType::get(Context, 32),
+ llvm::APInt(32, (uint64_t)(isSignedInteger ? 1 : 0)))
+ };
+ kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
+ }
+
if (FD->hasAttr<WorkGroupSizeHintAttr>()) {
WorkGroupSizeHintAttr *attr = FD->getAttr<WorkGroupSizeHintAttr>();
llvm::Value *attrMDArgs[] = {
@@ -392,19 +420,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// Emit subprogram debug descriptor.
if (CGDebugInfo *DI = getDebugInfo()) {
- unsigned NumArgs = 0;
- QualType *ArgsArray = new QualType[Args.size()];
+ SmallVector<QualType, 16> ArgTypes;
for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i) {
- ArgsArray[NumArgs++] = (*i)->getType();
+ ArgTypes.push_back((*i)->getType());
}
QualType FnType =
- getContext().getFunctionType(RetTy, ArgsArray, NumArgs,
+ getContext().getFunctionType(RetTy, ArgTypes,
FunctionProtoType::ExtProtoInfo());
- delete[] ArgsArray;
-
DI->setLocation(StartLoc);
DI->EmitFunctionStart(GD, FnType, CurFn, Builder);
}
@@ -419,7 +444,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// Void type; nothing to return.
ReturnValue = 0;
} else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect &&
- hasAggregateLLVMType(CurFnInfo->getReturnType())) {
+ !hasScalarEvaluationKind(CurFnInfo->getReturnType())) {
// Indirect aggregate return; emit returned value directly into sret slot.
// This reduces code size, and affects correctness in C++.
ReturnValue = CurFn->arg_begin();
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 6cb0b3304e..0155f033e6 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -78,6 +78,17 @@ namespace CodeGen {
class BlockFlags;
class BlockFieldFlags;
+/// The kind of evaluation to perform on values of a particular
+/// type. Basically, is the code in CGExprScalar, CGExprComplex, or
+/// CGExprAgg?
+///
+/// TODO: should vectors maybe be split out into their own thing?
+enum TypeEvaluationKind {
+ TEK_Scalar,
+ TEK_Complex,
+ TEK_Aggregate
+};
+
/// A branch fixup. These are required when emitting a goto to a
/// label which hasn't been emitted yet. The goto is optimistically
/// emitted as a branch to the basic block for the label, and (if it
@@ -796,7 +807,9 @@ public:
class RunCleanupsScope {
EHScopeStack::stable_iterator CleanupStackDepth;
bool OldDidCallStackSave;
+ protected:
bool PerformCleanup;
+ private:
RunCleanupsScope(const RunCleanupsScope &) LLVM_DELETED_FUNCTION;
void operator=(const RunCleanupsScope &) LLVM_DELETED_FUNCTION;
@@ -840,7 +853,6 @@ public:
class LexicalScope: protected RunCleanupsScope {
SourceRange Range;
- bool PopDebugStack;
LexicalScope(const LexicalScope &) LLVM_DELETED_FUNCTION;
void operator=(const LexicalScope &) LLVM_DELETED_FUNCTION;
@@ -848,7 +860,7 @@ public:
public:
/// \brief Enter a new cleanup scope.
explicit LexicalScope(CodeGenFunction &CGF, SourceRange Range)
- : RunCleanupsScope(CGF), Range(Range), PopDebugStack(true) {
+ : RunCleanupsScope(CGF), Range(Range) {
if (CGDebugInfo *DI = CGF.getDebugInfo())
DI->EmitLexicalBlockStart(CGF.Builder, Range.getBegin());
}
@@ -856,20 +868,20 @@ public:
/// \brief Exit this cleanup scope, emitting any accumulated
/// cleanups.
~LexicalScope() {
- if (PopDebugStack) {
- CGDebugInfo *DI = CGF.getDebugInfo();
- if (DI) DI->EmitLexicalBlockEnd(CGF.Builder, Range.getEnd());
- }
+ if (PerformCleanup) endLexicalScope();
}
/// \brief Force the emission of cleanups now, instead of waiting
/// until this object is destroyed.
void ForceCleanup() {
RunCleanupsScope::ForceCleanup();
- if (CGDebugInfo *DI = CGF.getDebugInfo()) {
+ endLexicalScope();
+ }
+
+ private:
+ void endLexicalScope() {
+ if (CGDebugInfo *DI = CGF.getDebugInfo())
DI->EmitLexicalBlockEnd(CGF.Builder, Range.getEnd());
- PopDebugStack = false;
- }
}
};
@@ -1202,6 +1214,9 @@ private:
/// Add a kernel metadata node to the named metadata node 'opencl.kernels'.
/// In the kernel metadata node, reference the kernel function and metadata
/// nodes for its optional attribute qualifiers (OpenCL 1.1 6.7.2):
+ /// - A node for the vec_type_hint(<type>) qualifier contains string
+ /// "vec_type_hint", an undefined value of the <type> data type,
+ /// and a Boolean that is true if the <type> is integer and signed.
/// - A node for the work_group_size_hint(X,Y,Z) qualifier contains string
/// "work_group_size_hint", and three 32-bit integers X, Y and Z.
/// - A node for the reqd_work_group_size(X,Y,Z) qualifier contains string
@@ -1514,7 +1529,15 @@ public:
/// hasAggregateLLVMType - Return true if the specified AST type will map into
/// an aggregate LLVM type or is void.
- static bool hasAggregateLLVMType(QualType T);
+ static TypeEvaluationKind getEvaluationKind(QualType T);
+
+ static bool hasScalarEvaluationKind(QualType T) {
+ return getEvaluationKind(T) == TEK_Scalar;
+ }
+
+ static bool hasAggregateEvaluationKind(QualType T) {
+ return getEvaluationKind(T) == TEK_Aggregate;
+ }
/// createBasicBlock - Create an LLVM basic block.
llvm::BasicBlock *createBasicBlock(const Twine &name = "",
@@ -2127,6 +2150,15 @@ public:
/// that the address will be used to access the object.
LValue EmitCheckedLValue(const Expr *E, TypeCheckKind TCK);
+ RValue convertTempToRValue(llvm::Value *addr, QualType type);
+
+ void EmitAtomicInit(Expr *E, LValue lvalue);
+
+ RValue EmitAtomicLoad(LValue lvalue,
+ AggValueSlot slot = AggValueSlot::ignored());
+
+ void EmitAtomicStore(RValue rvalue, LValue lvalue, bool isInit);
+
/// EmitToMemory - Change a scalar value from its value
/// representation to its in-memory representation.
llvm::Value *EmitToMemory(llvm::Value *Value, QualType Ty);
@@ -2301,11 +2333,29 @@ public:
RValue EmitCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue = ReturnValueSlot());
+ llvm::CallInst *EmitRuntimeCall(llvm::Value *callee,
+ const Twine &name = "");
+ llvm::CallInst *EmitRuntimeCall(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const Twine &name = "");
+ llvm::CallInst *EmitNounwindRuntimeCall(llvm::Value *callee,
+ const Twine &name = "");
+ llvm::CallInst *EmitNounwindRuntimeCall(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const Twine &name = "");
+
llvm::CallSite EmitCallOrInvoke(llvm::Value *Callee,
ArrayRef<llvm::Value *> Args,
const Twine &Name = "");
llvm::CallSite EmitCallOrInvoke(llvm::Value *Callee,
const Twine &Name = "");
+ llvm::CallSite EmitRuntimeCallOrInvoke(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const Twine &name = "");
+ llvm::CallSite EmitRuntimeCallOrInvoke(llvm::Value *callee,
+ const Twine &name = "");
+ void EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args);
llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
llvm::Type *Ty);
@@ -2485,16 +2535,15 @@ public:
bool IgnoreReal = false,
bool IgnoreImag = false);
- /// EmitComplexExprIntoAddr - Emit the computation of the specified expression
- /// of complex type, storing into the specified Value*.
- void EmitComplexExprIntoAddr(const Expr *E, llvm::Value *DestAddr,
- bool DestIsVolatile);
+ /// EmitComplexExprIntoLValue - Emit the given expression of complex
+ /// type and place its result into the specified l-value.
+ void EmitComplexExprIntoLValue(const Expr *E, LValue dest, bool isInit);
+
+ /// EmitStoreOfComplex - Store a complex number into the specified l-value.
+ void EmitStoreOfComplex(ComplexPairTy V, LValue dest, bool isInit);
- /// StoreComplexToAddr - Store a complex number into the specified address.
- void StoreComplexToAddr(ComplexPairTy V, llvm::Value *DestAddr,
- bool DestIsVolatile);
- /// LoadComplexFromAddr - Load a complex number from the specified address.
- ComplexPairTy LoadComplexFromAddr(llvm::Value *SrcAddr, bool SrcIsVolatile);
+ /// EmitLoadOfComplex - Load a complex number from the specified l-value.
+ ComplexPairTy EmitLoadOfComplex(LValue src);
/// CreateStaticVarDecl - Create a zero-initialized LLVM global for
/// a static local variable.
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 2d3b5076b5..402b309f8e 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -107,6 +107,8 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
Int8PtrTy = Int8Ty->getPointerTo(0);
Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
+ RuntimeCC = getTargetCodeGenInfo().getABIInfo().getRuntimeCC();
+
if (LangOpts.ObjC1)
createObjCRuntime();
if (LangOpts.OpenCL)
@@ -617,16 +619,20 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
F->addFnAttr(llvm::Attribute::StackProtectReq);
- // When AddressSanitizer is enabled, set SanitizeAddress attribute
- // unless __attribute__((no_sanitize_address)) is used.
- if (SanOpts.Address && !D->hasAttr<NoSanitizeAddressAttr>())
- F->addFnAttr(llvm::Attribute::SanitizeAddress);
- // Same for ThreadSanitizer and __attribute__((no_sanitize_thread))
- if (SanOpts.Thread && !D->hasAttr<NoSanitizeThreadAttr>())
- F->addFnAttr(llvm::Attribute::SanitizeThread);
- // Same for MemorySanitizer and __attribute__((no_sanitize_memory))
- if (SanOpts.Memory && !D->hasAttr<NoSanitizeMemoryAttr>())
- F->addFnAttr(llvm::Attribute::SanitizeMemory);
+ // Add sanitizer attributes if function is not blacklisted.
+ if (!SanitizerBlacklist.isIn(*F)) {
+ // When AddressSanitizer is enabled, set SanitizeAddress attribute
+ // unless __attribute__((no_sanitize_address)) is used.
+ if (SanOpts.Address && !D->hasAttr<NoSanitizeAddressAttr>())
+ F->addFnAttr(llvm::Attribute::SanitizeAddress);
+ // Same for ThreadSanitizer and __attribute__((no_sanitize_thread))
+ if (SanOpts.Thread && !D->hasAttr<NoSanitizeThreadAttr>()) {
+ F->addFnAttr(llvm::Attribute::SanitizeThread);
+ }
+ // Same for MemorySanitizer and __attribute__((no_sanitize_memory))
+ if (SanOpts.Memory && !D->hasAttr<NoSanitizeMemoryAttr>())
+ F->addFnAttr(llvm::Attribute::SanitizeMemory);
+ }
unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();
if (alignment)
@@ -1354,8 +1360,13 @@ llvm::Constant *
CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy,
StringRef Name,
llvm::AttributeSet ExtraAttrs) {
- return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
- ExtraAttrs);
+ llvm::Constant *C
+ = GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
+ ExtraAttrs);
+ if (llvm::Function *F = dyn_cast<llvm::Function>(C))
+ if (F->empty())
+ F->setCallingConv(getRuntimeCC());
+ return C;
}
/// isTypeConstant - Determine whether an object of this type can be emitted
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index bf9dc255d6..2bddb6f79f 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -28,6 +28,7 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/ValueHandle.h"
#include "llvm/Transforms/Utils/BlackList.h"
@@ -46,6 +47,7 @@ namespace llvm {
namespace clang {
class TargetCodeGenInfo;
class ASTContext;
+ class AtomicType;
class FunctionDecl;
class IdentifierInfo;
class ObjCMethodDecl;
@@ -145,6 +147,11 @@ namespace CodeGen {
unsigned char PointerSizeInBytes;
unsigned char SizeSizeInBytes; // sizeof(size_t)
};
+
+ llvm::CallingConv::ID RuntimeCC;
+ llvm::CallingConv::ID getRuntimeCC() const {
+ return RuntimeCC;
+ }
};
struct RREntrypoints {
@@ -488,6 +495,9 @@ public:
bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor);
+ bool isPaddedAtomicType(QualType type);
+ bool isPaddedAtomicType(const AtomicType *type);
+
static void DecorateInstruction(llvm::Instruction *Inst,
llvm::MDNode *TBAAInfo);
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 259d10673d..8fc78e3de6 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -582,7 +582,21 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
}
case Type::Atomic: {
- ResultType = ConvertType(cast<AtomicType>(Ty)->getValueType());
+ QualType valueType = cast<AtomicType>(Ty)->getValueType();
+ ResultType = ConvertTypeForMem(valueType);
+
+ // Pad out to the inflated size if necessary.
+ uint64_t valueSize = Context.getTypeSize(valueType);
+ uint64_t atomicSize = Context.getTypeSize(Ty);
+ if (valueSize != atomicSize) {
+ assert(valueSize < atomicSize);
+ llvm::Type *elts[] = {
+ ResultType,
+ llvm::ArrayType::get(CGM.Int8Ty, (atomicSize - valueSize) / 8)
+ };
+ ResultType = llvm::StructType::get(getLLVMContext(),
+ llvm::makeArrayRef(elts));
+ }
break;
}
}
@@ -593,6 +607,14 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
return ResultType;
}
+bool CodeGenModule::isPaddedAtomicType(QualType type) {
+ return isPaddedAtomicType(type->castAs<AtomicType>());
+}
+
+bool CodeGenModule::isPaddedAtomicType(const AtomicType *type) {
+ return Context.getTypeSize(type) != Context.getTypeSize(type->getValueType());
+}
+
/// ConvertRecordDeclType - Lay out a tagged decl type like struct or union.
llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) {
// TagDecl's are not necessarily unique, instead use the (clang)
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index c66e3b7426..b314fd6a39 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -1061,8 +1061,8 @@ namespace {
CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
- CGF.Builder.CreateCall(getGuardAbortFn(CGF.CGM, Guard->getType()), Guard)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(getGuardAbortFn(CGF.CGM, Guard->getType()),
+ Guard);
}
};
}
@@ -1181,7 +1181,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
if (threadsafe) {
// Call __cxa_guard_acquire.
llvm::Value *V
- = Builder.CreateCall(getGuardAcquireFn(CGM, guardPtrTy), guard);
+ = CGF.EmitNounwindRuntimeCall(getGuardAcquireFn(CGM, guardPtrTy), guard);
llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
@@ -1202,7 +1202,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
CGF.PopCleanupBlock();
// Call __cxa_guard_release. This cannot throw.
- Builder.CreateCall(getGuardReleaseFn(CGM, guardPtrTy), guard);
+ CGF.EmitNounwindRuntimeCall(getGuardReleaseFn(CGM, guardPtrTy), guard);
} else {
Builder.CreateStore(llvm::ConstantInt::get(guardTy, 1), guard);
}
@@ -1240,7 +1240,7 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
llvm::ConstantExpr::getBitCast(addr, CGF.Int8PtrTy),
handle
};
- CGF.Builder.CreateCall(atexit, args)->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(atexit, args);
}
/// Register a global destructor as best as we know how.
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 6ca2910d79..612e72bdd7 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -37,7 +37,7 @@ static void AssignToArrayRange(CodeGen::CGBuilderTy &Builder,
}
static bool isAggregateTypeForABI(QualType T) {
- return CodeGenFunction::hasAggregateLLVMType(T) ||
+ return !CodeGenFunction::hasScalarEvaluationKind(T) ||
T->isMemberFunctionPointerType();
}
@@ -2965,7 +2965,9 @@ private:
ABIKind Kind;
public:
- ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind) : ABIInfo(CGT), Kind(_Kind) {}
+ ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind) : ABIInfo(CGT), Kind(_Kind) {
+ setRuntimeCC();
+ }
bool isEABI() const {
StringRef Env =
@@ -2987,6 +2989,10 @@ private:
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const;
+
+ llvm::CallingConv::ID getLLVMDefaultCC() const;
+ llvm::CallingConv::ID getABIDefaultCC() const;
+ void setRuntimeCC();
};
class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
@@ -3056,32 +3062,41 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
if (FI.getCallingConvention() != llvm::CallingConv::C)
return;
- // Calling convention as default by an ABI.
- llvm::CallingConv::ID DefaultCC;
+ llvm::CallingConv::ID cc = getRuntimeCC();
+ if (cc != llvm::CallingConv::C)
+ FI.setEffectiveCallingConvention(cc);
+}
+
+/// Return the default calling convention that LLVM will use.
+llvm::CallingConv::ID ARMABIInfo::getLLVMDefaultCC() const {
+ // The default calling convention that LLVM will infer.
if (getContext().getTargetInfo().getTriple().getEnvironmentName()=="gnueabihf")
- DefaultCC = llvm::CallingConv::ARM_AAPCS_VFP;
+ return llvm::CallingConv::ARM_AAPCS_VFP;
else if (isEABI())
- DefaultCC = llvm::CallingConv::ARM_AAPCS;
+ return llvm::CallingConv::ARM_AAPCS;
else
- DefaultCC = llvm::CallingConv::ARM_APCS;
+ return llvm::CallingConv::ARM_APCS;
+}
- // If user did not ask for specific calling convention explicitly (e.g. via
- // pcs attribute), set effective calling convention if it's different than ABI
- // default.
+/// Return the calling convention that our ABI would like us to use
+/// as the C calling convention.
+llvm::CallingConv::ID ARMABIInfo::getABIDefaultCC() const {
switch (getABIKind()) {
- case APCS:
- if (DefaultCC != llvm::CallingConv::ARM_APCS)
- FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_APCS);
- break;
- case AAPCS:
- if (DefaultCC != llvm::CallingConv::ARM_AAPCS)
- FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS);
- break;
- case AAPCS_VFP:
- if (DefaultCC != llvm::CallingConv::ARM_AAPCS_VFP)
- FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP);
- break;
+ case APCS: return llvm::CallingConv::ARM_APCS;
+ case AAPCS: return llvm::CallingConv::ARM_AAPCS;
+ case AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP;
}
+ llvm_unreachable("bad ABI kind");
+}
+
+void ARMABIInfo::setRuntimeCC() {
+ assert(getRuntimeCC() == llvm::CallingConv::C);
+
+ // Don't muddy up the IR with a ton of explicit annotations if
+ // they'd just match what LLVM will infer from the triple.
+ llvm::CallingConv::ID abiCC = getABIDefaultCC();
+ if (abiCC != getLLVMDefaultCC())
+ RuntimeCC = abiCC;
}
/// isHomogeneousAggregate - Return true if a type is an AAPCS-VFP homogeneous
@@ -4017,7 +4032,7 @@ namespace {
class NVPTXABIInfo : public ABIInfo {
public:
- NVPTXABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
+ NVPTXABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) { setRuntimeCC(); }
ABIArgInfo classifyReturnType(QualType RetTy) const;
ABIArgInfo classifyArgumentType(QualType Ty) const;
@@ -4025,6 +4040,8 @@ public:
virtual void computeInfo(CGFunctionInfo &FI) const;
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CFG) const;
+private:
+ void setRuntimeCC();
};
class NVPTXTargetCodeGenInfo : public TargetCodeGenInfo {
@@ -4061,25 +4078,26 @@ void NVPTXABIInfo::computeInfo(CGFunctionInfo &FI) const {
if (FI.getCallingConvention() != llvm::CallingConv::C)
return;
+ FI.setEffectiveCallingConvention(getRuntimeCC());
+}
+
+void NVPTXABIInfo::setRuntimeCC() {
// Calling convention as default by an ABI.
// We're still using the PTX_Kernel/PTX_Device calling conventions here,
// but we should switch to NVVM metadata later on.
- llvm::CallingConv::ID DefaultCC;
const LangOptions &LangOpts = getContext().getLangOpts();
if (LangOpts.OpenCL || LangOpts.CUDA) {
// If we are in OpenCL or CUDA mode, then default to device functions
- DefaultCC = llvm::CallingConv::PTX_Device;
+ RuntimeCC = llvm::CallingConv::PTX_Device;
} else {
// If we are in standard C/C++ mode, use the triple to decide on the default
StringRef Env =
getContext().getTargetInfo().getTriple().getEnvironmentName();
if (Env == "device")
- DefaultCC = llvm::CallingConv::PTX_Device;
+ RuntimeCC = llvm::CallingConv::PTX_Device;
else
- DefaultCC = llvm::CallingConv::PTX_Kernel;
+ RuntimeCC = llvm::CallingConv::PTX_Kernel;
}
- FI.setEffectiveCallingConvention(DefaultCC);
-
}
llvm::Value *NVPTXABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 8229129055..652046fce4 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -1038,17 +1038,17 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// Construct the actions to perform.
ActionList LinkerInputs;
ActionList SplitInputs;
- unsigned NumSteps = 0;
+ llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PL;
for (unsigned i = 0, e = Inputs.size(); i != e; ++i) {
types::ID InputType = Inputs[i].first;
const Arg *InputArg = Inputs[i].second;
- NumSteps = types::getNumCompilationPhases(InputType);
- assert(NumSteps && "Invalid number of steps!");
+ PL.clear();
+ types::getCompilationPhases(InputType, PL);
// If the first step comes after the final phase we are doing as part of
// this compilation, warn the user about it.
- phases::ID InitialPhase = types::getCompilationPhase(InputType, 0);
+ phases::ID InitialPhase = PL[0];
if (InitialPhase > FinalPhase) {
// Claim here to avoid the more general unused warning.
InputArg->claim();
@@ -1083,8 +1083,9 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// Build the pipeline for this file.
OwningPtr<Action> Current(new InputAction(*InputArg, InputType));
- for (unsigned i = 0; i != NumSteps; ++i) {
- phases::ID Phase = types::getCompilationPhase(InputType, i);
+ for (llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases>::iterator
+ i = PL.begin(), e = PL.end(); i != e; ++i) {
+ phases::ID Phase = *i;
// We are done if this step is past what the user requested.
if (Phase > FinalPhase)
@@ -1092,7 +1093,7 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// Queue linker inputs.
if (Phase == phases::Link) {
- assert(i + 1 == NumSteps && "linking must be final compilation step.");
+ assert((i + 1) == e && "linking must be final compilation step.");
LinkerInputs.push_back(Current.take());
break;
}
@@ -1120,7 +1121,7 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// If we are linking, claim any options which are obviously only used for
// compilation.
- if (FinalPhase == phases::Link && (NumSteps == 1))
+ if (FinalPhase == phases::Link && PL.size() == 1)
Args.ClaimAllArgs(options::OPT_CompileOnly_Group);
}
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index 751c9f805e..21015a6c84 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -109,16 +109,17 @@ static const char *getARMTargetCPU(const ArgList &Args,
.Case("armv6j", "arm1136j-s")
.Cases("armv6z", "armv6zk", "arm1176jzf-s")
.Case("armv6t2", "arm1156t2-s")
+ .Cases("armv6m", "armv6-m", "cortex-m0")
.Cases("armv7", "armv7a", "armv7-a", "cortex-a8")
.Cases("armv7l", "armv7-l", "cortex-a8")
.Cases("armv7f", "armv7-f", "cortex-a9-mp")
.Cases("armv7s", "armv7-s", "swift")
- .Cases("armv7r", "armv7-r", "cortex-r4", "cortex-r5")
+ .Cases("armv7r", "armv7-r", "cortex-r4")
.Cases("armv7m", "armv7-m", "cortex-m3")
+ .Cases("armv7em", "armv7e-m", "cortex-m4")
.Case("ep9312", "ep9312")
.Case("iwmmxt", "iwmmxt")
.Case("xscale", "xscale")
- .Cases("armv6m", "armv6-m", "cortex-m0")
// If all else failed, return the most base CPU LLVM supports.
.Default("arm7tdmi");
}
@@ -141,10 +142,12 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) {
.Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
.Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
.Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
- .Cases("cortex-a8", "cortex-a9", "cortex-a15", "v7")
- .Case("cortex-m3", "v7m")
- .Case("cortex-m4", "v7m")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7")
+ .Cases("cortex-a9", "cortex-a15", "v7")
+ .Case("cortex-r5", "v7r")
.Case("cortex-m0", "v6m")
+ .Case("cortex-m3", "v7m")
+ .Case("cortex-m4", "v7em")
.Case("cortex-a9-mp", "v7f")
.Case("swift", "v7s")
.Default("");
@@ -166,7 +169,8 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
// FIXME: Thumb should just be another -target-feaure, not in the triple.
StringRef Suffix =
getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
- bool ThumbDefault = (Suffix.startswith("v7") && getTriple().isOSDarwin());
+ bool ThumbDefault = Suffix.startswith("v6m") ||
+ (Suffix.startswith("v7") && getTriple().isOSDarwin());
std::string ArchName = "arm";
// Assembly files should start in ARM mode.
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index d1072d5a37..035af21975 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -99,15 +99,17 @@ bool Darwin::hasBlocksRuntime() const {
static const char *GetArmArchForMArch(StringRef Value) {
return llvm::StringSwitch<const char*>(Value)
.Case("armv6k", "armv6")
+ .Case("armv6m", "armv6m")
.Case("armv5tej", "armv5")
.Case("xscale", "xscale")
.Case("armv4t", "armv4t")
.Case("armv7", "armv7")
.Cases("armv7a", "armv7-a", "armv7")
.Cases("armv7r", "armv7-r", "armv7")
- .Cases("armv7m", "armv7-m", "armv7")
+ .Cases("armv7em", "armv7e-m", "armv7em")
.Cases("armv7f", "armv7-f", "armv7f")
.Cases("armv7k", "armv7-k", "armv7k")
+ .Cases("armv7m", "armv7-m", "armv7m")
.Cases("armv7s", "armv7-s", "armv7s")
.Default(0);
}
@@ -118,11 +120,12 @@ static const char *GetArmArchForMCpu(StringRef Value) {
.Cases("arm10e", "arm10tdmi", "armv5")
.Cases("arm1020t", "arm1020e", "arm1022e", "arm1026ej-s", "armv5")
.Case("xscale", "xscale")
- .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s",
- "arm1176jzf-s", "cortex-m0", "armv6")
- .Cases("cortex-a8", "cortex-r4", "cortex-m3", "cortex-a9", "cortex-a15",
- "armv7")
+ .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "arm1176jzf-s", "armv6")
+ .Case("cortex-m0", "armv6m")
+ .Cases("cortex-a8", "cortex-r4", "cortex-a9", "cortex-a15", "armv7")
.Case("cortex-a9-mp", "armv7f")
+ .Case("cortex-m3", "armv7m")
+ .Case("cortex-m4", "armv7em")
.Case("swift", "armv7s")
.Default(0);
}
@@ -813,12 +816,18 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
DAL->AddJoinedArg(0, MArch, "xscale");
else if (Name == "armv6")
DAL->AddJoinedArg(0, MArch, "armv6k");
+ else if (Name == "armv6m")
+ DAL->AddJoinedArg(0, MArch, "armv6m");
else if (Name == "armv7")
DAL->AddJoinedArg(0, MArch, "armv7a");
+ else if (Name == "armv7em")
+ DAL->AddJoinedArg(0, MArch, "armv7em");
else if (Name == "armv7f")
DAL->AddJoinedArg(0, MArch, "armv7f");
else if (Name == "armv7k")
DAL->AddJoinedArg(0, MArch, "armv7k");
+ else if (Name == "armv7m")
+ DAL->AddJoinedArg(0, MArch, "armv7m");
else if (Name == "armv7s")
DAL->AddJoinedArg(0, MArch, "armv7s");
@@ -2588,7 +2597,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include");
}
-/// \brief Helper to add the thre variant paths for a libstdc++ installation.
+/// \brief Helper to add the three variant paths for a libstdc++ installation.
/*static*/ bool Linux::addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir,
const ArgList &DriverArgs,
ArgStringList &CC1Args) {
@@ -2600,6 +2609,22 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
return true;
}
+/// \brief Helper to add an extra variant path for an (Ubuntu) multilib
+/// libstdc++ installation.
+/*static*/ bool Linux::addLibStdCXXIncludePaths(Twine Base, Twine Suffix,
+ Twine TargetArchDir,
+ Twine MultiLibSuffix,
+ const ArgList &DriverArgs,
+ ArgStringList &CC1Args) {
+ if (!addLibStdCXXIncludePaths(Base+Suffix, TargetArchDir + MultiLibSuffix,
+ DriverArgs, CC1Args))
+ return false;
+
+ addSystemInclude(DriverArgs, CC1Args, Base + "/" + TargetArchDir + Suffix
+ + MultiLibSuffix);
+ return true;
+}
+
void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
@@ -2627,8 +2652,14 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
StringRef Version = GCCInstallation.getVersion().Text;
StringRef TripleStr = GCCInstallation.getTriple().str();
+ if (addLibStdCXXIncludePaths(LibDir.str() + "/../include",
+ "/c++/" + Version.str(),
+ TripleStr,
+ GCCInstallation.getMultiarchSuffix(),
+ DriverArgs, CC1Args))
+ return;
+
const std::string IncludePathCandidates[] = {
- LibDir.str() + "/../include/c++/" + Version.str(),
// Gentoo is weird and places its headers inside the GCC install, so if the
// first attempt to find the headers fails, try this pattern.
InstallDir.str() + "/include/g++-v4",
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index b313ab610c..0419a375ea 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -297,10 +297,6 @@ public:
return false;
}
- virtual bool IsObjCDefaultSynthPropertiesDefault() const {
- return true;
- }
-
virtual bool IsEncodeExtendedBlockSignatureDefault() const {
return true;
}
@@ -505,6 +501,11 @@ public:
std::vector<std::string> ExtraOpts;
private:
+ static bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix,
+ Twine TargetArchDir,
+ Twine MultiLibSuffix,
+ const ArgList &DriverArgs,
+ ArgStringList &CC1Args);
static bool addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir,
const ArgList &DriverArgs,
ArgStringList &CC1Args);
@@ -564,10 +565,6 @@ public:
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
const ActionList &Inputs) const;
- virtual bool IsObjCDefaultSynthPropertiesDefault() const {
- return true;
- }
-
virtual bool IsIntegratedAssemblerDefault() const;
virtual bool IsUnwindTablesDefault() const;
virtual bool isPICDefault() const;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index eac4bc600f..ef759ff6d3 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -456,11 +456,12 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) {
.Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
.Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
.Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
- .Cases("cortex-a5", "cortex-a8", "cortex-a9", "cortex-a15", "v7")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7")
+ .Cases("cortex-a9", "cortex-a15", "v7")
.Case("cortex-r5", "v7r")
- .Case("cortex-m3", "v7m")
- .Case("cortex-m4", "v7m")
.Case("cortex-m0", "v6m")
+ .Case("cortex-m3", "v7m")
+ .Case("cortex-m4", "v7em")
.Case("cortex-a9-mp", "v7f")
.Case("swift", "v7s")
.Default("");
@@ -516,7 +517,9 @@ static std::string getARMTargetCPU(const ArgList &Args,
.Case("armv6j", "arm1136j-s")
.Cases("armv6z", "armv6zk", "arm1176jzf-s")
.Case("armv6t2", "arm1156t2-s")
+ .Cases("armv6m", "armv6-m", "cortex-m0")
.Cases("armv7", "armv7a", "armv7-a", "cortex-a8")
+ .Cases("armv7em", "armv7e-m", "cortex-m4")
.Cases("armv7f", "armv7-f", "cortex-a9-mp")
.Cases("armv7s", "armv7-s", "swift")
.Cases("armv7r", "armv7-r", "cortex-r4")
@@ -524,7 +527,6 @@ static std::string getARMTargetCPU(const ArgList &Args,
.Case("ep9312", "ep9312")
.Case("iwmmxt", "iwmmxt")
.Case("xscale", "xscale")
- .Cases("armv6m", "armv6-m", "cortex-m0")
// If all else failed, return the most base CPU LLVM supports.
.Default("arm7tdmi");
}
@@ -596,8 +598,9 @@ static void addFPMathArgs(const Driver &D, const Arg *A, const ArgList &Args,
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+neonfp");
- if (CPU != "cortex-a8" && CPU != "cortex-a9" && CPU != "cortex-a9-mp" &&
- CPU != "cortex-a15" && CPU != "cortex-a5")
+ if (CPU != "cortex-a5" && CPU != "cortex-a7" &&
+ CPU != "cortex-a8" && CPU != "cortex-a9" &&
+ CPU != "cortex-a9-mp" && CPU != "cortex-a15")
D.Diag(diag::err_drv_invalid_feature) << "-mfpmath=neon" << CPU;
} else if (FPMath == "vfp" || FPMath == "vfp2" || FPMath == "vfp3" ||
@@ -1426,12 +1429,18 @@ static bool ShouldDisableCFI(const ArgList &Args,
Default);
}
-static bool ShouldDisableDwarfDirectory(const ArgList &Args,
- const ToolChain &TC) {
+static bool ShouldUseIntegratedAssembler(const ArgList &Args,
+ const ToolChain &TC) {
bool IsIADefault = TC.IsIntegratedAssemblerDefault();
bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as,
options::OPT_no_integrated_as,
IsIADefault);
+ return UseIntegratedAs;
+}
+
+static bool ShouldDisableDwarfDirectory(const ArgList &Args,
+ const ToolChain &TC) {
+ bool UseIntegratedAs = ShouldUseIntegratedAssembler(Args, TC);
bool UseDwarfDirectory = Args.hasFlag(options::OPT_fdwarf_directory_asm,
options::OPT_fno_dwarf_directory_asm,
UseIntegratedAs);
@@ -2329,8 +2338,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Output.isFilename()) {
CmdArgs.push_back("-coverage-file");
SmallString<128> CoverageFilename(Output.getFilename());
- if (!C.getArgs().hasArg(options::OPT_no_canonical_prefixes))
- llvm::sys::fs::make_absolute(CoverageFilename);
+ if (llvm::sys::path::is_relative(CoverageFilename.str())) {
+ if (const char *pwd = ::getenv("PWD")) {
+ if (llvm::sys::path::is_absolute(pwd)) {
+ SmallString<128> Pwd(pwd);
+ llvm::sys::path::append(Pwd, CoverageFilename.str());
+ CoverageFilename.swap(Pwd);
+ }
+ }
+ }
CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
}
}
@@ -2768,6 +2784,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fmodules");
HaveModules = true;
}
+
+ if (HaveModules && !ShouldUseIntegratedAssembler(Args, getToolChain())) {
+ D.Diag(diag::err_drv_modules_integrated_as);
+ D.Diag(diag::note_drv_modules_integrated_as);
+ return;
+ }
}
// If a module path was provided, pass it along. Otherwise, use a temporary
@@ -3998,8 +4020,9 @@ llvm::Triple::ArchType darwin::getArchTypeForDarwinArchName(StringRef Str) {
llvm::Triple::x86)
.Case("x86_64", llvm::Triple::x86_64)
// This is derived from the driver driver.
- .Cases("arm", "armv4t", "armv5", "armv6", llvm::Triple::arm)
- .Cases("armv7", "armv7f", "armv7k", "armv7s", "xscale", llvm::Triple::arm)
+ .Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm)
+ .Cases("armv7", "armv7em", "armv7f", "armv7k", "armv7m", llvm::Triple::arm)
+ .Cases("armv7s", "xscale", llvm::Triple::arm)
.Case("r600", llvm::Triple::r600)
.Case("nvptx", llvm::Triple::nvptx)
.Case("nvptx64", llvm::Triple::nvptx64)
@@ -5629,8 +5652,8 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
static void AddLibgcc(llvm::Triple Triple, const Driver &D,
ArgStringList &CmdArgs, const ArgList &Args) {
bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android;
- bool StaticLibgcc = Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_static_libgcc);
+ bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) ||
+ Args.hasArg(options::OPT_static);
if (!D.CCCIsCXX)
CmdArgs.push_back("-lgcc");
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 88574fc2c3..9665095b00 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -179,47 +179,29 @@ types::ID types::lookupTypeForTypeSpecifier(const char *Name) {
}
// FIXME: Why don't we just put this list in the defs file, eh.
-
-unsigned types::getNumCompilationPhases(ID Id) {
- if (Id == TY_Object)
- return 1;
-
- unsigned N = 0;
- if (getPreprocessedType(Id) != TY_INVALID)
- N += 1;
-
- if (onlyAssembleType(Id))
- return N + 2; // assemble, link
- if (onlyPrecompileType(Id))
- return N + 1; // precompile
-
- return N + 3; // compile, assemble, link
-}
-
-phases::ID types::getCompilationPhase(ID Id, unsigned N) {
- assert(N < getNumCompilationPhases(Id) && "Invalid index.");
-
- if (Id == TY_Object)
- return phases::Link;
-
- if (getPreprocessedType(Id) != TY_INVALID) {
- if (N == 0)
- return phases::Preprocess;
- --N;
+void types::getCompilationPhases(
+ ID Id,
+ llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &P) {
+ if (Id != TY_Object) {
+ if (getPreprocessedType(Id) != TY_INVALID) {
+ P.push_back(phases::Preprocess);
+ }
+
+ if (onlyPrecompileType(Id)) {
+ P.push_back(phases::Precompile);
+ } else {
+ if (!onlyAssembleType(Id)) {
+ P.push_back(phases::Compile);
+ }
+ P.push_back(phases::Assemble);
+ }
}
-
- if (onlyAssembleType(Id))
- return N == 0 ? phases::Assemble : phases::Link;
-
- if (onlyPrecompileType(Id))
- return phases::Precompile;
-
- if (N == 0)
- return phases::Compile;
- if (N == 1)
- return phases::Assemble;
-
- return phases::Link;
+ if (!onlyPrecompileType(Id)) {
+ P.push_back(phases::Link);
+ }
+ assert(0 < P.size() && "Not enough phases in list");
+ assert(P.size() <= phases::MaxNumberOfPhases && "Too many phases in list");
+ return;
}
ID types::lookupCXXTypeForCType(ID Id) {
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 4aaae844fc..0e556fe9b2 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -116,20 +116,30 @@ public:
// Align line comments if they are trailing or if they continue other
// trailing comments.
- if (isTrailingComment(Tok) && (Tok.Parent != NULL || !Comments.empty())) {
- if (Style.ColumnLimit >=
- Spaces + WhitespaceStartColumn + Tok.FormatTok.TokenLength) {
- Comments.push_back(StoredComment());
- Comments.back().Tok = Tok.FormatTok;
- Comments.back().Spaces = Spaces;
- Comments.back().NewLines = NewLines;
- if (NewLines == 0)
- Comments.back().MinColumn = WhitespaceStartColumn + Spaces;
- else
- Comments.back().MinColumn = Spaces;
- Comments.back().MaxColumn =
- Style.ColumnLimit - Tok.FormatTok.TokenLength;
- return;
+ if (isTrailingComment(Tok)) {
+ // Remove the comment's trailing whitespace.
+ if (Tok.FormatTok.Tok.getLength() != Tok.FormatTok.TokenLength)
+ Replaces.insert(tooling::Replacement(
+ SourceMgr, Tok.FormatTok.Tok.getLocation().getLocWithOffset(
+ Tok.FormatTok.TokenLength),
+ Tok.FormatTok.Tok.getLength() - Tok.FormatTok.TokenLength, ""));
+
+ // Align comment with other comments.
+ if (Tok.Parent != NULL || !Comments.empty()) {
+ if (Style.ColumnLimit >=
+ Spaces + WhitespaceStartColumn + Tok.FormatTok.TokenLength) {
+ Comments.push_back(StoredComment());
+ Comments.back().Tok = Tok.FormatTok;
+ Comments.back().Spaces = Spaces;
+ Comments.back().NewLines = NewLines;
+ if (NewLines == 0)
+ Comments.back().MinColumn = WhitespaceStartColumn + Spaces;
+ else
+ Comments.back().MinColumn = Spaces;
+ Comments.back().MaxColumn =
+ Style.ColumnLimit - Tok.FormatTok.TokenLength;
+ return;
+ }
}
}
@@ -329,7 +339,8 @@ private:
: Indent(Indent), LastSpace(LastSpace), FirstLessLess(0),
BreakBeforeClosingBrace(false), QuestionColumn(0),
AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
- HasMultiParameterLine(HasMultiParameterLine), ColonPos(0) {}
+ HasMultiParameterLine(HasMultiParameterLine), ColonPos(0),
+ StartOfFunctionCall(0) {}
/// \brief The position to which a specific parenthesis level needs to be
/// indented.
@@ -372,6 +383,9 @@ private:
/// \brief The position of the colon in an ObjC method declaration/call.
unsigned ColonPos;
+ /// \brief The start of the most recent function in a builder-type call.
+ unsigned StartOfFunctionCall;
+
bool operator<(const ParenState &Other) const {
if (Indent != Other.Indent)
return Indent < Other.Indent;
@@ -391,6 +405,8 @@ private:
return HasMultiParameterLine;
if (ColonPos != Other.ColonPos)
return ColonPos < Other.ColonPos;
+ if (StartOfFunctionCall != Other.StartOfFunctionCall)
+ return StartOfFunctionCall < Other.StartOfFunctionCall;
return false;
}
};
@@ -612,9 +628,6 @@ private:
// If this function has multiple parameters, indent nested calls from
// the start of the first parameter.
State.Stack.back().LastSpace = State.Column;
- else if ((Current.is(tok::period) || Current.is(tok::arrow)) &&
- Line.Type == LT_BuilderTypeCall && State.ParenLevel == 0)
- State.Stack.back().LastSpace = State.Column;
}
return moveStateToNextToken(State, DryRun);
@@ -632,6 +645,10 @@ private:
State.Stack.back().FirstLessLess = State.Column;
if (Current.is(tok::question))
State.Stack.back().QuestionColumn = State.Column;
+ if ((Current.is(tok::period) || Current.is(tok::arrow)) &&
+ Line.Type == LT_BuilderTypeCall && State.ParenLevel == 0)
+ State.Stack.back().StartOfFunctionCall =
+ Current.LastInChainOfCalls ? 0 : State.Column;
if (Current.Type == TT_CtorInitializerColon) {
if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
State.Stack.back().AvoidBinPacking = true;
@@ -657,7 +674,8 @@ private:
NewIndent = 2 + State.Stack.back().LastSpace;
AvoidBinPacking = false;
} else {
- NewIndent = 4 + State.Stack.back().LastSpace;
+ NewIndent = 4 + std::max(State.Stack.back().LastSpace,
+ State.Stack.back().StartOfFunctionCall);
AvoidBinPacking =
!Style.BinPackParameters || State.Stack.back().AvoidBinPacking;
}
@@ -711,6 +729,9 @@ private:
bool DryRun) {
if (Current.isNot(tok::string_literal))
return 0;
+ // Only break up default narrow strings.
+ if (StringRef(Current.FormatTok.Tok.getLiteralData()).find('"') != 0)
+ return 0;
unsigned Penalty = 0;
unsigned TailOffset = 0;
@@ -720,8 +741,10 @@ private:
while (StartColumn + TailLength > getColumnLimit()) {
StringRef Text = StringRef(Current.FormatTok.Tok.getLiteralData() +
TailOffset, TailLength);
- StringRef::size_type SplitPoint =
- getSplitPoint(Text, getColumnLimit() - StartColumn - 1);
+ if (StartColumn + OffsetFromStart + 1 > getColumnLimit())
+ break;
+ StringRef::size_type SplitPoint = getSplitPoint(
+ Text, getColumnLimit() - StartColumn - OffsetFromStart - 1);
if (SplitPoint == StringRef::npos)
break;
assert(SplitPoint != 0);
@@ -748,8 +771,67 @@ private:
StringRef::size_type
getSplitPoint(StringRef Text, StringRef::size_type Offset) {
- // FIXME: Implement more sophisticated splitting mechanism, and a fallback.
- return Text.rfind(' ', Offset);
+ StringRef::size_type SpaceOffset = Text.rfind(' ', Offset);
+ if (SpaceOffset != StringRef::npos && SpaceOffset != 0)
+ return SpaceOffset;
+ StringRef::size_type SlashOffset = Text.rfind('/', Offset);
+ if (SlashOffset != StringRef::npos && SlashOffset != 0)
+ return SlashOffset;
+ StringRef::size_type Split = getStartOfCharacter(Text, Offset);
+ if (Split != StringRef::npos && Split > 1)
+ // Do not split at 0.
+ return Split - 1;
+ return StringRef::npos;
+ }
+
+ StringRef::size_type
+ getStartOfCharacter(StringRef Text, StringRef::size_type Offset) {
+ StringRef::size_type NextEscape = Text.find('\\');
+ while (NextEscape != StringRef::npos && NextEscape < Offset) {
+ StringRef::size_type SequenceLength =
+ getEscapeSequenceLength(Text.substr(NextEscape));
+ if (Offset < NextEscape + SequenceLength)
+ return NextEscape;
+ NextEscape = Text.find('\\', NextEscape + SequenceLength);
+ }
+ return Offset;
+ }
+
+ unsigned getEscapeSequenceLength(StringRef Text) {
+ assert(Text[0] == '\\');
+ if (Text.size() < 2)
+ return 1;
+
+ switch (Text[1]) {
+ case 'u':
+ return 6;
+ case 'U':
+ return 10;
+ case 'x':
+ return getHexLength(Text);
+ default:
+ if (Text[1] >= '0' && Text[1] <= '7')
+ return getOctalLength(Text);
+ return 2;
+ }
+ }
+
+ unsigned getHexLength(StringRef Text) {
+ unsigned I = 2; // Point after '\x'.
+ while (I < Text.size() && ((Text[I] >= '0' && Text[I] <= '9') ||
+ (Text[I] >= 'a' && Text[I] <= 'f') ||
+ (Text[I] >= 'A' && Text[I] <= 'F'))) {
+ ++I;
+ }
+ return I;
+ }
+
+ unsigned getOctalLength(StringRef Text) {
+ unsigned I = 1;
+ while (I < Text.size() && I < 4 && (Text[I] >= '0' && Text[I] <= '7')) {
+ ++I;
+ }
+ return I;
}
unsigned getColumnLimit() {
@@ -967,6 +1049,9 @@ public:
// Consume and record whitespace until we find a significant token.
while (FormatTok.Tok.is(tok::unknown)) {
unsigned Newlines = Text.count('\n');
+ if (Newlines > 0)
+ FormatTok.LastNewlineOffset =
+ FormatTok.WhiteSpaceLength + Text.rfind('\n') + 1;
unsigned EscapedNewlines = Text.count("\\\n");
FormatTok.NewlinesBefore += Newlines;
FormatTok.HasUnescapedNewline |= EscapedNewlines != Newlines;
@@ -1007,6 +1092,11 @@ public:
GreaterStashed = true;
}
+ // If we reformat comments, we remove trailing whitespace. Update the length
+ // accordingly.
+ if (FormatTok.Tok.is(tok::comment))
+ FormatTok.TokenLength = Text.rtrim().size();
+
return FormatTok;
}
@@ -1099,7 +1189,15 @@ public:
IndentForLevel.resize(TheLine.Level + 1);
bool WasMoved =
PreviousLineWasTouched && TheLine.First.FormatTok.NewlinesBefore == 0;
- if (TheLine.Type != LT_Invalid && (WasMoved || touchesRanges(TheLine))) {
+ if (TheLine.First.is(tok::eof)) {
+ if (PreviousLineWasTouched) {
+ unsigned NewLines =
+ std::min(TheLine.First.FormatTok.NewlinesBefore, 1u);
+ Whitespaces.replaceWhitespace(TheLine.First, NewLines, /*Indent*/ 0,
+ /*WhitespaceStartColumn*/ 0, Style);
+ }
+ } else if (TheLine.Type != LT_Invalid &&
+ (WasMoved || touchesLine(TheLine))) {
unsigned LevelIndent = getIndent(IndentForLevel, TheLine.Level);
unsigned Indent = LevelIndent;
if (static_cast<int>(Indent) + Offset >= 0)
@@ -1131,7 +1229,7 @@ public:
IndentForLevel[TheLine.Level] = LevelIndent;
// Remove trailing whitespace of the previous line if it was touched.
- if (PreviousLineWasTouched)
+ if (PreviousLineWasTouched || touchesEmptyLineBefore(TheLine))
formatFirstToken(TheLine.First, Indent, TheLine.InPPDirective,
PreviousEndOfLineColumn);
}
@@ -1326,21 +1424,34 @@ private:
}
}
- bool touchesRanges(const AnnotatedLine &TheLine) {
- const FormatToken *First = &TheLine.First.FormatTok;
- const FormatToken *Last = &TheLine.Last->FormatTok;
- CharSourceRange LineRange = CharSourceRange::getTokenRange(
- First->Tok.getLocation(), Last->Tok.getLocation());
+ bool touchesRanges(const CharSourceRange& Range) {
for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
- if (!SourceMgr.isBeforeInTranslationUnit(LineRange.getEnd(),
+ if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),
Ranges[i].getBegin()) &&
!SourceMgr.isBeforeInTranslationUnit(Ranges[i].getEnd(),
- LineRange.getBegin()))
+ Range.getBegin()))
return true;
}
return false;
}
+ bool touchesLine(const AnnotatedLine &TheLine) {
+ const FormatToken *First = &TheLine.First.FormatTok;
+ const FormatToken *Last = &TheLine.Last->FormatTok;
+ CharSourceRange LineRange = CharSourceRange::getTokenRange(
+ First->WhiteSpaceStart.getLocWithOffset(First->LastNewlineOffset),
+ Last->Tok.getLocation());
+ return touchesRanges(LineRange);
+ }
+
+ bool touchesEmptyLineBefore(const AnnotatedLine &TheLine) {
+ const FormatToken *First = &TheLine.First.FormatTok;
+ CharSourceRange LineRange = CharSourceRange::getCharRange(
+ First->WhiteSpaceStart,
+ First->WhiteSpaceStart.getLocWithOffset(First->LastNewlineOffset));
+ return touchesRanges(LineRange);
+ }
+
virtual void consumeUnwrappedLine(const UnwrappedLine &TheLine) {
AnnotatedLines.push_back(AnnotatedLine(TheLine));
}
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 5c17223219..307607aadd 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -73,7 +73,7 @@ static const AnnotatedToken *getNextToken(const AnnotatedToken &Tok) {
/// \brief A parser that gathers additional information about tokens.
///
-/// The \c TokenAnnotator tries to matches parenthesis and square brakets and
+/// The \c TokenAnnotator tries to match parenthesis and square brakets and
/// store a parenthesis levels. It also tries to resolve matching "<" and ">"
/// into template parameter lists.
class AnnotatingParser {
@@ -149,7 +149,7 @@ private:
AnnotatedToken &Prev = *CurrentToken->Parent;
AnnotatedToken &Next = CurrentToken->Children[0];
if (Prev.Parent->is(tok::identifier) &&
- (Prev.is(tok::star) || Prev.is(tok::amp)) &&
+ (Prev.is(tok::star) || Prev.is(tok::amp) || Prev.is(tok::ampamp)) &&
CurrentToken->is(tok::identifier) && Next.isNot(tok::equal)) {
Prev.Type = TT_BinaryOperator;
LookForDecls = false;
@@ -221,9 +221,7 @@ private:
// determineStarAmpUsage() thinks that '*' '[' is allocating an
// array of pointers, but if '[' starts a selector then '*' is a
// binary operator.
- if (Parent != NULL &&
- (Parent->is(tok::star) || Parent->is(tok::amp)) &&
- Parent->Type == TT_PointerOrReference)
+ if (Parent != NULL && Parent->Type == TT_PointerOrReference)
Parent->Type = TT_BinaryOperator;
} else if (StartsObjCArrayLiteral) {
CurrentToken->Type = TT_ObjCArrayLiteral;
@@ -464,6 +462,7 @@ private:
public:
LineType parseLine() {
int PeriodsAndArrows = 0;
+ AnnotatedToken *LastPeriodOrArrow = NULL;
bool CanBeBuilderTypeStmt = true;
if (CurrentToken->is(tok::hash)) {
parsePreprocessorDirective();
@@ -472,8 +471,10 @@ public:
while (CurrentToken != NULL) {
if (CurrentToken->is(tok::kw_virtual))
KeywordVirtualFound = true;
- if (CurrentToken->is(tok::period) || CurrentToken->is(tok::arrow))
+ if (CurrentToken->is(tok::period) || CurrentToken->is(tok::arrow)) {
++PeriodsAndArrows;
+ LastPeriodOrArrow = CurrentToken;
+ }
AnnotatedToken *TheToken = CurrentToken;
if (!consumeToken())
return LT_Invalid;
@@ -485,8 +486,10 @@ public:
return LT_VirtualFunctionDecl;
// Assume a builder-type call if there are 2 or more "." and "->".
- if (PeriodsAndArrows >= 2 && CanBeBuilderTypeStmt)
+ if (PeriodsAndArrows >= 2 && CanBeBuilderTypeStmt) {
+ LastPeriodOrArrow->LastInChainOfCalls = true;
return LT_BuilderTypeCall;
+ }
if (Line.First.Type == TT_ObjCMethodSpecifier) {
if (Contexts.back().FirstObjCSelectorName != NULL)
@@ -581,7 +584,8 @@ private:
Current.Parent->Type == TT_PointerOrReference ||
Current.Parent->Type == TT_TemplateCloser)) {
Current.Type = TT_StartOfName;
- } else if (Current.is(tok::star) || Current.is(tok::amp)) {
+ } else if (Current.is(tok::star) || Current.is(tok::amp) ||
+ Current.is(tok::ampamp)) {
Current.Type =
determineStarAmpUsage(Current, Contexts.back().IsExpression);
} else if (Current.is(tok::minus) || Current.is(tok::plus) ||
@@ -640,6 +644,9 @@ private:
if (NextToken == NULL)
return TT_Unknown;
+ if (PrevToken->is(tok::l_paren) && !IsExpression)
+ return TT_PointerOrReference;
+
if (PrevToken->is(tok::l_paren) || PrevToken->is(tok::l_square) ||
PrevToken->is(tok::l_brace) || PrevToken->is(tok::comma) ||
PrevToken->is(tok::kw_return) || PrevToken->is(tok::colon) ||
@@ -880,8 +887,6 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
else
return 100;
}
- if (Left.is(tok::l_brace) && Right.isNot(tok::l_brace))
- return 50;
if (Left.is(tok::equal) && Right.is(tok::l_brace))
return 150;
if (Left.is(tok::coloncolon))
@@ -917,7 +922,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
return 20;
if (Left.is(tok::l_paren) || Left.is(tok::l_square) ||
- Left.Type == TT_TemplateOpener)
+ Left.is(tok::l_brace) || Left.Type == TT_TemplateOpener)
return 20;
if (Right.is(tok::lessless)) {
@@ -936,7 +941,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Level != prec::Unknown)
return Level;
-
+
return 3;
}
@@ -970,14 +975,13 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
Left.isNot(tok::l_paren);
if (Left.is(tok::less) || Right.is(tok::greater) || Right.is(tok::less))
return false;
- if (Right.is(tok::amp) || Right.is(tok::star))
+ if (Right.Type == TT_PointerOrReference)
return Left.FormatTok.Tok.isLiteral() ||
- (Left.isNot(tok::star) && Left.isNot(tok::amp) &&
- Left.isNot(tok::l_paren) && !Style.PointerBindsToType);
- if (Left.is(tok::amp) || Left.is(tok::star))
+ ((Left.Type != TT_PointerOrReference) && Left.isNot(tok::l_paren) &&
+ !Style.PointerBindsToType);
+ if (Left.Type == TT_PointerOrReference)
return Right.FormatTok.Tok.isLiteral() ||
- (Right.isNot(tok::star) && Right.isNot(tok::amp) &&
- Style.PointerBindsToType);
+ ((Right.Type != TT_PointerOrReference) && Style.PointerBindsToType);
if (Right.is(tok::star) && Left.is(tok::l_paren))
return false;
if (Left.is(tok::l_square))
@@ -1036,8 +1040,14 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Tok.Type == TT_OverloadedOperatorLParen)
return false;
if (Tok.is(tok::colon))
- return Line.First.isNot(tok::kw_case) && !Tok.Children.empty() &&
+ return Line.First.isNot(tok::kw_case) &&
+ Line.First.isNot(tok::kw_default) && !Tok.Children.empty() &&
Tok.Type != TT_ObjCMethodExpr;
+ if (Tok.is(tok::l_paren) && !Tok.Children.empty() &&
+ Tok.Children[0].Type == TT_PointerOrReference &&
+ !Tok.Children[0].Children.empty() &&
+ Tok.Children[0].Children[0].isNot(tok::r_paren))
+ return true;
if (Tok.Parent->Type == TT_UnaryOperator || Tok.Parent->Type == TT_CastRParen)
return false;
if (Tok.Type == TT_UnaryOperator)
@@ -1092,6 +1102,9 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return false;
if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl)
return false;
+ if (Left.is(tok::l_paren) && Right.is(tok::l_paren) && Left.Parent &&
+ Left.Parent->is(tok::kw___attribute))
+ return false;
if (Right.Type == TT_LineComment)
// We rely on MustBreakBefore being set correctly here as we should not
@@ -1120,7 +1133,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
Right.is(tok::colon) || Left.is(tok::coloncolon) ||
Left.is(tok::semi) || Left.is(tok::l_brace) ||
(Left.is(tok::r_paren) && Left.Type != TT_CastRParen &&
- Right.is(tok::identifier)) ||
+ (Right.is(tok::identifier) || Right.is(tok::kw___attribute))) ||
(Left.is(tok::l_paren) && !Right.is(tok::r_paren)) ||
(Left.is(tok::l_square) && !Right.is(tok::r_square));
}
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
index aa78779f9b..b79ee97da8 100644
--- a/lib/Format/TokenAnnotator.h
+++ b/lib/Format/TokenAnnotator.h
@@ -75,7 +75,7 @@ public:
ClosesTemplateDeclaration(false), MatchingParen(NULL),
ParameterCount(0), BindingStrength(0), SplitPenalty(0),
LongestObjCSelectorName(0), Parent(NULL), FakeLParens(0),
- FakeRParens(0) {
+ FakeRParens(0), LastInChainOfCalls(false) {
}
bool is(tok::TokenKind Kind) const { return FormatTok.Tok.is(Kind); }
@@ -127,6 +127,9 @@ public:
/// \brief Insert this many fake ) after this token for correct indentation.
unsigned FakeRParens;
+ /// \brief Is this the last "." or "->" in a builder-type call?
+ bool LastInChainOfCalls;
+
const AnnotatedToken *getPreviousNoneComment() const {
AnnotatedToken *Tok = Parent;
while (Tok != NULL && Tok->is(tok::comment))
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index 28522a3e32..cdd77759fd 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -138,6 +138,11 @@ bool UnwrappedLineParser::parse() {
I != E; ++I) {
Callback.consumeUnwrappedLine(*I);
}
+
+ // Create line with eof token.
+ pushToken(FormatTok);
+ Callback.consumeUnwrappedLine(*Line);
+
return Error;
}
@@ -776,14 +781,14 @@ void UnwrappedLineParser::addUnwrappedLine() {
CurrentLines->push_back(*Line);
Line->Tokens.clear();
if (CurrentLines == &Lines && !PreprocessorDirectives.empty()) {
- for (std::vector<UnwrappedLine>::iterator I = PreprocessorDirectives
- .begin(), E = PreprocessorDirectives.end();
+ for (std::vector<UnwrappedLine>::iterator
+ I = PreprocessorDirectives.begin(),
+ E = PreprocessorDirectives.end();
I != E; ++I) {
CurrentLines->push_back(*I);
}
PreprocessorDirectives.clear();
}
-
}
bool UnwrappedLineParser::eof() const {
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index 5db5e7ba21..f4fecc5ef0 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -33,8 +33,8 @@ namespace format {
struct FormatToken {
FormatToken()
: NewlinesBefore(0), HasUnescapedNewline(false), WhiteSpaceLength(0),
- TokenLength(0), IsFirst(false), MustBreakBefore(false) {
- }
+ LastNewlineOffset(0), TokenLength(0), IsFirst(false),
+ MustBreakBefore(false) {}
/// \brief The \c Token.
Token Tok;
@@ -59,6 +59,10 @@ struct FormatToken {
/// the \c Token.
unsigned WhiteSpaceLength;
+ /// \brief The offset just past the last '\n' in this token's leading
+ /// whitespace (relative to \c WhiteSpaceStart). 0 if there is no '\n'.
+ unsigned LastNewlineOffset;
+
/// \brief The length of the non-whitespace parts of the token. This is
/// necessary because we need to handle escaped newlines that are stored
/// with the token.
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 3dc6e2e607..4a956ff3ab 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -1711,6 +1711,15 @@ StringRef ASTUnit::getMainFileName() const {
return StringRef();
}
+StringRef ASTUnit::getASTFileName() const {
+ if (!isMainFileAST())
+ return StringRef();
+
+ serialization::ModuleFile &
+ Mod = Reader->getModuleManager().getPrimaryModule();
+ return Mod.FileName;
+}
+
ASTUnit *ASTUnit::create(CompilerInvocation *CI,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
bool CaptureDiagnostics,
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index d856c31a05..3c5954a696 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -380,12 +380,31 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
Opts.SanitizeRecover = !Args.hasArg(OPT_fno_sanitize_recover);
- Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
- Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data);
Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes);
- Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info);
+ if (Opts.EmitGcovArcs || Opts.EmitGcovNotes) {
Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file);
+ Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum);
+ Opts.CoverageFunctionNamesInData =
+ Args.hasArg(OPT_coverage_function_names_in_data);
+ if (Args.hasArg(OPT_coverage_version_EQ)) {
+ StringRef CoverageVersion = Args.getLastArgValue(OPT_coverage_version_EQ);
+ if (CoverageVersion.size() != 4) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_coverage_version_EQ)->getAsString(Args)
+ << CoverageVersion;
+ } else {
+ Opts.CoverageVersion[0] = CoverageVersion[3];
+ Opts.CoverageVersion[1] = CoverageVersion[2];
+ Opts.CoverageVersion[2] = CoverageVersion[1];
+ Opts.CoverageVersion[3] = CoverageVersion[0];
+ }
+ }
+ }
+
+ Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
+ Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
+ Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info);
Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
Opts.LinkBitcodeFile = Args.getLastArgValue(OPT_mlink_bitcode_file);
Opts.SanitizerBlacklistFile = Args.getLastArgValue(OPT_fsanitize_blacklist);
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 58bbfd3f8a..d894939b4b 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -515,6 +515,9 @@ struct UnknownPragmaHandler : public PragmaHandler {
static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
PrintPPOutputPPCallbacks *Callbacks,
raw_ostream &OS) {
+ bool DropComments = PP.getLangOpts().TraditionalCPP &&
+ !PP.getCommentRetentionState();
+
char Buffer[256];
Token PrevPrevTok, PrevTok;
PrevPrevTok.startToken();
@@ -537,7 +540,13 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
OS << ' ';
}
- if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
+ if (DropComments && Tok.is(tok::comment)) {
+ // Skip comments. Normally the preprocessor does not generate
+ // tok::comment nodes at all when not keeping comments, but under
+ // -traditional-cpp the lexer keeps /all/ whitespace, including comments.
+ SourceLocation StartLoc = Tok.getLocation();
+ Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength()));
+ } else if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
OS << II->getName();
} else if (Tok.isLiteral() && !Tok.needsCleaning() &&
Tok.getLiteralData()) {
diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h
index c243676a2f..74ce08aa6f 100644
--- a/lib/Headers/altivec.h
+++ b/lib/Headers/altivec.h
@@ -1923,43 +1923,43 @@ vec_lvx(int __a, const float *__b)
/* vec_lde */
static vector signed char __ATTRS_o_ai
-vec_lde(int __a, const vector signed char *__b)
+vec_lde(int __a, const signed char *__b)
{
return (vector signed char)__builtin_altivec_lvebx(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lde(int __a, const vector unsigned char *__b)
+vec_lde(int __a, const unsigned char *__b)
{
return (vector unsigned char)__builtin_altivec_lvebx(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_lde(int __a, const vector short *__b)
+vec_lde(int __a, const short *__b)
{
return (vector short)__builtin_altivec_lvehx(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_lde(int __a, const vector unsigned short *__b)
+vec_lde(int __a, const unsigned short *__b)
{
return (vector unsigned short)__builtin_altivec_lvehx(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_lde(int __a, const vector int *__b)
+vec_lde(int __a, const int *__b)
{
return (vector int)__builtin_altivec_lvewx(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_lde(int __a, const vector unsigned int *__b)
+vec_lde(int __a, const unsigned int *__b)
{
return (vector unsigned int)__builtin_altivec_lvewx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_lde(int __a, const vector float *__b)
+vec_lde(int __a, const float *__b)
{
return (vector float)__builtin_altivec_lvewx(__a, __b);
}
@@ -1967,13 +1967,13 @@ vec_lde(int __a, const vector float *__b)
/* vec_lvebx */
static vector signed char __ATTRS_o_ai
-vec_lvebx(int __a, const vector signed char *__b)
+vec_lvebx(int __a, const signed char *__b)
{
return (vector signed char)__builtin_altivec_lvebx(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvebx(int __a, const vector unsigned char *__b)
+vec_lvebx(int __a, const unsigned char *__b)
{
return (vector unsigned char)__builtin_altivec_lvebx(__a, __b);
}
@@ -1981,13 +1981,13 @@ vec_lvebx(int __a, const vector unsigned char *__b)
/* vec_lvehx */
static vector short __ATTRS_o_ai
-vec_lvehx(int __a, const vector short *__b)
+vec_lvehx(int __a, const short *__b)
{
return (vector short)__builtin_altivec_lvehx(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_lvehx(int __a, const vector unsigned short *__b)
+vec_lvehx(int __a, const unsigned short *__b)
{
return (vector unsigned short)__builtin_altivec_lvehx(__a, __b);
}
@@ -1995,19 +1995,19 @@ vec_lvehx(int __a, const vector unsigned short *__b)
/* vec_lvewx */
static vector int __ATTRS_o_ai
-vec_lvewx(int __a, const vector int *__b)
+vec_lvewx(int __a, const int *__b)
{
return (vector int)__builtin_altivec_lvewx(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_lvewx(int __a, const vector unsigned int *__b)
+vec_lvewx(int __a, const unsigned int *__b)
{
return (vector unsigned int)__builtin_altivec_lvewx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_lvewx(int __a, const vector float *__b)
+vec_lvewx(int __a, const float *__b)
{
return (vector float)__builtin_altivec_lvewx(__a, __b);
}
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 3b6c5ccde4..d4d14e8745 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -266,10 +266,6 @@ const FileEntry *DirectoryLookup::LookupFile(
return Result;
}
-/// FIXME: HACK HACK HACK!
-static llvm::DenseMap<const DirectoryEntry *, const DirectoryEntry *>
- TopFrameworkDirs;
-
/// \brief Given a framework directory, find the top-most framework directory.
///
/// \param FileMgr The file manager to use for directory lookups.
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 65ea5e3996..ed4666aa21 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -1630,7 +1630,9 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr,
(Kind == tok::utf8_string_literal ||
Kind == tok::utf16_string_literal ||
Kind == tok::utf32_string_literal))
- Diag(BufferPtr, diag::warn_cxx98_compat_unicode_literal);
+ Diag(BufferPtr, getLangOpts().CPlusPlus
+ ? diag::warn_cxx98_compat_unicode_literal
+ : diag::warn_c99_compat_unicode_literal);
char C = getAndAdvanceChar(CurPtr, Result);
while (C != '"') {
@@ -1795,7 +1797,9 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
if (!isLexingRawMode() &&
(Kind == tok::utf16_char_constant || Kind == tok::utf32_char_constant))
- Diag(BufferPtr, diag::warn_cxx98_compat_unicode_literal);
+ Diag(BufferPtr, getLangOpts().CPlusPlus
+ ? diag::warn_cxx98_compat_unicode_literal
+ : diag::warn_c99_compat_unicode_literal);
char C = getAndAdvanceChar(CurPtr, Result);
if (C == '\'') {
@@ -2848,11 +2852,11 @@ LexNextToken:
MIOpt.ReadToken();
return LexNumericConstant(Result, CurPtr);
- case 'u': // Identifier (uber) or C++0x UTF-8 or UTF-16 string literal
+ case 'u': // Identifier (uber) or C11/C++11 UTF-8 or UTF-16 string literal
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();
- if (LangOpts.CPlusPlus11) {
+ if (LangOpts.CPlusPlus11 || LangOpts.C11) {
Char = getCharAndSize(CurPtr, SizeTmp);
// UTF-16 string literal
@@ -2866,7 +2870,8 @@ LexNextToken:
tok::utf16_char_constant);
// UTF-16 raw string literal
- if (Char == 'R' && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
+ if (Char == 'R' && LangOpts.CPlusPlus11 &&
+ getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
@@ -2882,7 +2887,7 @@ LexNextToken:
SizeTmp2, Result),
tok::utf8_string_literal);
- if (Char2 == 'R') {
+ if (Char2 == 'R' && LangOpts.CPlusPlus11) {
unsigned SizeTmp3;
char Char3 = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3);
// UTF-8 raw string literal
@@ -2900,11 +2905,11 @@ LexNextToken:
// treat u like the start of an identifier.
return LexIdentifier(Result, CurPtr);
- case 'U': // Identifier (Uber) or C++0x UTF-32 string literal
+ case 'U': // Identifier (Uber) or C11/C++11 UTF-32 string literal
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();
- if (LangOpts.CPlusPlus11) {
+ if (LangOpts.CPlusPlus11 || LangOpts.C11) {
Char = getCharAndSize(CurPtr, SizeTmp);
// UTF-32 string literal
@@ -2918,7 +2923,8 @@ LexNextToken:
tok::utf32_char_constant);
// UTF-32 raw string literal
- if (Char == 'R' && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
+ if (Char == 'R' && LangOpts.CPlusPlus11 &&
+ getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
@@ -3121,10 +3127,13 @@ LexNextToken:
// this as "foo / bar" and langauges with Line comments would lex it as
// "foo". Check to see if the character after the second slash is a '*'.
// If so, we will lex that as a "/" instead of the start of a comment.
- // However, we never do this in -traditional-cpp mode.
- if ((LangOpts.LineComment ||
- getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') &&
- !LangOpts.TraditionalCPP) {
+ // However, we never do this if we are just preprocessing.
+ bool TreatAsComment = LangOpts.LineComment && !LangOpts.TraditionalCPP;
+ if (!TreatAsComment)
+ if (!(PP && PP->isPreprocessedOutput()))
+ TreatAsComment = getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*';
+
+ if (TreatAsComment) {
if (SkipLineComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
return; // There is a token to return.
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index e36596f2af..f6e781a936 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -215,15 +215,11 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
// If this is a string or character constant, escape the token as specified
// by 6.10.3.2p2.
- if (Tok.is(tok::string_literal) || // "foo"
- Tok.is(tok::wide_string_literal) || // L"foo"
- Tok.is(tok::utf8_string_literal) || // u8"foo"
- Tok.is(tok::utf16_string_literal) || // u"foo"
- Tok.is(tok::utf32_string_literal) || // U"foo"
- Tok.is(tok::char_constant) || // 'x'
- Tok.is(tok::wide_char_constant) || // L'x'.
- Tok.is(tok::utf16_char_constant) || // u'x'.
- Tok.is(tok::utf32_char_constant)) { // U'x'.
+ if (tok::isStringLiteral(Tok.getKind()) || // "foo", u8R"x(foo)x"_bar, etc.
+ Tok.is(tok::char_constant) || // 'x'
+ Tok.is(tok::wide_char_constant) || // L'x'.
+ Tok.is(tok::utf16_char_constant) || // u'x'.
+ Tok.is(tok::utf32_char_constant)) { // U'x'.
bool Invalid = false;
std::string TokStr = PP.getSpelling(Tok, &Invalid);
if (!Invalid) {
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 07f24c8200..8379ca8719 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -143,15 +143,14 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
// Fall through on error.
} else if (isDefineUndef && II->getPPKeywordID() == tok::pp_defined) {
- // Error if defining "defined": C99 6.10.8.4.
+ // Error if defining "defined": C99 6.10.8/4, C++ [cpp.predefined]p4.
Diag(MacroNameTok, diag::err_defined_macro_name);
- } else if (isDefineUndef && II->hasMacroDefinition() &&
+ } else if (isDefineUndef == 2 && II->hasMacroDefinition() &&
getMacroInfo(II)->isBuiltinMacro()) {
- // Error if defining "__LINE__" and other builtins: C99 6.10.8.4.
- if (isDefineUndef == 1)
- Diag(MacroNameTok, diag::pp_redef_builtin_macro);
- else
- Diag(MacroNameTok, diag::pp_undef_builtin_macro);
+ // Warn if undefining "__LINE__" and other builtins, per C99 6.10.8/4
+ // and C++ [cpp.predefined]p4], but allow it as an extension.
+ Diag(MacroNameTok, diag::ext_pp_undef_builtin_macro);
+ return;
} else {
// Okay, we got a good identifier node. Return it.
return;
@@ -1925,10 +1924,14 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
if (!OtherMI->isUsed() && OtherMI->isWarnIfUnused())
Diag(OtherMI->getDefinitionLoc(), diag::pp_macro_not_used);
+ // Warn if defining "__LINE__" and other builtins, per C99 6.10.8/4 and
+ // C++ [cpp.predefined]p4, but allow it as an extension.
+ if (OtherMI->isBuiltinMacro())
+ Diag(MacroNameTok, diag::ext_pp_redef_builtin_macro);
// Macros must be identical. This means all tokens and whitespace
// separation must be the same. C99 6.10.3.2.
- if (!OtherMI->isAllowRedefinitionsWithoutWarning() &&
- !MI->isIdenticalTo(*OtherMI, *this)) {
+ else if (!OtherMI->isAllowRedefinitionsWithoutWarning() &&
+ !MI->isIdenticalTo(*OtherMI, *this)) {
Diag(MI->getDefinitionLoc(), diag::ext_pp_macro_redef)
<< MacroNameTok.getIdentifierInfo();
Diag(OtherMI->getDefinitionLoc(), diag::note_previous_definition);
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 23d088a9fb..2094dd1e1c 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -184,7 +184,7 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
// Read the '"..."'.
Lex(Tok);
- if (Tok.isNot(tok::string_literal) && Tok.isNot(tok::wide_string_literal)) {
+ if (!tok::isStringLiteral(Tok.getKind())) {
Diag(PragmaLoc, diag::err__Pragma_malformed);
// Skip this token, and the ')', if present.
if (Tok.isNot(tok::r_paren))
@@ -219,15 +219,50 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
SourceLocation RParenLoc = Tok.getLocation();
std::string StrVal = getSpelling(StrTok);
- // The _Pragma is lexically sound. Destringize according to C99 6.10.9.1:
- // "The string literal is destringized by deleting the L prefix, if present,
+ // The _Pragma is lexically sound. Destringize according to C11 6.10.9.1:
+ // "The string literal is destringized by deleting any encoding prefix,
// deleting the leading and trailing double-quotes, replacing each escape
// sequence \" by a double-quote, and replacing each escape sequence \\ by a
// single backslash."
- if (StrVal[0] == 'L') // Remove L prefix.
+ if (StrVal[0] == 'L' || StrVal[0] == 'U' ||
+ (StrVal[0] == 'u' && StrVal[1] != '8'))
StrVal.erase(StrVal.begin());
- assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' &&
- "Invalid string token!");
+ else if (StrVal[0] == 'u')
+ StrVal.erase(StrVal.begin(), StrVal.begin() + 2);
+
+ if (StrVal[0] == 'R') {
+ // FIXME: C++11 does not specify how to handle raw-string-literals here.
+ // We strip off the 'R', the quotes, the d-char-sequences, and the parens.
+ assert(StrVal[1] == '"' && StrVal[StrVal.size() - 1] == '"' &&
+ "Invalid raw string token!");
+
+ // Measure the length of the d-char-sequence.
+ unsigned NumDChars = 0;
+ while (StrVal[2 + NumDChars] != '(') {
+ assert(NumDChars < (StrVal.size() - 5) / 2 &&
+ "Invalid raw string token!");
+ ++NumDChars;
+ }
+ assert(StrVal[StrVal.size() - 2 - NumDChars] == ')');
+
+ // Remove 'R " d-char-sequence' and 'd-char-sequence "'. We'll replace the
+ // parens below.
+ StrVal.erase(0, 2 + NumDChars);
+ StrVal.erase(StrVal.size() - 1 - NumDChars);
+ } else {
+ assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' &&
+ "Invalid string token!");
+
+ // Remove escaped quotes and escapes.
+ for (unsigned i = 1, e = StrVal.size(); i < e-2; ++i) {
+ if (StrVal[i] == '\\' &&
+ (StrVal[i+1] == '\\' || StrVal[i+1] == '"')) {
+ // \\ -> '\' and \" -> '"'.
+ StrVal.erase(StrVal.begin()+i);
+ --e;
+ }
+ }
+ }
// Remove the front quote, replacing it with a space, so that the pragma
// contents appear to have a space before them.
@@ -236,16 +271,6 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
// Replace the terminating quote with a \n.
StrVal[StrVal.size()-1] = '\n';
- // Remove escaped quotes and escapes.
- for (unsigned i = 0, e = StrVal.size(); i != e-1; ++i) {
- if (StrVal[i] == '\\' &&
- (StrVal[i+1] == '\\' || StrVal[i+1] == '"')) {
- // \\ -> '\' and \" -> '"'.
- StrVal.erase(StrVal.begin()+i);
- --e;
- }
- }
-
// Plop the string (including the newline and trailing null) into a buffer
// where we can lex it.
Token TmpTok;
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 6ab1540134..5202e694d8 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -214,6 +214,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
SourceLocation ParmLoc;
bool BuiltinType = false;
+ TypeResult T;
+ SourceRange TypeRange;
+ bool TypeParsed = false;
+
switch (Tok.getKind()) {
case tok::kw_char:
case tok::kw_wchar_t:
@@ -232,12 +236,17 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
case tok::kw_void:
case tok::kw_typeof:
// __attribute__(( vec_type_hint(char) ))
- // FIXME: Don't just discard the builtin type token.
- ConsumeToken();
BuiltinType = true;
+ T = ParseTypeName(&TypeRange);
+ TypeParsed = true;
break;
case tok::identifier:
+ if (AttrName->isStr("vec_type_hint")) {
+ T = ParseTypeName(&TypeRange);
+ TypeParsed = true;
+ break;
+ }
ParmName = Tok.getIdentifierInfo();
ParmLoc = ConsumeToken();
break;
@@ -247,8 +256,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
}
ExprVector ArgExprs;
+ bool isInvalid = false;
+ bool isParmType = false;
- if (!BuiltinType &&
+ if (!BuiltinType && !AttrName->isStr("vec_type_hint") &&
(ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) {
// Eat the comma.
if (ParmLoc.isValid())
@@ -283,17 +294,32 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
Diag(Tok, diag::err_iboutletcollection_with_protocol);
SkipUntil(tok::r_paren, false, true); // skip until ')'
}
+ } else if (AttrName->isStr("vec_type_hint")) {
+ if (T.get() && !T.isInvalid())
+ isParmType = true;
+ else {
+ if (Tok.is(tok::identifier))
+ ConsumeToken();
+ if (TypeParsed)
+ isInvalid = true;
+ }
}
SourceLocation RParen = Tok.getLocation();
- if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
+ if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen) &&
+ !isInvalid) {
SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc;
- AttributeList *attr =
- Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen),
- ScopeName, ScopeLoc, ParmName, ParmLoc,
- ArgExprs.data(), ArgExprs.size(), Syntax);
- if (BuiltinType && attr->getKind() == AttributeList::AT_IBOutletCollection)
- Diag(Tok, diag::err_iboutletcollection_builtintype);
+ if (isParmType) {
+ Attrs.addNewTypeAttr(AttrName, SourceRange(AttrLoc, RParen), ScopeName,
+ ScopeLoc, ParmName, ParmLoc, T.get(), Syntax);
+ } else {
+ AttributeList *attr = Attrs.addNew(
+ AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, ParmName,
+ ParmLoc, ArgExprs.data(), ArgExprs.size(), Syntax);
+ if (BuiltinType &&
+ attr->getKind() == AttributeList::AT_IBOutletCollection)
+ Diag(Tok, diag::err_iboutletcollection_builtintype);
+ }
}
}
diff --git a/lib/Rewrite/Frontend/RewriteModernObjC.cpp b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
index f688603411..caba62b118 100644
--- a/lib/Rewrite/Frontend/RewriteModernObjC.cpp
+++ b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
@@ -572,14 +572,13 @@ namespace {
}
QualType getSimpleFunctionType(QualType result,
- const QualType *args,
- unsigned numArgs,
+ ArrayRef<QualType> args,
bool variadic = false) {
if (result == Context->getObjCInstanceType())
result = Context->getObjCIdType();
FunctionProtoType::ExtProtoInfo fpi;
fpi.Variadic = variadic;
- return Context->getFunctionType(result, args, numArgs, fpi);
+ return Context->getFunctionType(result, args, fpi);
}
// Helper function: create a CStyleCastExpr with trivial type source info.
@@ -2358,7 +2357,7 @@ void RewriteModernObjC::SynthSelGetUidFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getFuncType =
- getSimpleFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size());
+ getSimpleFunctionType(Context->getObjCSelType(), ArgTys);
SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2456,7 +2455,7 @@ void RewriteModernObjC::SynthSuperContructorFunctionDecl() {
ArgTys.push_back(argT);
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2475,8 +2474,7 @@ void RewriteModernObjC::SynthMsgSendFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2490,8 +2488,7 @@ void RewriteModernObjC::SynthMsgSendSuperFunctionDecl() {
SmallVector<QualType, 2> ArgTys;
ArgTys.push_back(Context->VoidTy);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], 1,
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2510,8 +2507,7 @@ void RewriteModernObjC::SynthMsgSendStretFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2527,8 +2523,7 @@ void RewriteModernObjC::SynthMsgSendSuperStretFunctionDecl() {
SmallVector<QualType, 2> ArgTys;
ArgTys.push_back(Context->VoidTy);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], 1,
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2548,8 +2543,7 @@ void RewriteModernObjC::SynthMsgSendFpretFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->DoubleTy,
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2563,7 +2557,7 @@ void RewriteModernObjC::SynthGetClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2578,7 +2572,7 @@ void RewriteModernObjC::SynthGetSuperClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getObjCClassType());
QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2593,7 +2587,7 @@ void RewriteModernObjC::SynthGetMetaClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2740,8 +2734,7 @@ Stmt *RewriteModernObjC::RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp) {
// Now do the "normal" pointer to function cast.
QualType castType =
- getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- BoxingMethod->isVariadic());
+ getSimpleFunctionType(returnType, ArgTypes, BoxingMethod->isVariadic());
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -2774,7 +2767,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
// Build the expression: __NSContainer_literal(int, ...).arr
QualType IntQT = Context->IntTy;
QualType NSArrayFType =
- getSimpleFunctionType(Context->VoidTy, &IntQT, 1, true);
+ getSimpleFunctionType(Context->VoidTy, IntQT, true);
std::string NSArrayFName("__NSContainer_literal");
FunctionDecl *NSArrayFD = SynthBlockInitFunctionDecl(NSArrayFName);
DeclRefExpr *NSArrayDRE =
@@ -2878,8 +2871,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
// Now do the "normal" pointer to function cast.
QualType castType =
- getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- ArrayMethod->isVariadic());
+ getSimpleFunctionType(returnType, ArgTypes, ArrayMethod->isVariadic());
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -2912,7 +2904,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
// Build the expression: __NSContainer_literal(int, ...).arr
QualType IntQT = Context->IntTy;
QualType NSDictFType =
- getSimpleFunctionType(Context->VoidTy, &IntQT, 1, true);
+ getSimpleFunctionType(Context->VoidTy, IntQT, true);
std::string NSDictFName("__NSContainer_literal");
FunctionDecl *NSDictFD = SynthBlockInitFunctionDecl(NSDictFName);
DeclRefExpr *NSDictDRE =
@@ -3052,8 +3044,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
// Now do the "normal" pointer to function cast.
QualType castType =
- getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- DictMethod->isVariadic());
+ getSimpleFunctionType(returnType, ArgTypes, DictMethod->isVariadic());
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -3195,8 +3186,9 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla
SmallVectorImpl<Expr*> &MsgExprs,
ObjCMethodDecl *Method) {
// Now do the "normal" pointer to function cast.
- QualType castType = getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- Method ? Method->isVariadic() : false);
+ QualType castType = getSimpleFunctionType(returnType, ArgTypes,
+ Method ? Method->isVariadic()
+ : false);
castType = Context->getPointerType(castType);
// build type for containing the objc_msgSend_stret object.
@@ -3635,10 +3627,10 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
CK_BitCast, DRE);
// Now do the "normal" pointer to function cast.
+ // If we don't have a method decl, force a variadic cast.
+ const ObjCMethodDecl *MD = Exp->getMethodDecl();
QualType castType =
- getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- // If we don't have a method decl, force a variadic cast.
- Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true);
+ getSimpleFunctionType(returnType, ArgTypes, MD ? MD->isVariadic() : true);
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -4744,7 +4736,7 @@ QualType RewriteModernObjC::convertFunctionTypeOfBlocks(const FunctionType *FT)
}
QualType FuncType;
if (modified)
- FuncType = getSimpleFunctionType(Res, &ArgTypes[0], ArgTypes.size());
+ FuncType = getSimpleFunctionType(Res, ArgTypes);
else FuncType = QualType(FT, 0);
return FuncType;
}
@@ -4811,8 +4803,7 @@ Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp
}
}
// Now do the pointer to function cast.
- QualType PtrToFuncCastType
- = getSimpleFunctionType(Exp->getType(), &ArgTypes[0], ArgTypes.size());
+ QualType PtrToFuncCastType = getSimpleFunctionType(Exp->getType(), ArgTypes);
PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType);
diff --git a/lib/Rewrite/Frontend/RewriteObjC.cpp b/lib/Rewrite/Frontend/RewriteObjC.cpp
index b5d9f0c8f4..108041753d 100644
--- a/lib/Rewrite/Frontend/RewriteObjC.cpp
+++ b/lib/Rewrite/Frontend/RewriteObjC.cpp
@@ -485,14 +485,13 @@ namespace {
}
QualType getSimpleFunctionType(QualType result,
- const QualType *args,
- unsigned numArgs,
+ ArrayRef<QualType> args,
bool variadic = false) {
if (result == Context->getObjCInstanceType())
result = Context->getObjCIdType();
FunctionProtoType::ExtProtoInfo fpi;
fpi.Variadic = variadic;
- return Context->getFunctionType(result, args, numArgs, fpi);
+ return Context->getFunctionType(result, args, fpi);
}
// Helper function: create a CStyleCastExpr with trivial type source info.
@@ -2263,7 +2262,7 @@ void RewriteObjC::SynthSelGetUidFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getFuncType =
- getSimpleFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size());
+ getSimpleFunctionType(Context->getObjCSelType(), ArgTys);
SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2359,7 +2358,7 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() {
ArgTys.push_back(argT);
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2378,8 +2377,7 @@ void RewriteObjC::SynthMsgSendFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2401,8 +2399,7 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2421,8 +2418,7 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2446,8 +2442,7 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2467,8 +2462,7 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->DoubleTy,
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2482,7 +2476,7 @@ void RewriteObjC::SynthGetClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2497,7 +2491,7 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getObjCClassType());
QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2512,7 +2506,7 @@ void RewriteObjC::SynthGetMetaClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
@@ -2642,8 +2636,9 @@ CallExpr *RewriteObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavo
Context->getPointerType(Context->VoidTy),
CK_BitCast, STDRE);
// Now do the "normal" pointer to function cast.
- QualType castType = getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- Method ? Method->isVariadic() : false);
+ QualType castType = getSimpleFunctionType(returnType, ArgTypes,
+ Method ? Method->isVariadic()
+ : false);
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -3024,10 +3019,10 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
CK_BitCast, DRE);
// Now do the "normal" pointer to function cast.
+ // If we don't have a method decl, force a variadic cast.
+ const ObjCMethodDecl *MD = Exp->getMethodDecl();
QualType castType =
- getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- // If we don't have a method decl, force a variadic cast.
- Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true);
+ getSimpleFunctionType(returnType, ArgTypes, MD ? MD->isVariadic() : true);
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -3806,7 +3801,7 @@ QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) {
// FIXME. Does this work if block takes no argument but has a return type
// which is of block type?
if (HasBlockType)
- FuncType = getSimpleFunctionType(Res, &ArgTypes[0], ArgTypes.size());
+ FuncType = getSimpleFunctionType(Res, ArgTypes);
else FuncType = QualType(FT, 0);
return FuncType;
}
@@ -3873,8 +3868,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
}
}
// Now do the pointer to function cast.
- QualType PtrToFuncCastType
- = getSimpleFunctionType(Exp->getType(), &ArgTypes[0], ArgTypes.size());
+ QualType PtrToFuncCastType = getSimpleFunctionType(Exp->getType(), ArgTypes);
PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType);
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 50feef87c2..9993b48832 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -505,7 +505,7 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
StringRef Str;
SourceRange Range;
- // FixIts to suppress the diagnosic by removing the dead condition.
+ // FixIts to suppress the diagnostic by removing the dead condition.
// For all binary terminators, branch 0 is taken if the condition is true,
// and branch 1 is taken if the condition is false.
int RemoveDiagKind = -1;
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 8c79d822cf..6239172a09 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -360,7 +360,7 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck);
}
- if (D->getLinkage() == ExternalLinkage)
+ if (D->hasExternalLinkage())
return true;
return false;
@@ -402,13 +402,13 @@ void Sema::getUndefinedButUsed(
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
if (FD->isDefined())
continue;
- if (FD->getLinkage() == ExternalLinkage &&
+ if (FD->hasExternalLinkage() &&
!FD->getMostRecentDecl()->isInlined())
continue;
} else {
if (cast<VarDecl>(ND)->hasDefinition() != VarDecl::DeclarationOnly)
continue;
- if (ND->getLinkage() == ExternalLinkage)
+ if (ND->hasExternalLinkage())
continue;
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index e0585df9e5..be0480b9f1 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -5026,10 +5026,8 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (const EnumType *SourceEnum = Source->getAs<EnumType>())
if (const EnumType *TargetEnum = Target->getAs<EnumType>())
- if ((SourceEnum->getDecl()->getIdentifier() ||
- SourceEnum->getDecl()->getTypedefNameForAnonDecl()) &&
- (TargetEnum->getDecl()->getIdentifier() ||
- TargetEnum->getDecl()->getTypedefNameForAnonDecl()) &&
+ if (SourceEnum->getDecl()->hasNameForLinkage() &&
+ TargetEnum->getDecl()->hasNameForLinkage() &&
SourceEnum != TargetEnum) {
if (S.SourceMgr.isInSystemMacro(CC))
return;
@@ -5689,7 +5687,7 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl **P, ParmVarDecl **PEnd,
QualType PType = Param->getOriginalType();
if (const ArrayType *AT = Context.getAsArrayType(PType)) {
if (AT->getSizeModifier() == ArrayType::Star) {
- // FIXME: This diagnosic should point the '[*]' if source-location
+ // FIXME: This diagnostic should point the '[*]' if source-location
// information is added for it.
Diag(Param->getLocation(), diag::err_array_star_in_function_definition);
}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 2cc7b85a7f..78d8518b23 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -1476,7 +1476,7 @@ static const char *GetCompletionTypeString(QualType T,
// Anonymous tag types are constant strings.
if (const TagType *TagT = dyn_cast<TagType>(T))
if (TagDecl *Tag = TagT->getDecl())
- if (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl()) {
+ if (!Tag->hasNameForLinkage()) {
switch (Tag->getTagKind()) {
case TTK_Struct: return "struct <anonymous>";
case TTK_Interface: return "__interface <anonymous>";
@@ -2605,7 +2605,12 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
// Add documentation comment, if it exists.
if (const RawComment *RC = Ctx.getRawCommentForAnyRedecl(ND)) {
Result.addBriefComment(RC->getBriefText(Ctx));
- }
+ }
+ else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND))
+ if (OMD->isPropertyAccessor())
+ if (const ObjCPropertyDecl *PDecl = OMD->findPropertyDecl())
+ if (const RawComment *RC = Ctx.getRawCommentForAnyRedecl(PDecl))
+ Result.addBriefComment(RC->getBriefText(Ctx));
}
if (StartsNestedNameSpecifier) {
@@ -4472,6 +4477,14 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("class");
Results.AddResult(Result(Builder.TakeString()));
+
+ if (Results.getSema().getLangOpts().Modules) {
+ // @import name
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "import"));
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddPlaceholderChunk("module");
+ Results.AddResult(Result(Builder.TakeString()));
+ }
}
void Sema::CodeCompleteObjCAtDirective(Scope *S) {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 2416f39442..252f94dc22 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1223,7 +1223,7 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
}
// Only warn for unused decls internal to the translation unit.
- if (D->getLinkage() == ExternalLinkage)
+ if (D->hasExternalLinkage())
return false;
return true;
@@ -1584,7 +1584,7 @@ static void filterNonConflictingPreviousDecls(ASTContext &context,
return;
// If this declaration has external
- bool hasExternalLinkage = (decl->getLinkage() == ExternalLinkage);
+ bool hasExternalLinkage = decl->hasExternalLinkage();
LookupResult::Filter filter = previous.makeFilter();
while (filter.hasNext()) {
@@ -2563,7 +2563,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(),
OldProto->arg_type_end());
NewQType = Context.getFunctionType(NewFuncType->getResultType(),
- ParamTypes.data(), ParamTypes.size(),
+ ParamTypes,
OldProto->getExtProtoInfo());
New->setType(NewQType);
New->setHasInheritedPrototype();
@@ -2646,8 +2646,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
diag::note_previous_declaration);
}
- New->setType(Context.getFunctionType(MergedReturn, &ArgTypes[0],
- ArgTypes.size(),
+ New->setType(Context.getFunctionType(MergedReturn, ArgTypes,
OldProto->getExtProtoInfo()));
return MergeCompatibleFunctionDecls(New, Old, S);
}
@@ -4117,6 +4116,11 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef)
Previous.clear();
+ // Check that there are no default arguments other than in the parameters
+ // of a function declaration (C++ only).
+ if (getLangOpts().CPlusPlus)
+ CheckExtraCXXDefaultArguments(D);
+
NamedDecl *New;
bool AddToScope = true;
@@ -4356,11 +4360,6 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Previous.clear();
}
- if (getLangOpts().CPlusPlus) {
- // Check that there are no default arguments (C++ only).
- CheckExtraCXXDefaultArguments(D);
- }
-
DiagnoseFunctionSpecifiers(D);
if (D.getDeclSpec().isThreadSpecified())
@@ -4577,7 +4576,7 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
}
}
if (WeakRefAttr *Attr = ND.getAttr<WeakRefAttr>()) {
- if (ND.getLinkage() == ExternalLinkage) {
+ if (ND.hasExternalLinkage()) {
S.Diag(Attr->getLocation(), diag::err_attribute_weakref_not_static);
ND.dropAttr<WeakRefAttr>();
}
@@ -4591,10 +4590,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
QualType R = TInfo->getType();
DeclarationName Name = GetNameForDeclarator(D).getName();
- // Check that there are no default arguments (C++ only).
- if (getLangOpts().CPlusPlus)
- CheckExtraCXXDefaultArguments(D);
-
DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
assert(SCSpec != DeclSpec::SCS_typedef &&
"Parser allowed 'typedef' as storage class VarDecl.");
@@ -4900,6 +4895,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD->setInvalidDecl();
}
+ ProcessPragmaWeak(S, NewVD);
checkAttributesAfterMerging(*this, *NewVD);
// If this is a locally-scoped extern C variable, update the map of
@@ -5008,10 +5004,7 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) {
template<typename T>
static bool mayConflictWithNonVisibleExternC(const T *ND) {
- VarDecl::StorageClass SC = ND->getStorageClass();
- if (ND->isExternC() && (SC == SC_Extern || SC == SC_PrivateExtern))
- return true;
- return ND->getDeclContext()->isTranslationUnit();
+ return ND->isExternC() || ND->getDeclContext()->isTranslationUnit();
}
/// \brief Perform semantic checking on a newly-created variable
@@ -5704,8 +5697,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
T = Context.getObjCObjectPointerType(T);
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(R)) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
- R = Context.getFunctionType(T, FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI);
+ R = Context.getFunctionType(T,
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
}
else if (isa<FunctionNoProtoType>(R))
R = Context.getFunctionNoProtoType(T);
@@ -6000,8 +5995,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExceptionSpecType = EST_BasicNoexcept;
NewFD->setType(Context.getFunctionType(FPT->getResultType(),
- FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI));
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI));
}
}
@@ -6368,6 +6364,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
+ ProcessPragmaWeak(S, NewFD);
checkAttributesAfterMerging(*this, *NewFD);
AddKnownFunctionAttributes(NewFD);
@@ -6384,13 +6381,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
EPI.Variadic = true;
EPI.ExtInfo = FT->getExtInfo();
- QualType R = Context.getFunctionType(FT->getResultType(), 0, 0, EPI);
+ QualType R = Context.getFunctionType(FT->getResultType(),
+ ArrayRef<QualType>(),
+ EPI);
NewFD->setType(R);
}
// If there's a #pragma GCC visibility in scope, and this isn't a class
// member, set the visibility of this function.
- if (NewFD->getLinkage() == ExternalLinkage && !DC->isRecord())
+ if (NewFD->hasExternalLinkage() && !DC->isRecord())
AddPushedVisibilityAttribute(NewFD);
// If there's a #pragma clang arc_cf_code_audited in scope, consider
@@ -6585,8 +6584,9 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.TypeQuals |= Qualifiers::Const;
MD->setType(Context.getFunctionType(FPT->getResultType(),
- FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI));
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI));
}
}
@@ -7127,6 +7127,20 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
DeduceInit = CXXDirectInit->getExpr(0);
}
}
+
+ // Expressions default to 'id' when we're in a debugger.
+ bool DefaultedToAuto = false;
+ if (getLangOpts().DebuggerCastResultToId &&
+ Init->getType() == Context.UnknownAnyTy) {
+ ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType());
+ if (Result.isInvalid()) {
+ VDecl->setInvalidDecl();
+ return;
+ }
+ Init = Result.take();
+ DefaultedToAuto = true;
+ }
+
TypeSourceInfo *DeducedType = 0;
if (DeduceAutoType(VDecl->getTypeSourceInfo(), DeduceInit, DeducedType) ==
DAR_Failed)
@@ -7147,7 +7161,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// 'id' instead of a specific object type prevents most of our usual checks.
// We only want to warn outside of template instantiations, though:
// inside a template, the 'id' could have come from a parameter.
- if (ActiveTemplateInstantiations.empty() &&
+ if (ActiveTemplateInstantiations.empty() && !DefaultedToAuto &&
DeducedType->getType()->isObjCIdType()) {
SourceLocation Loc = DeducedType->getTypeLoc().getBeginLoc();
Diag(Loc, diag::warn_auto_var_is_id)
@@ -7238,17 +7252,17 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// CheckInitializerTypes may change it.
QualType DclT = VDecl->getType(), SavT = DclT;
- // Top-level message sends default to 'id' when we're in a debugger
- // and we are assigning it to a variable of 'id' type.
- if (getLangOpts().DebuggerCastResultToId && DclT->isObjCIdType())
- if (Init->getType() == Context.UnknownAnyTy && isa<ObjCMessageExpr>(Init)) {
- ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType());
- if (Result.isInvalid()) {
- VDecl->setInvalidDecl();
- return;
- }
- Init = Result.take();
+ // Expressions default to 'id' when we're in a debugger
+ // and we are assigning it to a variable of Objective-C pointer type.
+ if (getLangOpts().DebuggerCastResultToId && DclT->isObjCObjectPointerType() &&
+ Init->getType() == Context.UnknownAnyTy) {
+ ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType());
+ if (Result.isInvalid()) {
+ VDecl->setInvalidDecl();
+ return;
}
+ Init = Result.take();
+ }
// Perform the initialization.
if (!VDecl->isInvalidDecl()) {
@@ -7784,7 +7798,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
if (var->isThisDeclarationADefinition() &&
- var->getLinkage() == ExternalLinkage &&
+ var->hasExternalLinkage() &&
getDiagnostics().getDiagnosticLevel(
diag::warn_missing_variable_declarations,
var->getLocation())) {
@@ -7813,10 +7827,10 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (type->isStructureOrClassType()) {
SourceLocation poi = var->getLocation();
Expr *varRef =new (Context) DeclRefExpr(var, false, type, VK_LValue, poi);
- ExprResult result =
- PerformCopyInitialization(
- InitializedEntity::InitializeBlock(poi, type, false),
- poi, Owned(varRef));
+ ExprResult result
+ = PerformMoveOrCopyInitialization(
+ InitializedEntity::InitializeBlock(poi, type, false),
+ var, var->getType(), varRef, /*AllowNRVO=*/true);
if (!result.isInvalid()) {
result = MaybeCreateExprWithCleanups(result);
Expr *init = result.takeAs<Expr>();
@@ -7882,7 +7896,7 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
const DeclContext *DC = VD->getDeclContext();
// If there's a #pragma GCC visibility in scope, and this isn't a class
// member, set the visibility of this variable.
- if (VD->getLinkage() == ExternalLinkage && !DC->isRecord())
+ if (VD->hasExternalLinkage() && !DC->isRecord())
AddPushedVisibilityAttribute(VD);
if (VD->isFileVarDecl())
@@ -8857,7 +8871,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
DeclContext *PrevDC = CurContext;
CurContext = Context.getTranslationUnitDecl();
- FunctionDecl *FD = dyn_cast<FunctionDecl>(ActOnDeclarator(TUScope, D));
+ FunctionDecl *FD = cast<FunctionDecl>(ActOnDeclarator(TUScope, D));
FD->setImplicit();
CurContext = PrevDC;
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 25202b1b3c..c9ccf80191 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -2769,6 +2769,36 @@ static void handleWorkGroupSize(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
+static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) {
+ assert(Attr.getKind() == AttributeList::AT_VecTypeHint);
+
+ // Attribute has 1 argument.
+ if (!checkAttributeNumArgs(S, Attr, 1))
+ return;
+
+ QualType ParmType = S.GetTypeFromParser(Attr.getTypeArg());
+
+ if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() &&
+ (ParmType->isBooleanType() ||
+ !ParmType->isIntegralType(S.getASTContext()))) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_vec_type_hint)
+ << ParmType;
+ return;
+ }
+
+ if (Attr.getKind() == AttributeList::AT_VecTypeHint &&
+ D->hasAttr<VecTypeHintAttr>()) {
+ VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>();
+ if (A->getTypeHint() != ParmType) {
+ S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName();
+ return;
+ }
+ }
+
+ D->addAttr(::new (S.Context) VecTypeHintAttr(Attr.getLoc(), S.Context,
+ ParmType, Attr.getLoc()));
+}
+
SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
StringRef Name,
unsigned AttrSpellingListIndex) {
@@ -4750,6 +4780,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ReqdWorkGroupSize:
handleWorkGroupSize(S, D, Attr); break;
+ case AttributeList::AT_VecTypeHint:
+ handleVecTypeHint(S, D, Attr); break;
+
case AttributeList::AT_InitPriority:
handleInitPriorityAttr(S, D, Attr); break;
@@ -5087,37 +5120,37 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
}
}
-/// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
-/// it, apply them to D. This is a bit tricky because PD can have attributes
-/// specified in many different places, and we need to find and apply them all.
-void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
- bool NonInheritable, bool Inheritable) {
+void Sema::ProcessPragmaWeak(Scope *S, Decl *D) {
// It's valid to "forward-declare" #pragma weak, in which case we
// have to do this.
- if (Inheritable) {
- LoadExternalWeakUndeclaredIdentifiers();
- if (!WeakUndeclaredIdentifiers.empty()) {
- NamedDecl *ND = NULL;
- if (VarDecl *VD = dyn_cast<VarDecl>(D))
- if (VD->isExternC())
- ND = VD;
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- if (FD->isExternC())
- ND = FD;
- if (ND) {
- if (IdentifierInfo *Id = ND->getIdentifier()) {
- llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I
- = WeakUndeclaredIdentifiers.find(Id);
- if (I != WeakUndeclaredIdentifiers.end()) {
- WeakInfo W = I->second;
- DeclApplyPragmaWeak(S, ND, W);
- WeakUndeclaredIdentifiers[Id] = W;
- }
+ LoadExternalWeakUndeclaredIdentifiers();
+ if (!WeakUndeclaredIdentifiers.empty()) {
+ NamedDecl *ND = NULL;
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ if (VD->isExternC())
+ ND = VD;
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->isExternC())
+ ND = FD;
+ if (ND) {
+ if (IdentifierInfo *Id = ND->getIdentifier()) {
+ llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I
+ = WeakUndeclaredIdentifiers.find(Id);
+ if (I != WeakUndeclaredIdentifiers.end()) {
+ WeakInfo W = I->second;
+ DeclApplyPragmaWeak(S, ND, W);
+ WeakUndeclaredIdentifiers[Id] = W;
}
}
}
}
+}
+/// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
+/// it, apply them to D. This is a bit tricky because PD can have attributes
+/// specified in many different places, and we need to find and apply them all.
+void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
+ bool NonInheritable, bool Inheritable) {
// Apply decl attributes from the DeclSpec if present.
if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes().getList())
ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index ce526a9ed3..f66509d177 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -352,16 +352,25 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
// parameter pack. If it is specified in a
// parameter-declaration-clause, it shall not occur within a
// declarator or abstract-declarator of a parameter-declaration.
+ bool MightBeFunction = D.isFunctionDeclarationContext();
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
DeclaratorChunk &chunk = D.getTypeObject(i);
if (chunk.Kind == DeclaratorChunk::Function) {
+ if (MightBeFunction) {
+ // This is a function declaration. It can have default arguments, but
+ // keep looking in case its return type is a function type with default
+ // arguments.
+ MightBeFunction = false;
+ continue;
+ }
for (unsigned argIdx = 0, e = chunk.Fun.NumArgs; argIdx != e; ++argIdx) {
ParmVarDecl *Param =
cast<ParmVarDecl>(chunk.Fun.ArgInfo[argIdx].Param);
if (Param->hasUnparsedDefaultArg()) {
CachedTokens *Toks = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens;
Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
- << SourceRange((*Toks)[1].getLocation(), Toks->back().getLocation());
+ << SourceRange((*Toks)[1].getLocation(),
+ Toks->back().getLocation());
delete Toks;
chunk.Fun.ArgInfo[argIdx].DefaultArgTokens = 0;
} else if (Param->getDefaultArg()) {
@@ -370,6 +379,8 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
Param->setDefaultArg(0);
}
}
+ } else if (chunk.Kind != DeclaratorChunk::Paren) {
+ MightBeFunction = false;
}
}
}
@@ -4183,8 +4194,10 @@ updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT,
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
ExceptSpec.getEPI(EPI);
const FunctionProtoType *NewFPT = cast<FunctionProtoType>(
- S.Context.getFunctionType(FPT->getResultType(), FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI));
+ S.Context.getFunctionType(FPT->getResultType(),
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI));
FD->setType(QualType(NewFPT, 0));
}
@@ -4346,8 +4359,10 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = MD;
- MD->setType(Context.getFunctionType(ReturnType, &ArgType,
- ExpectedParams, EPI));
+ MD->setType(Context.getFunctionType(ReturnType,
+ ArrayRef<QualType>(&ArgType,
+ ExpectedParams),
+ EPI));
}
if (ShouldDeleteSpecialMember(MD, CSM)) {
@@ -4376,7 +4391,7 @@ void Sema::CheckExplicitlyDefaultedMemberExceptionSpec(
FunctionProtoType::ExtProtoInfo EPI;
computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI);
const FunctionProtoType *ImplicitType = cast<FunctionProtoType>(
- Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ Context.getFunctionType(Context.VoidTy, ArrayRef<QualType>(), EPI));
// Ensure that it matches.
CheckEquivalentExceptionSpec(
@@ -5109,7 +5124,6 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
CXXRecordDecl *RD = MD->getParent();
bool ConstArg = false;
- ParmVarDecl *Param0 = MD->getNumParams() ? MD->getParamDecl(0) : 0;
// C++11 [class.copy]p12, p25:
// A [special member] is trivial if its declared parameter type is the same
@@ -5124,6 +5138,7 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
case CXXCopyAssignment: {
// Trivial copy operations always have const, non-volatile parameter types.
ConstArg = true;
+ const ParmVarDecl *Param0 = MD->getParamDecl(0);
const ReferenceType *RT = Param0->getType()->getAs<ReferenceType>();
if (!RT || RT->getPointeeType().getCVRQualifiers() != Qualifiers::Const) {
if (Diagnose)
@@ -5139,6 +5154,7 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
case CXXMoveConstructor:
case CXXMoveAssignment: {
// Trivial move operations always have non-cv-qualified parameters.
+ const ParmVarDecl *Param0 = MD->getParamDecl(0);
const RValueReferenceType *RT =
Param0->getType()->getAs<RValueReferenceType>();
if (!RT || RT->getPointeeType().getCVRQualifiers()) {
@@ -5628,8 +5644,10 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
EPI.TypeQuals = 0;
EPI.RefQualifier = RQ_None;
- return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(),
- Proto->getNumArgs(), EPI);
+ return Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
+ EPI);
}
/// CheckConstructor - Checks a fully-formed constructor for
@@ -5809,7 +5827,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
EPI.Variadic = false;
EPI.TypeQuals = 0;
EPI.RefQualifier = RQ_None;
- return Context.getFunctionType(Context.VoidTy, 0, 0, EPI);
+ return Context.getFunctionType(Context.VoidTy, ArrayRef<QualType>(), EPI);
}
/// CheckConversionDeclarator - Called by ActOnDeclarator to check the
@@ -5890,7 +5908,8 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// of the errors above fired) and with the conversion type as the
// return type.
if (D.isInvalidType())
- R = Context.getFunctionType(ConvType, 0, 0, Proto->getExtProtoInfo());
+ R = Context.getFunctionType(ConvType, ArrayRef<QualType>(),
+ Proto->getExtProtoInfo());
// C++0x explicit conversion operators.
if (D.getDeclSpec().isExplicitSpecified())
@@ -7520,7 +7539,9 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = DefaultCon;
- DefaultCon->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ DefaultCon->setType(Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(),
+ EPI));
// We don't need to use SpecialMemberIsTrivial here; triviality for default
// constructors is easy to compute.
@@ -7685,7 +7706,7 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
BaseCtorType->getExtProtoInfo();
ExtInfo.Variadic = false;
NewCtorType = Context.getFunctionType(BaseCtorType->getResultType(),
- Args.data(), params, ExtInfo)
+ Args, ExtInfo)
.getTypePtr();
}
const Type *CanonicalNewCtorType =
@@ -7831,7 +7852,9 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = Destructor;
- Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ Destructor->setType(Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(),
+ EPI));
AddOverriddenMethods(ClassDecl, Destructor);
@@ -7935,7 +7958,9 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo();
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = Destructor;
- Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ Destructor->setType(Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(),
+ EPI));
// FIXME: If the destructor has a body that could throw, and the newly created
// spec doesn't allow exceptions, we should emit a warning, because this
@@ -8335,7 +8360,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = CopyAssignment;
- CopyAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI));
+ CopyAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI));
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
@@ -8785,7 +8810,7 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = MoveAssignment;
- MoveAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI));
+ MoveAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI));
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment,
@@ -9139,7 +9164,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = CopyConstructor;
CopyConstructor->setType(
- Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+ Context.getFunctionType(Context.VoidTy, ArgType, EPI));
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
@@ -9326,7 +9351,7 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = MoveConstructor;
MoveConstructor->setType(
- Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+ Context.getFunctionType(Context.VoidTy, ArgType, EPI));
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor,
@@ -10225,8 +10250,8 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
bool Invalid = D.isInvalidType();
// Check for unexpanded parameter packs.
- if (TInfo && DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
- UPPC_ExceptionType)) {
+ if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
+ UPPC_ExceptionType)) {
TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy,
D.getIdentifierLoc());
Invalid = true;
@@ -11352,7 +11377,7 @@ bool Sema::DefineUsedVTables() {
Consumer.HandleVTable(Class, VTablesUsed[Canonical]);
// Optionally warn if we're emitting a weak vtable.
- if (Class->getLinkage() == ExternalLinkage &&
+ if (Class->hasExternalLinkage() &&
Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) {
const FunctionDecl *KeyFunctionDef = 0;
if (!KeyFunction ||
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 43b097d1f2..66fdc67e41 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -394,7 +394,7 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
// Then in ActOnSuperMessage() (SemaExprObjC), set it back to false.
// Finally, in ActOnFinishFunctionBody() (SemaDecl), warn if flag is set.
// Only do this if the current class actually has a superclass.
- if (IC->getSuperClass()) {
+ if (const ObjCInterfaceDecl *SuperClass = IC->getSuperClass()) {
ObjCMethodFamily Family = MDecl->getMethodFamily();
if (Family == OMF_dealloc) {
if (!(getLangOpts().ObjCAutoRefCount ||
@@ -407,8 +407,8 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
} else {
const ObjCMethodDecl *SuperMethod =
- IC->getSuperClass()->lookupMethod(MDecl->getSelector(),
- MDecl->isInstanceMethod());
+ SuperClass->lookupMethod(MDecl->getSelector(),
+ MDecl->isInstanceMethod());
getCurFunction()->ObjCShouldCallSuper =
(SuperMethod && SuperMethod->hasAttr<ObjCRequiresSuperAttr>());
}
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 29ce7dbb22..ab8dcd1ad4 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -203,10 +203,11 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
Old->isExternC()) {
FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
EPI.ExceptionSpecType = EST_DynamicNone;
- QualType NewType = Context.getFunctionType(NewProto->getResultType(),
- NewProto->arg_type_begin(),
- NewProto->getNumArgs(),
- EPI);
+ QualType NewType =
+ Context.getFunctionType(NewProto->getResultType(),
+ ArrayRef<QualType>(NewProto->arg_type_begin(),
+ NewProto->getNumArgs()),
+ EPI);
New->setType(NewType);
return false;
}
@@ -227,10 +228,11 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// Update the type of the function with the appropriate exception
// specification.
- QualType NewType = Context.getFunctionType(NewProto->getResultType(),
- NewProto->arg_type_begin(),
- NewProto->getNumArgs(),
- EPI);
+ QualType NewType =
+ Context.getFunctionType(NewProto->getResultType(),
+ ArrayRef<QualType>(NewProto->arg_type_begin(),
+ NewProto->getNumArgs()),
+ EPI);
New->setType(NewType);
// If exceptions are disabled, suppress the warning about missing
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 65bdd2a47f..69e06ea88f 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -547,7 +547,7 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) {
// First, convert to an r-value.
ExprResult Res = DefaultFunctionArrayLvalueConversion(E);
if (Res.isInvalid())
- return Owned(E);
+ return ExprError();
E = Res.take();
QualType Ty = E->getType();
@@ -598,7 +598,7 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
ExprResult Res = UsualUnaryConversions(E);
if (Res.isInvalid())
- return Owned(E);
+ return ExprError();
E = Res.take();
// If this is a 'float' or '__fp16' (CVR qualified or typedef) promote to
@@ -3341,33 +3341,56 @@ static bool checkArithmeticOnObjCPointer(Sema &S,
}
ExprResult
-Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
- Expr *Idx, SourceLocation RLoc) {
+Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
+ Expr *idx, SourceLocation rbLoc) {
// Since this might be a postfix expression, get rid of ParenListExprs.
- ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);
- if (Result.isInvalid()) return ExprError();
- Base = Result.take();
+ if (isa<ParenListExpr>(base)) {
+ ExprResult result = MaybeConvertParenListExprToParenExpr(S, base);
+ if (result.isInvalid()) return ExprError();
+ base = result.take();
+ }
- Expr *LHSExp = Base, *RHSExp = Idx;
+ // Handle any non-overload placeholder types in the base and index
+ // expressions. We can't handle overloads here because the other
+ // operand might be an overloadable type, in which case the overload
+ // resolution for the operator overload should get the first crack
+ // at the overload.
+ if (base->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(base);
+ if (result.isInvalid()) return ExprError();
+ base = result.take();
+ }
+ if (idx->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(idx);
+ if (result.isInvalid()) return ExprError();
+ idx = result.take();
+ }
+ // Build an unanalyzed expression if either operand is type-dependent.
if (getLangOpts().CPlusPlus &&
- (LHSExp->isTypeDependent() || RHSExp->isTypeDependent())) {
- return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
+ (base->isTypeDependent() || idx->isTypeDependent())) {
+ return Owned(new (Context) ArraySubscriptExpr(base, idx,
Context.DependentTy,
VK_LValue, OK_Ordinary,
- RLoc));
+ rbLoc));
}
+ // Use C++ overloaded-operator rules if either operand has record
+ // type. The spec says to do this if either type is *overloadable*,
+ // but enum types can't declare subscript operators or conversion
+ // operators, so there's nothing interesting for overload resolution
+ // to do if there aren't any record types involved.
+ //
+ // ObjC pointers have their own subscripting logic that is not tied
+ // to overload resolution and so should not take this path.
if (getLangOpts().CPlusPlus &&
- (LHSExp->getType()->isRecordType() ||
- LHSExp->getType()->isEnumeralType() ||
- RHSExp->getType()->isRecordType() ||
- RHSExp->getType()->isEnumeralType()) &&
- !LHSExp->getType()->isObjCObjectPointerType()) {
- return CreateOverloadedArraySubscriptExpr(LLoc, RLoc, Base, Idx);
+ (base->getType()->isRecordType() ||
+ (!base->getType()->isObjCObjectPointerType() &&
+ idx->getType()->isRecordType()))) {
+ return CreateOverloadedArraySubscriptExpr(lbLoc, rbLoc, base, idx);
}
- return CreateBuiltinArraySubscriptExpr(Base, LLoc, Idx, RLoc);
+ return CreateBuiltinArraySubscriptExpr(base, lbLoc, idx, rbLoc);
}
ExprResult
@@ -3812,11 +3835,8 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
if (Proto->getResultType() == Context.UnknownAnyTy &&
FDecl && FDecl->isExternC()) {
for (unsigned i = ArgIx; i != NumArgs; ++i) {
- ExprResult arg;
- if (isa<ExplicitCastExpr>(Args[i]->IgnoreParens()))
- arg = DefaultFunctionArrayLvalueConversion(Args[i]);
- else
- arg = DefaultVariadicArgumentPromotion(Args[i], CallType, FDecl);
+ QualType paramType; // ignored
+ ExprResult arg = checkUnknownAnyArg(CallLoc, Args[i], paramType);
Invalid |= arg.isInvalid();
AllArgs.push_back(arg.take());
}
@@ -9465,8 +9485,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
FunctionProtoType::ExtProtoInfo EPI;
EPI.HasTrailingReturn = false;
EPI.TypeQuals |= DeclSpec::TQ_const;
- T = Context.getFunctionType(Context.DependentTy, /*Args=*/0, /*NumArgs=*/0,
- EPI);
+ T = Context.getFunctionType(Context.DependentTy, ArrayRef<QualType>(), EPI);
Sig = Context.getTrivialTypeSourceInfo(T);
}
@@ -9645,7 +9664,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (isa<FunctionNoProtoType>(FTy)) {
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExtInfo = Ext;
- BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI);
+ BlockTy = Context.getFunctionType(RetTy, ArrayRef<QualType>(), EPI);
// Otherwise, if we don't need to change anything about the function type,
// preserve its sugar structure.
@@ -9659,17 +9678,18 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.TypeQuals = 0; // FIXME: silently?
EPI.ExtInfo = Ext;
- BlockTy = Context.getFunctionType(RetTy,
- FPT->arg_type_begin(),
- FPT->getNumArgs(),
- EPI);
+ BlockTy =
+ Context.getFunctionType(RetTy,
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
}
// If we don't have a function type, just build one from nothing.
} else {
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn);
- BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI);
+ BlockTy = Context.getFunctionType(RetTy, ArrayRef<QualType>(), EPI);
}
DiagnoseUnusedParameters(BSI->TheDecl->param_begin(),
@@ -11825,10 +11845,11 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *E) {
// Rebuild the function type, replacing the result type with DestType.
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FnType))
- DestType = S.Context.getFunctionType(DestType,
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
- Proto->getExtProtoInfo());
+ DestType =
+ S.Context.getFunctionType(DestType,
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
+ Proto->getExtProtoInfo());
else
DestType = S.Context.getFunctionNoProtoType(DestType,
FnType->getExtInfo());
@@ -11990,20 +12011,27 @@ ExprResult Sema::forceUnknownAnyToType(Expr *E, QualType ToType) {
return RebuildUnknownAnyExpr(*this, ToType).Visit(E);
}
-QualType Sema::checkUnknownAnyArg(Expr *&arg) {
- // Filter out placeholders.
- ExprResult argR = CheckPlaceholderExpr(arg);
- if (argR.isInvalid()) return QualType();
- arg = argR.take();
-
- // If the argument is an explicit cast, use that exact type as the
- // effective parameter type.
- if (ExplicitCastExpr *castArg = dyn_cast<ExplicitCastExpr>(arg)) {
- return castArg->getTypeAsWritten();
+ExprResult Sema::checkUnknownAnyArg(SourceLocation callLoc,
+ Expr *arg, QualType &paramType) {
+ // If the syntactic form of the argument is not an explicit cast of
+ // any sort, just do default argument promotion.
+ ExplicitCastExpr *castArg = dyn_cast<ExplicitCastExpr>(arg->IgnoreParens());
+ if (!castArg) {
+ ExprResult result = DefaultArgumentPromotion(arg);
+ if (result.isInvalid()) return ExprError();
+ paramType = result.get()->getType();
+ return result;
}
- // Otherwise, try to pass by value.
- return arg->getType().getUnqualifiedType();
+ // Otherwise, use the type that was written in the explicit cast.
+ assert(!arg->hasPlaceholderType());
+ paramType = castArg->getTypeAsWritten();
+
+ // Copy-initialize a parameter of that type.
+ InitializedEntity entity =
+ InitializedEntity::InitializeParameter(Context, paramType,
+ /*consumed*/ false);
+ return PerformCopyInitialization(entity, callLoc, Owned(arg));
}
static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) {
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 49d66113dc..09f04b7c43 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1595,8 +1595,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
EPI.Variadic = Proto->isVariadic();
ExpectedFunctionType
- = Context.getFunctionType(Context.VoidTy, ArgTypes.data(),
- ArgTypes.size(), EPI);
+ = Context.getFunctionType(Context.VoidTy, ArgTypes, EPI);
}
for (LookupResult::iterator D = FoundDelete.begin(),
@@ -1898,7 +1897,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
EST_BasicNoexcept : EST_DynamicNone;
}
- QualType FnType = Context.getFunctionType(Return, &Argument, 1, EPI);
+ QualType FnType = Context.getFunctionType(Return, Argument, EPI);
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(),
SourceLocation(), Name,
@@ -5489,10 +5488,9 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
if (DiagnoseUnexpandedParameterPack(FullExpr.get()))
return ExprError();
- // Top-level message sends default to 'id' when we're in a debugger.
+ // Top-level expressions default to 'id' when we're in a debugger.
if (DiscardedValue && getLangOpts().DebuggerCastResultToId &&
- FullExpr.get()->getType() == Context.UnknownAnyTy &&
- isa<ObjCMessageExpr>(FullExpr.get())) {
+ FullExpr.get()->getType() == Context.UnknownAnyTy) {
FullExpr = forceUnknownAnyToType(FullExpr.take(), Context.getObjCIdType());
if (FullExpr.isInvalid())
return ExprError();
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index b26fa7661c..b0d5453808 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -1135,10 +1135,16 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
if (Args[i]->isTypeDependent())
continue;
- ExprResult Result = DefaultArgumentPromotion(Args[i]);
- if (Result.isInvalid())
+ ExprResult result;
+ if (getLangOpts().DebuggerSupport) {
+ QualType paramTy; // ignored
+ result = checkUnknownAnyArg(lbrac, Args[i], paramTy);
+ } else {
+ result = DefaultArgumentPromotion(Args[i]);
+ }
+ if (result.isInvalid())
return true;
- Args[i] = Result.take();
+ Args[i] = result.take();
}
unsigned DiagID;
@@ -1199,14 +1205,17 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
// If the parameter is __unknown_anytype, infer its type
// from the argument.
if (param->getType() == Context.UnknownAnyTy) {
- QualType paramType = checkUnknownAnyArg(argExpr);
- if (paramType.isNull()) {
+ QualType paramType;
+ ExprResult argE = checkUnknownAnyArg(lbrac, argExpr, paramType);
+ if (argE.isInvalid()) {
IsError = true;
- continue;
- }
+ } else {
+ Args[i] = argE.take();
- // Update the parameter type in-place.
- param->setType(paramType);
+ // Update the parameter type in-place.
+ param->setType(paramType);
+ }
+ continue;
}
if (RequireCompleteType(argExpr->getSourceRange().getBegin(),
@@ -1552,8 +1561,15 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf(receiverNameLoc)) {
if (CurMethod->isInstanceMethod()) {
- QualType T =
- Context.getObjCInterfaceType(CurMethod->getClassInterface());
+ ObjCInterfaceDecl *Super =
+ CurMethod->getClassInterface()->getSuperClass();
+ if (!Super) {
+ // The current class does not have a superclass.
+ Diag(receiverNameLoc, diag::error_root_class_cannot_use_super)
+ << CurMethod->getClassInterface()->getIdentifier();
+ return ExprError();
+ }
+ QualType T = Context.getObjCInterfaceType(Super);
T = Context.getObjCObjectPointerType(T);
return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(),
@@ -2119,8 +2135,46 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
return ExprError();
Receiver = Result.take();
ReceiverType = Receiver->getType();
+
+ // If the receiver is an ObjC pointer, a block pointer, or an
+ // __attribute__((NSObject)) pointer, we don't need to do any
+ // special conversion in order to look up a receiver.
+ if (ReceiverType->isObjCRetainableType()) {
+ // do nothing
+ } else if (!getLangOpts().ObjCAutoRefCount &&
+ !Context.getObjCIdType().isNull() &&
+ (ReceiverType->isPointerType() ||
+ ReceiverType->isIntegerType())) {
+ // Implicitly convert integers and pointers to 'id' but emit a warning.
+ // But not in ARC.
+ Diag(Loc, diag::warn_bad_receiver_type)
+ << ReceiverType
+ << Receiver->getSourceRange();
+ if (ReceiverType->isPointerType()) {
+ Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
+ CK_CPointerToObjCPointerCast).take();
+ } else {
+ // TODO: specialized warning on null receivers?
+ bool IsNull = Receiver->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull);
+ CastKind Kind = IsNull ? CK_NullToPointer : CK_IntegralToPointer;
+ Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
+ Kind).take();
+ }
+ ReceiverType = Receiver->getType();
+ } else if (getLangOpts().CPlusPlus) {
+ ExprResult result = PerformContextuallyConvertToObjCPointer(Receiver);
+ if (result.isUsable()) {
+ Receiver = result.take();
+ ReceiverType = Receiver->getType();
+ }
+ }
}
+ // There's a somewhat weird interaction here where we assume that we
+ // won't actually have a method unless we also don't need to do some
+ // of the more detailed type-checking on the receiver.
+
if (!Method) {
// Handle messages to id.
bool receiverIsId = ReceiverType->isObjCIdType();
@@ -2256,48 +2310,11 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
if (Method && DiagnoseUseOfDecl(Method, Loc, forwardClass))
return ExprError();
- } else if (!getLangOpts().ObjCAutoRefCount &&
- !Context.getObjCIdType().isNull() &&
- (ReceiverType->isPointerType() ||
- ReceiverType->isIntegerType())) {
- // Implicitly convert integers and pointers to 'id' but emit a warning.
- // But not in ARC.
- Diag(Loc, diag::warn_bad_receiver_type)
- << ReceiverType
- << Receiver->getSourceRange();
- if (ReceiverType->isPointerType())
- Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
- CK_CPointerToObjCPointerCast).take();
- else {
- // TODO: specialized warning on null receivers?
- bool IsNull = Receiver->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNull);
- CastKind Kind = IsNull ? CK_NullToPointer : CK_IntegralToPointer;
- Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
- Kind).take();
- }
- ReceiverType = Receiver->getType();
} else {
- ExprResult ReceiverRes;
- if (getLangOpts().CPlusPlus)
- ReceiverRes = PerformContextuallyConvertToObjCPointer(Receiver);
- if (ReceiverRes.isUsable()) {
- Receiver = ReceiverRes.take();
- return BuildInstanceMessage(Receiver,
- ReceiverType,
- SuperLoc,
- Sel,
- Method,
- LBracLoc,
- SelectorLocs,
- RBracLoc,
- ArgsIn);
- } else {
- // Reject other random receiver types (e.g. structs).
- Diag(Loc, diag::err_bad_receiver_type)
- << ReceiverType << Receiver->getSourceRange();
- return ExprError();
- }
+ // Reject other random receiver types (e.g. structs).
+ Diag(Loc, diag::err_bad_receiver_type)
+ << ReceiverType << Receiver->getSourceRange();
+ return ExprError();
}
}
}
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 43e0c05c93..468fa0251e 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -225,73 +225,153 @@ void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
}
}
-static bool checkReturnValueType(const ASTContext &Ctx, const Expr *E,
- QualType &DeducedType,
- QualType &AlternateType) {
- // Handle ReturnStmts with no expressions.
- if (!E) {
- if (AlternateType.isNull())
- AlternateType = Ctx.VoidTy;
-
- return Ctx.hasSameType(DeducedType, Ctx.VoidTy);
+/// If this expression is an enumerator-like expression of some type
+/// T, return the type T; otherwise, return null.
+///
+/// Pointer comparisons on the result here should always work because
+/// it's derived from either the parent of an EnumConstantDecl
+/// (i.e. the definition) or the declaration returned by
+/// EnumType::getDecl() (i.e. the definition).
+static EnumDecl *findEnumForBlockReturn(Expr *E) {
+ // An expression is an enumerator-like expression of type T if,
+ // ignoring parens and parens-like expressions:
+ E = E->IgnoreParens();
+
+ // - it is an enumerator whose enum type is T or
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (EnumConstantDecl *D
+ = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
+ return cast<EnumDecl>(D->getDeclContext());
+ }
+ return 0;
}
- QualType StrictType = E->getType();
- QualType LooseType = StrictType;
-
- // In C, enum constants have the type of their underlying integer type,
- // not the enum. When inferring block return types, we should allow
- // the enum type if an enum constant is used, unless the enum is
- // anonymous (in which case there can be no variables of its type).
- if (!Ctx.getLangOpts().CPlusPlus) {
- const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
- if (DRE) {
- const Decl *D = DRE->getDecl();
- if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
- const EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext());
- if (Enum->getDeclName() || Enum->getTypedefNameForAnonDecl())
- LooseType = Ctx.getTypeDeclType(Enum);
- }
- }
+ // - it is a comma expression whose RHS is an enumerator-like
+ // expression of type T or
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->getOpcode() == BO_Comma)
+ return findEnumForBlockReturn(BO->getRHS());
+ return 0;
}
- // Special case for the first return statement we find.
- // The return type has already been tentatively set, but we might still
- // have an alternate type we should prefer.
- if (AlternateType.isNull())
- AlternateType = LooseType;
-
- if (Ctx.hasSameType(DeducedType, StrictType)) {
- // FIXME: The loose type is different when there are constants from two
- // different enums. We could consider warning here.
- if (AlternateType != Ctx.DependentTy)
- if (!Ctx.hasSameType(AlternateType, LooseType))
- AlternateType = Ctx.VoidTy;
- return true;
+ // - it is a statement-expression whose value expression is an
+ // enumerator-like expression of type T or
+ if (StmtExpr *SE = dyn_cast<StmtExpr>(E)) {
+ if (Expr *last = dyn_cast_or_null<Expr>(SE->getSubStmt()->body_back()))
+ return findEnumForBlockReturn(last);
+ return 0;
}
- if (Ctx.hasSameType(DeducedType, LooseType)) {
- // Use DependentTy to signal that we're using an alternate type and may
- // need to add casts somewhere.
- AlternateType = Ctx.DependentTy;
- return true;
+ // - it is a ternary conditional operator (not the GNU ?:
+ // extension) whose second and third operands are
+ // enumerator-like expressions of type T or
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ if (EnumDecl *ED = findEnumForBlockReturn(CO->getTrueExpr()))
+ if (ED == findEnumForBlockReturn(CO->getFalseExpr()))
+ return ED;
+ return 0;
}
- if (Ctx.hasSameType(AlternateType, StrictType) ||
- Ctx.hasSameType(AlternateType, LooseType)) {
- DeducedType = AlternateType;
- // Use DependentTy to signal that we're using an alternate type and may
- // need to add casts somewhere.
- AlternateType = Ctx.DependentTy;
- return true;
+ // (implicitly:)
+ // - it is an implicit integral conversion applied to an
+ // enumerator-like expression of type T or
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ // We can only see integral conversions in valid enumerator-like
+ // expressions.
+ if (ICE->getCastKind() == CK_IntegralCast)
+ return findEnumForBlockReturn(ICE->getSubExpr());
+ return 0;
}
- return false;
+ // - it is an expression of that formal enum type.
+ if (const EnumType *ET = E->getType()->getAs<EnumType>()) {
+ return ET->getDecl();
+ }
+
+ // Otherwise, nope.
+ return 0;
+}
+
+/// Attempt to find a type T for which the returned expression of the
+/// given statement is an enumerator-like expression of that type.
+static EnumDecl *findEnumForBlockReturn(ReturnStmt *ret) {
+ if (Expr *retValue = ret->getRetValue())
+ return findEnumForBlockReturn(retValue);
+ return 0;
+}
+
+/// Attempt to find a common type T for which all of the returned
+/// expressions in a block are enumerator-like expressions of that
+/// type.
+static EnumDecl *findCommonEnumForBlockReturns(ArrayRef<ReturnStmt*> returns) {
+ ArrayRef<ReturnStmt*>::iterator i = returns.begin(), e = returns.end();
+
+ // Try to find one for the first return.
+ EnumDecl *ED = findEnumForBlockReturn(*i);
+ if (!ED) return 0;
+
+ // Check that the rest of the returns have the same enum.
+ for (++i; i != e; ++i) {
+ if (findEnumForBlockReturn(*i) != ED)
+ return 0;
+ }
+
+ // Never infer an anonymous enum type.
+ if (!ED->hasNameForLinkage()) return 0;
+
+ return ED;
+}
+
+/// Adjust the given return statements so that they formally return
+/// the given type. It should require, at most, an IntegralCast.
+static void adjustBlockReturnsToEnum(Sema &S, ArrayRef<ReturnStmt*> returns,
+ QualType returnType) {
+ for (ArrayRef<ReturnStmt*>::iterator
+ i = returns.begin(), e = returns.end(); i != e; ++i) {
+ ReturnStmt *ret = *i;
+ Expr *retValue = ret->getRetValue();
+ if (S.Context.hasSameType(retValue->getType(), returnType))
+ continue;
+
+ // Right now we only support integral fixup casts.
+ assert(returnType->isIntegralOrUnscopedEnumerationType());
+ assert(retValue->getType()->isIntegralOrUnscopedEnumerationType());
+
+ ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(retValue);
+
+ Expr *E = (cleanups ? cleanups->getSubExpr() : retValue);
+ E = ImplicitCastExpr::Create(S.Context, returnType, CK_IntegralCast,
+ E, /*base path*/ 0, VK_RValue);
+ if (cleanups) {
+ cleanups->setSubExpr(E);
+ } else {
+ ret->setRetValue(E);
+ }
+ }
}
void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
assert(CSI.HasImplicitReturnType);
+ // C++ Core Issue #975, proposed resolution:
+ // If a lambda-expression does not include a trailing-return-type,
+ // it is as if the trailing-return-type denotes the following type:
+ // - if there are no return statements in the compound-statement,
+ // or all return statements return either an expression of type
+ // void or no expression or braced-init-list, the type void;
+ // - otherwise, if all return statements return an expression
+ // and the types of the returned expressions after
+ // lvalue-to-rvalue conversion (4.1 [conv.lval]),
+ // array-to-pointer conversion (4.2 [conv.array]), and
+ // function-to-pointer conversion (4.3 [conv.func]) are the
+ // same, that common type;
+ // - otherwise, the program is ill-formed.
+ //
+ // In addition, in blocks in non-C++ modes, if all of the return
+ // statements are enumerator-like expressions of some type T, where
+ // T has a name for linkage, then we infer the return type of the
+ // block to be that type.
+
// First case: no return statements, implicit void return type.
ASTContext &Ctx = getASTContext();
if (CSI.Returns.empty()) {
@@ -308,6 +388,17 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
if (CSI.ReturnType->isDependentType())
return;
+ // Try to apply the enum-fuzz rule.
+ if (!getLangOpts().CPlusPlus) {
+ assert(isa<BlockScopeInfo>(CSI));
+ const EnumDecl *ED = findCommonEnumForBlockReturns(CSI.Returns);
+ if (ED) {
+ CSI.ReturnType = Context.getTypeDeclType(ED);
+ adjustBlockReturnsToEnum(*this, CSI.Returns, CSI.ReturnType);
+ return;
+ }
+ }
+
// Third case: only one return statement. Don't bother doing extra work!
SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(),
E = CSI.Returns.end();
@@ -316,47 +407,25 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
// General case: many return statements.
// Check that they all have compatible return types.
- // For now, that means "identical", with an exception for enum constants.
- // (In C, enum constants have the type of their underlying integer type,
- // not the type of the enum. C++ uses the type of the enum.)
- QualType AlternateType;
// We require the return types to strictly match here.
+ // Note that we've already done the required promotions as part of
+ // processing the return statement.
for (; I != E; ++I) {
const ReturnStmt *RS = *I;
const Expr *RetE = RS->getRetValue();
- if (!checkReturnValueType(Ctx, RetE, CSI.ReturnType, AlternateType)) {
- // FIXME: This is a poor diagnostic for ReturnStmts without expressions.
- Diag(RS->getLocStart(),
- diag::err_typecheck_missing_return_type_incompatible)
- << (RetE ? RetE->getType() : Ctx.VoidTy) << CSI.ReturnType
- << isa<LambdaScopeInfo>(CSI);
- // Don't bother fixing up the return statements in the block if some of
- // them are unfixable anyway.
- AlternateType = Ctx.VoidTy;
- // Continue iterating so that we keep emitting diagnostics.
- }
- }
- // If our return statements turned out to be compatible, but we needed to
- // pick a different return type, go through and fix the ones that need it.
- if (AlternateType == Ctx.DependentTy) {
- for (SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(),
- E = CSI.Returns.end();
- I != E; ++I) {
- ReturnStmt *RS = *I;
- Expr *RetE = RS->getRetValue();
- if (RetE->getType() == CSI.ReturnType)
- continue;
+ QualType ReturnType = (RetE ? RetE->getType() : Context.VoidTy);
+ if (Context.hasSameType(ReturnType, CSI.ReturnType))
+ continue;
- // Right now we only support integral fixup casts.
- assert(CSI.ReturnType->isIntegralOrUnscopedEnumerationType());
- assert(RetE->getType()->isIntegralOrUnscopedEnumerationType());
- ExprResult Casted = ImpCastExprToType(RetE, CSI.ReturnType,
- CK_IntegralCast);
- assert(Casted.isUsable());
- RS->setRetValue(Casted.take());
- }
+ // FIXME: This is a poor diagnostic for ReturnStmts without expressions.
+ // TODO: It's possible that the *first* return is the divergent one.
+ Diag(RS->getLocStart(),
+ diag::err_typecheck_missing_return_type_incompatible)
+ << ReturnType << CSI.ReturnType
+ << isa<LambdaScopeInfo>(CSI);
+ // Continue iterating so that we keep emitting diagnostics.
}
}
@@ -385,7 +454,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
EPI.HasTrailingReturn = true;
EPI.TypeQuals |= DeclSpec::TQ_const;
QualType MethodTy = Context.getFunctionType(Context.DependentTy,
- /*Args=*/0, /*NumArgs=*/0, EPI);
+ ArrayRef<QualType>(),
+ EPI);
MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
ExplicitParams = false;
ExplicitResultType = false;
@@ -628,16 +698,18 @@ static void addFunctionPointerConversion(Sema &S,
{
FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
ExtInfo.TypeQuals = 0;
- FunctionTy = S.Context.getFunctionType(Proto->getResultType(),
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
- ExtInfo);
+ FunctionTy =
+ S.Context.getFunctionType(Proto->getResultType(),
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
+ ExtInfo);
FunctionPtrTy = S.Context.getPointerType(FunctionTy);
}
FunctionProtoType::ExtProtoInfo ExtInfo;
ExtInfo.TypeQuals = Qualifiers::Const;
- QualType ConvTy = S.Context.getFunctionType(FunctionPtrTy, 0, 0, ExtInfo);
+ QualType ConvTy =
+ S.Context.getFunctionType(FunctionPtrTy, ArrayRef<QualType>(), ExtInfo);
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName Name
@@ -701,15 +773,16 @@ static void addBlockPointerConversion(Sema &S,
ExtInfo.TypeQuals = 0;
QualType FunctionTy
= S.Context.getFunctionType(Proto->getResultType(),
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
ExtInfo);
BlockPtrTy = S.Context.getBlockPointerType(FunctionTy);
}
FunctionProtoType::ExtProtoInfo ExtInfo;
ExtInfo.TypeQuals = Qualifiers::Const;
- QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, 0, 0, ExtInfo);
+ QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, ArrayRef<QualType>(),
+ ExtInfo);
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName Name
@@ -821,8 +894,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
= CallOperator->getType()->getAs<FunctionProtoType>();
QualType FunctionTy
= Context.getFunctionType(LSI->ReturnType,
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
Proto->getExtProtoInfo());
CallOperator->setType(FunctionTy);
}
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index d931bc7dd9..eae6269ca6 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -722,7 +722,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
EPI.NumExceptions = 0;
QualType ExpectedType
= R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(),
- 0, 0, EPI);
+ ArrayRef<QualType>(), EPI);
// Perform template argument deduction against the type that we would
// expect the function to have.
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 9b7ba04044..b5b35fc48b 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -2531,6 +2531,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/;
Result = new (Context) ReturnStmt(ReturnLoc);
} else {
+ assert(RetValExp || FnRetType->isDependentType());
const VarDecl *NRVOCandidate = 0;
if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
// we have a non-void function with an expression, continue checking
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 4b766a9fde..adf25ce3ae 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -3493,7 +3493,7 @@ bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) {
return true;
}
- if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl()) {
+ if (!Tag->hasNameForLinkage()) {
S.Diag(SR.getBegin(),
S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_arg_unnamed_type :
@@ -5648,11 +5648,15 @@ Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
static void StripImplicitInstantiation(NamedDecl *D) {
- // FIXME: "make check" is clean if the call to dropAttrs() is commented out.
D->dropAttrs();
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
FD->setInlineSpecified(false);
+
+ for (FunctionDecl::param_iterator I = FD->param_begin(),
+ E = FD->param_end();
+ I != E; ++I)
+ (*I)->dropAttrs();
}
}
@@ -5946,8 +5950,9 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.TypeQuals |= Qualifiers::Const;
FT = Context.getFunctionType(FPT->getResultType(),
- FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI);
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
}
}
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 421633f389..f3bbe8a0f1 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -2417,15 +2417,10 @@ Sema::SubstituteExplicitTemplateArguments(
return TDK_SubstitutionFailure;
if (FunctionType) {
- *FunctionType = BuildFunctionType(ResultType,
- ParamTypes.data(), ParamTypes.size(),
- Proto->isVariadic(),
- Proto->hasTrailingReturn(),
- Proto->getTypeQuals(),
- Proto->getRefQualifier(),
+ *FunctionType = BuildFunctionType(ResultType, ParamTypes,
Function->getLocation(),
Function->getDeclName(),
- Proto->getExtInfo());
+ Proto->getExtProtoInfo());
if (FunctionType->isNull() || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 79e16f3942..255df80d66 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1716,7 +1716,9 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
NewParm->setScopeInfo(OldParm->getFunctionScopeDepth(),
OldParm->getFunctionScopeIndex() + indexAdjustment);
-
+
+ InstantiateAttrs(TemplateArgs, OldParm, NewParm);
+
return NewParm;
}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 9ca44c0e4d..d7ab7fd842 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -229,9 +229,9 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
// tag decl, re-establish that relationship for the new typedef.
if (const TagType *oldTagType = D->getUnderlyingType()->getAs<TagType>()) {
TagDecl *oldTag = oldTagType->getDecl();
- if (oldTag->getTypedefNameForAnonDecl() == D) {
+ if (oldTag->getTypedefNameForAnonDecl() == D && !Invalid) {
TagDecl *newTag = DI->getType()->castAs<TagType>()->getDecl();
- assert(!newTag->getIdentifier() && !newTag->getTypedefNameForAnonDecl());
+ assert(!newTag->hasNameForLinkage());
newTag->setTypedefNameForAnonDecl(Typedef);
}
}
@@ -1090,8 +1090,8 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context,
FunctionProtoType::ExtProtoInfo NewEPI = NewFunc->getExtProtoInfo();
NewEPI.ExtInfo = OrigFunc->getExtInfo();
return Context.getFunctionType(NewFunc->getResultType(),
- NewFunc->arg_type_begin(),
- NewFunc->getNumArgs(),
+ ArrayRef<QualType>(NewFunc->arg_type_begin(),
+ NewFunc->getNumArgs()),
NewEPI);
}
@@ -2585,8 +2585,8 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
EPI.NoexceptExpr = NoexceptExpr;
New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
- NewProto->arg_type_begin(),
- NewProto->getNumArgs(),
+ ArrayRef<QualType>(NewProto->arg_type_begin(),
+ NewProto->getNumArgs()),
EPI));
}
@@ -2604,8 +2604,8 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
EPI.ExceptionSpecType = EST_None;
Decl->setType(Context.getFunctionType(Proto->getResultType(),
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
EPI));
return;
}
@@ -2685,8 +2685,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
EPI.ExceptionSpecDecl = New;
EPI.ExceptionSpecTemplate = ExceptionSpecTemplate;
New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
- NewProto->arg_type_begin(),
- NewProto->getNumArgs(),
+ ArrayRef<QualType>(NewProto->arg_type_begin(),
+ NewProto->getNumArgs()),
EPI));
} else {
::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs);
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index c47a7f59ac..e9ccbecaba 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -150,6 +150,10 @@ namespace {
return declarator;
}
+ bool isProcessingDeclSpec() const {
+ return chunkIndex == declarator.getNumTypeObjects();
+ }
+
unsigned getCurrentChunkIndex() const {
return chunkIndex;
}
@@ -160,8 +164,7 @@ namespace {
}
AttributeList *&getCurrentAttrListRef() const {
- assert(chunkIndex <= declarator.getNumTypeObjects());
- if (chunkIndex == declarator.getNumTypeObjects())
+ if (isProcessingDeclSpec())
return getMutableDeclSpec().getAttributes().getListRef();
return declarator.getTypeObject(chunkIndex).getAttrListRef();
}
@@ -302,6 +305,66 @@ static bool handleObjCPointerTypeAttr(TypeProcessingState &state,
return handleObjCOwnershipTypeAttr(state, attr, type);
}
+/// Given the index of a declarator chunk, check whether that chunk
+/// directly specifies the return type of a function and, if so, find
+/// an appropriate place for it.
+///
+/// \param i - a notional index which the search will start
+/// immediately inside
+static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator,
+ unsigned i) {
+ assert(i <= declarator.getNumTypeObjects());
+
+ DeclaratorChunk *result = 0;
+
+ // First, look inwards past parens for a function declarator.
+ for (; i != 0; --i) {
+ DeclaratorChunk &fnChunk = declarator.getTypeObject(i-1);
+ switch (fnChunk.Kind) {
+ case DeclaratorChunk::Paren:
+ continue;
+
+ // If we find anything except a function, bail out.
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::MemberPointer:
+ return result;
+
+ // If we do find a function declarator, scan inwards from that,
+ // looking for a block-pointer declarator.
+ case DeclaratorChunk::Function:
+ for (--i; i != 0; --i) {
+ DeclaratorChunk &blockChunk = declarator.getTypeObject(i-1);
+ switch (blockChunk.Kind) {
+ case DeclaratorChunk::Paren:
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::Function:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::MemberPointer:
+ continue;
+ case DeclaratorChunk::BlockPointer:
+ result = &blockChunk;
+ goto continue_outer;
+ }
+ llvm_unreachable("bad declarator chunk kind");
+ }
+
+ // If we run out of declarators doing that, we're done.
+ return result;
+ }
+ llvm_unreachable("bad declarator chunk kind");
+
+ // Okay, reconsider from our new point.
+ continue_outer: ;
+ }
+
+ // Ran out of chunks, bail out.
+ return result;
+}
+
/// Given that an objc_gc attribute was written somewhere on a
/// declaration *other* than on the declarator itself (for which, use
/// distributeObjCPointerTypeAttrFromDeclarator), and given that it
@@ -311,22 +374,44 @@ static void distributeObjCPointerTypeAttr(TypeProcessingState &state,
AttributeList &attr,
QualType type) {
Declarator &declarator = state.getDeclarator();
+
+ // Move it to the outermost normal or block pointer declarator.
for (unsigned i = state.getCurrentChunkIndex(); i != 0; --i) {
DeclaratorChunk &chunk = declarator.getTypeObject(i-1);
switch (chunk.Kind) {
case DeclaratorChunk::Pointer:
- case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::BlockPointer: {
+ // But don't move an ARC ownership attribute to the return type
+ // of a block.
+ DeclaratorChunk *destChunk = 0;
+ if (state.isProcessingDeclSpec() &&
+ attr.getKind() == AttributeList::AT_ObjCOwnership)
+ destChunk = maybeMovePastReturnType(declarator, i - 1);
+ if (!destChunk) destChunk = &chunk;
+
moveAttrFromListToList(attr, state.getCurrentAttrListRef(),
- chunk.getAttrListRef());
+ destChunk->getAttrListRef());
return;
+ }
case DeclaratorChunk::Paren:
case DeclaratorChunk::Array:
continue;
+ // We may be starting at the return type of a block.
+ case DeclaratorChunk::Function:
+ if (state.isProcessingDeclSpec() &&
+ attr.getKind() == AttributeList::AT_ObjCOwnership) {
+ if (DeclaratorChunk *dest = maybeMovePastReturnType(declarator, i)) {
+ moveAttrFromListToList(attr, state.getCurrentAttrListRef(),
+ dest->getAttrListRef());
+ return;
+ }
+ }
+ goto error;
+
// Don't walk through these.
case DeclaratorChunk::Reference:
- case DeclaratorChunk::Function:
case DeclaratorChunk::MemberPointer:
goto error;
}
@@ -1545,45 +1630,10 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
return Context.getDependentSizedExtVectorType(T, ArraySize, AttrLoc);
}
-/// \brief Build a function type.
-///
-/// This routine checks the function type according to C++ rules and
-/// under the assumption that the result type and parameter types have
-/// just been instantiated from a template. It therefore duplicates
-/// some of the behavior of GetTypeForDeclarator, but in a much
-/// simpler form that is only suitable for this narrow use case.
-///
-/// \param T The return type of the function.
-///
-/// \param ParamTypes The parameter types of the function. This array
-/// will be modified to account for adjustments to the types of the
-/// function parameters.
-///
-/// \param NumParamTypes The number of parameter types in ParamTypes.
-///
-/// \param Variadic Whether this is a variadic function type.
-///
-/// \param HasTrailingReturn Whether this function has a trailing return type.
-///
-/// \param Quals The cvr-qualifiers to be applied to the function type.
-///
-/// \param Loc The location of the entity whose type involves this
-/// function type or, if there is no such entity, the location of the
-/// type that will have function type.
-///
-/// \param Entity The name of the entity that involves the function
-/// type, if known.
-///
-/// \returns A suitable function type, if there are no
-/// errors. Otherwise, returns a NULL type.
QualType Sema::BuildFunctionType(QualType T,
- QualType *ParamTypes,
- unsigned NumParamTypes,
- bool Variadic, bool HasTrailingReturn,
- unsigned Quals,
- RefQualifierKind RefQualifier,
+ llvm::MutableArrayRef<QualType> ParamTypes,
SourceLocation Loc, DeclarationName Entity,
- FunctionType::ExtInfo Info) {
+ const FunctionProtoType::ExtProtoInfo &EPI) {
if (T->isArrayType() || T->isFunctionType()) {
Diag(Loc, diag::err_func_returning_array_function)
<< T->isFunctionType() << T;
@@ -1598,7 +1648,7 @@ QualType Sema::BuildFunctionType(QualType T,
}
bool Invalid = false;
- for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) {
+ for (unsigned Idx = 0, Cnt = ParamTypes.size(); Idx < Cnt; ++Idx) {
// FIXME: Loc is too inprecise here, should use proper locations for args.
QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]);
if (ParamType->isVoidType()) {
@@ -1617,14 +1667,7 @@ QualType Sema::BuildFunctionType(QualType T,
if (Invalid)
return QualType();
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.Variadic = Variadic;
- EPI.HasTrailingReturn = HasTrailingReturn;
- EPI.TypeQuals = Quals;
- EPI.RefQualifier = RefQualifier;
- EPI.ExtInfo = Info;
-
- return Context.getFunctionType(T, ParamTypes, NumParamTypes, EPI);
+ return Context.getFunctionType(T, ParamTypes, EPI);
}
/// \brief Build a member pointer type \c T Class::*.
@@ -2701,7 +2744,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
Exceptions,
EPI);
- T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(), EPI);
+ T = Context.getFunctionType(T, ArgTys, EPI);
}
break;
@@ -2841,8 +2884,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
EPI.RefQualifier = RQ_None;
T = Context.getFunctionType(FnTy->getResultType(),
- FnTy->arg_type_begin(),
- FnTy->getNumArgs(), EPI);
+ ArrayRef<QualType>(FnTy->arg_type_begin(),
+ FnTy->getNumArgs()),
+ EPI);
// Rebuild any parens around the identifier in the function type.
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
if (D.getTypeObject(i).Kind != DeclaratorChunk::Paren)
@@ -3300,6 +3344,7 @@ namespace {
TypeSourceInfo *TInfo = 0;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
+ assert(TInfo);
TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc());
}
@@ -3638,6 +3683,14 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
} else if (!type->isObjCRetainableType()) {
return false;
}
+
+ // Don't accept an ownership attribute in the declspec if it would
+ // just be the return type of a block pointer.
+ if (state.isProcessingDeclSpec()) {
+ Declarator &D = state.getDeclarator();
+ if (maybeMovePastReturnType(D, D.getNumTypeObjects()))
+ return false;
+ }
}
Sema &S = state.getSema();
@@ -3744,10 +3797,8 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
// Forbid __weak for class objects marked as
// objc_arc_weak_reference_unavailable
if (lifetime == Qualifiers::OCL_Weak) {
- QualType T = type;
- while (const PointerType *ptr = T->getAs<PointerType>())
- T = ptr->getPointeeType();
- if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
+ if (const ObjCObjectPointerType *ObjT =
+ type->getAs<ObjCObjectPointerType>()) {
if (ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl()) {
if (Class->isArcWeakrefUnavailable()) {
S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class);
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 66bf4cea68..1dde87d2e6 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -713,12 +713,8 @@ public:
/// By default, performs semantic analysis when building the function type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildFunctionProtoType(QualType T,
- QualType *ParamTypes,
- unsigned NumParamTypes,
- bool Variadic, bool HasTrailingReturn,
- unsigned Quals,
- RefQualifierKind RefQualifier,
- const FunctionType::ExtInfo &Info);
+ llvm::MutableArrayRef<QualType> ParamTypes,
+ const FunctionProtoType::ExtProtoInfo &EPI);
/// \brief Build a new unprototyped function type.
QualType RebuildFunctionNoProtoType(QualType ResultType);
@@ -4266,14 +4262,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
ResultType != T->getResultType() ||
T->getNumArgs() != ParamTypes.size() ||
!std::equal(T->arg_type_begin(), T->arg_type_end(), ParamTypes.begin())) {
- Result = getDerived().RebuildFunctionProtoType(ResultType,
- ParamTypes.data(),
- ParamTypes.size(),
- T->isVariadic(),
- T->hasTrailingReturn(),
- T->getTypeQuals(),
- T->getRefQualifier(),
- T->getExtInfo());
+ Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes,
+ T->getExtProtoInfo());
if (Result.isNull())
return QualType();
}
@@ -7177,9 +7167,14 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
QualType T;
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
T = MD->getThisType(getSema().Context);
- else
+ else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) {
T = getSema().Context.getPointerType(
- getSema().Context.getRecordType(cast<CXXRecordDecl>(DC)));
+ getSema().Context.getRecordType(Record));
+ } else {
+ assert(SemaRef.Context.getDiagnostics().hasErrorOccurred() &&
+ "this in the wrong scope?");
+ return ExprError();
+ }
if (!getDerived().AlwaysRebuild() && T == E->getType()) {
// Make sure that we capture 'this'.
@@ -7459,7 +7454,9 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
TypeSourceInfo *ScopeTypeInfo = 0;
if (E->getScopeTypeInfo()) {
- ScopeTypeInfo = getDerived().TransformType(E->getScopeTypeInfo());
+ CXXScopeSpec EmptySS;
+ ScopeTypeInfo = getDerived().TransformTypeInObjectScope(
+ E->getScopeTypeInfo(), ObjectType, 0, EmptySS);
if (!ScopeTypeInfo)
return ExprError();
}
@@ -8835,7 +8832,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
return ExprError();
}
- const FunctionType *exprFunctionType = E->getFunctionType();
+ const FunctionProtoType *exprFunctionType = E->getFunctionType();
QualType exprResultType =
getDerived().TransformType(exprFunctionType->getResultType());
@@ -8848,13 +8845,9 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
return ExprError();
}
- QualType functionType = getDerived().RebuildFunctionProtoType(
- exprResultType,
- paramTypes.data(),
- paramTypes.size(),
- oldBlock->isVariadic(),
- false, 0, RQ_None,
- exprFunctionType->getExtInfo());
+ QualType functionType =
+ getDerived().RebuildFunctionProtoType(exprResultType, paramTypes,
+ exprFunctionType->getExtProtoInfo());
blockScope->FunctionType = functionType;
// Set the parameters on the block decl.
@@ -9070,19 +9063,14 @@ TreeTransform<Derived>::RebuildDependentSizedExtVectorType(QualType ElementType,
}
template<typename Derived>
-QualType TreeTransform<Derived>::RebuildFunctionProtoType(QualType T,
- QualType *ParamTypes,
- unsigned NumParamTypes,
- bool Variadic,
- bool HasTrailingReturn,
- unsigned Quals,
- RefQualifierKind RefQualifier,
- const FunctionType::ExtInfo &Info) {
- return SemaRef.BuildFunctionType(T, ParamTypes, NumParamTypes, Variadic,
- HasTrailingReturn, Quals, RefQualifier,
+QualType TreeTransform<Derived>::RebuildFunctionProtoType(
+ QualType T,
+ llvm::MutableArrayRef<QualType> ParamTypes,
+ const FunctionProtoType::ExtProtoInfo &EPI) {
+ return SemaRef.BuildFunctionType(T, ParamTypes,
getDerived().getBaseLocation(),
getDerived().getBaseEntity(),
- Info);
+ EPI);
}
template<typename Derived>
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 24073df3ec..93ae6f1c44 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -41,6 +41,7 @@
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/ModuleManager.h"
#include "clang/Serialization/SerializationDiagnostic.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamReader.h"
#include "llvm/Support/ErrorHandling.h"
@@ -917,10 +918,13 @@ bool ASTReader::ReadSLocEntry(int ID) {
// we will also try to fail gracefully by setting up the SLocEntry.
unsigned InputID = Record[4];
InputFile IF = getInputFile(*F, InputID);
- const FileEntry *File = IF.getPointer();
- bool OverriddenBuffer = IF.getInt();
+ const FileEntry *File = IF.getFile();
+ bool OverriddenBuffer = IF.isOverridden();
- if (!IF.getPointer())
+ // Note that we only check if a File was returned. If it was out-of-date
+ // we have complained but we will continue creating a FileID to recover
+ // gracefully.
+ if (!File)
return true;
SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
@@ -1291,37 +1295,49 @@ ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const
return LocalID + I->second;
}
-unsigned HeaderFileInfoTrait::ComputeHash(const char *path) {
- return llvm::HashString(llvm::sys::path::filename(path));
+unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) {
+ return llvm::hash_combine(ikey.Size, ikey.ModTime);
}
HeaderFileInfoTrait::internal_key_type
-HeaderFileInfoTrait::GetInternalKey(const char *path) { return path; }
+HeaderFileInfoTrait::GetInternalKey(const FileEntry *FE) {
+ internal_key_type ikey = { FE->getSize(), FE->getModificationTime(),
+ FE->getName() };
+ return ikey;
+}
-bool HeaderFileInfoTrait::EqualKey(internal_key_type a, internal_key_type b) {
- if (strcmp(a, b) == 0)
- return true;
-
- if (llvm::sys::path::filename(a) != llvm::sys::path::filename(b))
+bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) {
+ if (a.Size != b.Size || a.ModTime != b.ModTime)
return false;
- // Determine whether the actual files are equivalent.
- bool Result = false;
- if (llvm::sys::fs::equivalent(a, b, Result))
- return false;
+ if (strcmp(a.Filename, b.Filename) == 0)
+ return true;
- return Result;
+ // Determine whether the actual files are equivalent.
+ FileManager &FileMgr = Reader.getFileManager();
+ const FileEntry *FEA = FileMgr.getFile(a.Filename);
+ const FileEntry *FEB = FileMgr.getFile(b.Filename);
+ return (FEA && FEA == FEB);
}
std::pair<unsigned, unsigned>
HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) {
unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
unsigned DataLen = (unsigned) *d++;
- return std::make_pair(KeyLen + 1, DataLen);
+ return std::make_pair(KeyLen, DataLen);
}
-
+
+HeaderFileInfoTrait::internal_key_type
+HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) {
+ internal_key_type ikey;
+ ikey.Size = off_t(clang::io::ReadUnalignedLE64(d));
+ ikey.ModTime = time_t(clang::io::ReadUnalignedLE64(d));
+ ikey.Filename = (const char *)d;
+ return ikey;
+}
+
HeaderFileInfoTrait::data_type
-HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d,
+HeaderFileInfoTrait::ReadData(internal_key_ref, const unsigned char *d,
unsigned DataLen) {
const unsigned char *End = d + DataLen;
using namespace clang::io;
@@ -1495,14 +1511,13 @@ void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) {
IdentifierGeneration[II] = CurrentGeneration;
}
-llvm::PointerIntPair<const FileEntry *, 1, bool>
-ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
+InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
// If this ID is bogus, just return an empty input file.
if (ID == 0 || ID > F.InputFilesLoaded.size())
return InputFile();
// If we've already loaded this input file, return it.
- if (F.InputFilesLoaded[ID-1].getPointer())
+ if (F.InputFilesLoaded[ID-1].getFile())
return F.InputFilesLoaded[ID-1];
// Go find this input file.
@@ -1556,17 +1571,15 @@ ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
}
return InputFile();
}
-
- // Note that we've loaded this input file.
- F.InputFilesLoaded[ID-1] = InputFile(File, Overridden);
-
+
// Check if there was a request to override the contents of the file
// that was part of the precompiled header. Overridding such a file
// can lead to problems when lexing using the source locations from the
// PCH.
SourceManager &SM = getSourceManager();
if (!Overridden && SM.isFileOverridden(File)) {
- Error(diag::err_fe_pch_file_overridden, Filename);
+ if (Complain)
+ Error(diag::err_fe_pch_file_overridden, Filename);
// After emitting the diagnostic, recover by disabling the override so
// that the original file will be used.
SM.disableFileContentsOverride(File);
@@ -1577,11 +1590,10 @@ ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
StoredSize, StoredTime);
}
- // For an overridden file, there is nothing to validate.
- if (Overridden)
- return InputFile(File, Overridden);
+ bool IsOutOfDate = false;
- if ((StoredSize != File->getSize()
+ // For an overridden file, there is nothing to validate.
+ if (!Overridden && (StoredSize != File->getSize()
#if !defined(LLVM_ON_WIN32)
// In our regression testing, the Windows file system seems to
// have inconsistent modification times that sometimes
@@ -1590,12 +1602,15 @@ ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
#endif
)) {
if (Complain)
- Error(diag::err_fe_pch_file_modified, Filename);
-
- return InputFile();
+ Error(diag::err_fe_pch_file_modified, Filename, F.FileName);
+ IsOutOfDate = true;
}
- return InputFile(File, Overridden);
+ InputFile IF = InputFile(File, Overridden, IsOutOfDate);
+
+ // Note that we've loaded this input file.
+ F.InputFilesLoaded[ID-1] = IF;
+ return IF;
}
}
@@ -1665,12 +1680,16 @@ ASTReader::ReadControlBlock(ModuleFile &F,
Error("malformed block record in AST file");
return Failure;
case llvm::BitstreamEntry::EndBlock:
- // Validate all of the input files.
+ // Validate all of the non-system input files.
if (!DisableValidation) {
bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
- for (unsigned I = 0, N = Record[0]; I < N; ++I)
- if (!getInputFile(F, I+1, Complain).getPointer())
+ // All user input files reside at the index range [0, Record[1]).
+ // Record is the one from INPUT_FILE_OFFSETS.
+ for (unsigned I = 0, N = Record[1]; I < N; ++I) {
+ InputFile IF = getInputFile(F, I+1, Complain);
+ if (!IF.getFile() || IF.isOutOfDate())
return OutOfDate;
+ }
}
return Success;
@@ -2473,7 +2492,6 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case HEADER_SEARCH_TABLE: {
F.HeaderFileInfoTableData = Blob.data();
F.LocalNumHeaderFileInfos = Record[1];
- F.HeaderFileFrameworkStrings = Blob.data() + Record[2];
if (Record[0]) {
F.HeaderFileInfoTable
= HeaderFileInfoLookupTable::Create(
@@ -3982,7 +4000,7 @@ ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const {
GlobalSLocOffsetMapType::const_iterator
SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
- BLoc.getOffset());
+ BLoc.getOffset() - 1);
assert(SLocMapI != GlobalSLocOffsetMap.end() &&
"Corrupted global sloc offset map");
@@ -4030,7 +4048,7 @@ ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const {
GlobalSLocOffsetMapType::const_iterator
SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
- ELoc.getOffset());
+ ELoc.getOffset() - 1);
assert(SLocMapI != GlobalSLocOffsetMap.end() &&
"Corrupted global sloc offset map");
@@ -4089,32 +4107,25 @@ Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index,
namespace {
/// \brief Visitor used to search for information about a header file.
class HeaderFileInfoVisitor {
- ASTReader &Reader;
const FileEntry *FE;
Optional<HeaderFileInfo> HFI;
public:
- HeaderFileInfoVisitor(ASTReader &Reader, const FileEntry *FE)
- : Reader(Reader), FE(FE) { }
+ explicit HeaderFileInfoVisitor(const FileEntry *FE)
+ : FE(FE) { }
static bool visit(ModuleFile &M, void *UserData) {
HeaderFileInfoVisitor *This
= static_cast<HeaderFileInfoVisitor *>(UserData);
- HeaderFileInfoTrait Trait(This->Reader, M,
- &This->Reader.getPreprocessor().getHeaderSearchInfo(),
- M.HeaderFileFrameworkStrings,
- This->FE->getName());
-
HeaderFileInfoLookupTable *Table
= static_cast<HeaderFileInfoLookupTable *>(M.HeaderFileInfoTable);
if (!Table)
return false;
// Look in the on-disk hash table for an entry for this file name.
- HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE->getName(),
- &Trait);
+ HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE);
if (Pos == Table->end())
return false;
@@ -4127,7 +4138,7 @@ namespace {
}
HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
- HeaderFileInfoVisitor Visitor(*this, FE);
+ HeaderFileInfoVisitor Visitor(FE);
ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor);
if (Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) {
if (Listener)
@@ -4384,8 +4395,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
} else if (EST == EST_Unevaluated) {
EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
}
- return Context.getFunctionType(ResultType, ParamTypes.data(), NumParams,
- EPI);
+ return Context.getFunctionType(ResultType, ParamTypes, EPI);
}
case TYPE_UNRESOLVED_USING: {
diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h
index 5bbb7299d1..327da4403a 100644
--- a/lib/Serialization/ASTReaderInternals.h
+++ b/lib/Serialization/ASTReaderInternals.h
@@ -25,6 +25,7 @@ namespace clang {
class ASTReader;
class HeaderSearch;
struct HeaderFileInfo;
+class FileEntry;
namespace serialization {
@@ -196,34 +197,33 @@ class HeaderFileInfoTrait {
ModuleFile &M;
HeaderSearch *HS;
const char *FrameworkStrings;
- const char *SearchPath;
- struct stat SearchPathStatBuf;
public:
- typedef const char *external_key_type;
- typedef const char *internal_key_type;
+ typedef const FileEntry *external_key_type;
+
+ struct internal_key_type {
+ off_t Size;
+ time_t ModTime;
+ const char *Filename;
+ };
+ typedef const internal_key_type &internal_key_ref;
typedef HeaderFileInfo data_type;
HeaderFileInfoTrait(ASTReader &Reader, ModuleFile &M, HeaderSearch *HS,
- const char *FrameworkStrings,
- const char *SearchPath = 0)
- : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings),
- SearchPath(SearchPath) { }
+ const char *FrameworkStrings)
+ : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings) { }
- static unsigned ComputeHash(const char *path);
- static internal_key_type GetInternalKey(const char *path);
- bool EqualKey(internal_key_type a, internal_key_type b);
+ static unsigned ComputeHash(internal_key_ref ikey);
+ static internal_key_type GetInternalKey(const FileEntry *FE);
+ bool EqualKey(internal_key_ref a, internal_key_ref b);
static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char*& d);
- static internal_key_type ReadKey(const unsigned char *d, unsigned) {
- return (const char *)d;
- }
+ static internal_key_type ReadKey(const unsigned char *d, unsigned);
- data_type ReadData(const internal_key_type, const unsigned char *d,
- unsigned DataLen);
+ data_type ReadData(internal_key_ref,const unsigned char *d, unsigned DataLen);
};
/// \brief The on-disk hash table used for known header files.
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index b0e36e2e0d..815cf12f11 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -42,6 +42,7 @@
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/FileSystem.h"
@@ -1231,8 +1232,9 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev);
- // Write out all of the input files.
- std::vector<uint32_t> InputFileOffsets;
+ // Get all ContentCache objects for files, sorted by whether the file is a
+ // system one or not. System files go at the back, users files at the front.
+ std::deque<const SrcMgr::ContentCache *> SortedFiles;
for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) {
// Get this source location entry.
const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I);
@@ -1245,6 +1247,19 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
if (!Cache->OrigEntry)
continue;
+ if (Cache->IsSystemFile)
+ SortedFiles.push_back(Cache);
+ else
+ SortedFiles.push_front(Cache);
+ }
+
+ unsigned UserFilesNum = 0;
+ // Write out all of the input files.
+ std::vector<uint32_t> InputFileOffsets;
+ for (std::deque<const SrcMgr::ContentCache *>::iterator
+ I = SortedFiles.begin(), E = SortedFiles.end(); I != E; ++I) {
+ const SrcMgr::ContentCache *Cache = *I;
+
uint32_t &InputFileID = InputFileIDs[Cache->OrigEntry];
if (InputFileID != 0)
continue; // already recorded this file.
@@ -1254,6 +1269,9 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
InputFileID = InputFileOffsets.size();
+ if (!Cache->IsSystemFile)
+ ++UserFilesNum;
+
Record.clear();
Record.push_back(INPUT_FILE);
Record.push_back(InputFileOffsets.size());
@@ -1289,6 +1307,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
BitCodeAbbrev *OffsetsAbbrev = new BitCodeAbbrev();
OffsetsAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE_OFFSETS));
OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # input files
+ OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # non-system
+ // input files
OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Array
unsigned OffsetsAbbrevCode = Stream.EmitAbbrev(OffsetsAbbrev);
@@ -1296,6 +1316,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
Record.clear();
Record.push_back(INPUT_FILE_OFFSETS);
Record.push_back(InputFileOffsets.size());
+ Record.push_back(UserFilesNum);
Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, data(InputFileOffsets));
}
@@ -1372,32 +1393,38 @@ namespace {
HeaderFileInfoTrait(ASTWriter &Writer)
: Writer(Writer) { }
- typedef const char *key_type;
- typedef key_type key_type_ref;
+ struct key_type {
+ const FileEntry *FE;
+ const char *Filename;
+ };
+ typedef const key_type &key_type_ref;
typedef HeaderFileInfo data_type;
typedef const data_type &data_type_ref;
- static unsigned ComputeHash(const char *path) {
- // The hash is based only on the filename portion of the key, so that the
- // reader can match based on filenames when symlinking or excess path
- // elements ("foo/../", "../") change the form of the name. However,
- // complete path is still the key.
- return llvm::HashString(llvm::sys::path::filename(path));
+ static unsigned 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.
+ return llvm::hash_combine(key.FE->getSize(),
+ key.FE->getModificationTime());
}
std::pair<unsigned,unsigned>
- EmitKeyDataLength(raw_ostream& Out, const char *path,
- data_type_ref Data) {
- unsigned StrLen = strlen(path);
- clang::io::Emit16(Out, StrLen);
+ EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) {
+ unsigned KeyLen = strlen(key.Filename) + 1 + 8 + 8;
+ clang::io::Emit16(Out, KeyLen);
unsigned DataLen = 1 + 2 + 4 + 4;
clang::io::Emit8(Out, DataLen);
- return std::make_pair(StrLen + 1, DataLen);
+ return std::make_pair(KeyLen, DataLen);
}
- void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) {
- Out.write(path, KeyLen);
+ void EmitKey(raw_ostream& Out, key_type_ref key, unsigned KeyLen) {
+ clang::io::Emit64(Out, key.FE->getSize());
+ KeyLen -= 8;
+ clang::io::Emit64(Out, key.FE->getModificationTime());
+ KeyLen -= 8;
+ Out.write(key.Filename, KeyLen);
}
void EmitData(raw_ostream &Out, key_type_ref,
@@ -1479,7 +1506,8 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
SavedStrings.push_back(Filename);
}
- Generator.insert(Filename, HFI, GeneratorTrait);
+ HeaderFileInfoTrait::key_type key = { File, Filename };
+ Generator.insert(key, HFI, GeneratorTrait);
++NumHeaderSearchEntries;
}
@@ -1758,12 +1786,10 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
// Construct the list of macro definitions that need to be serialized.
SmallVector<std::pair<const IdentifierInfo *, MacroDirective *>, 2>
MacrosToEmit;
- llvm::SmallPtrSet<const IdentifierInfo*, 4> MacroDefinitionsSeen;
for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0),
E = PP.macro_end(Chain == 0);
I != E; ++I) {
if (!IsModule || I->second->isPublic()) {
- MacroDefinitionsSeen.insert(I->first);
MacrosToEmit.push_back(std::make_pair(I->first, I->second));
}
}
diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp
index 27242d54da..2eb397176a 100644
--- a/lib/Serialization/Module.cpp
+++ b/lib/Serialization/Module.cpp
@@ -33,7 +33,7 @@ ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
PreprocessedEntityOffsets(0), NumPreprocessedEntities(0),
LocalNumHeaderFileInfos(0),
HeaderFileInfoTableData(0), HeaderFileInfoTable(0),
- HeaderFileFrameworkStrings(0), LocalNumSubmodules(0), BaseSubmoduleID(0),
+ LocalNumSubmodules(0), BaseSubmoduleID(0),
LocalNumSelectors(0), SelectorOffsets(0), BaseSelectorID(0),
SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0),
DeclOffsets(0), BaseDeclID(0),
diff --git a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
deleted file mode 100644
index de5e6dca5e..0000000000
--- a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
-//===--- AttrNonNullChecker.h - Undefined arguments checker ----*- C++ -*--===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines AttrNonNullChecker, a builtin check in ExprEngine that
-// performs checks for arguments declared to have nonnull attribute.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangSACheckers.h"
-#include "clang/AST/Attr.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class AttrNonNullChecker
- : public Checker< check::PreCall > {
- mutable OwningPtr<BugType> BT;
-public:
-
- void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
-};
-} // end anonymous namespace
-
-void AttrNonNullChecker::checkPreCall(const CallEvent &Call,
- CheckerContext &C) const {
- const Decl *FD = Call.getDecl();
- if (!FD)
- return;
-
- const NonNullAttr *Att = FD->getAttr<NonNullAttr>();
- if (!Att)
- return;
-
- ProgramStateRef state = C.getState();
-
- // Iterate through the arguments of CE and check them for null.
- for (unsigned idx = 0, count = Call.getNumArgs(); idx != count; ++idx) {
- if (!Att->isNonNull(idx))
- continue;
-
- SVal V = Call.getArgSVal(idx);
- Optional<DefinedSVal> DV = V.getAs<DefinedSVal>();
-
- // If the value is unknown or undefined, we can't perform this check.
- if (!DV)
- continue;
-
- if (!DV->getAs<Loc>()) {
- // If the argument is a union type, we want to handle a potential
- // transparent_union GCC extension.
- const Expr *ArgE = Call.getArgExpr(idx);
- if (!ArgE)
- continue;
-
- QualType T = ArgE->getType();
- const RecordType *UT = T->getAsUnionType();
- if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
- continue;
-
- if (Optional<nonloc::CompoundVal> CSV =
- DV->getAs<nonloc::CompoundVal>()) {
- nonloc::CompoundVal::iterator CSV_I = CSV->begin();
- assert(CSV_I != CSV->end());
- V = *CSV_I;
- DV = V.getAs<DefinedSVal>();
- assert(++CSV_I == CSV->end());
- if (!DV)
- continue;
- } else {
- // FIXME: Handle LazyCompoundVals?
- continue;
- }
- }
-
- ConstraintManager &CM = C.getConstraintManager();
- ProgramStateRef stateNotNull, stateNull;
- llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
-
- if (stateNull && !stateNotNull) {
- // Generate an error node. Check for a null node in case
- // we cache out.
- if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
-
- // Lazily allocate the BugType object if it hasn't already been
- // created. Ownership is transferred to the BugReporter object once
- // the BugReport is passed to 'EmitWarning'.
- if (!BT)
- BT.reset(new BugType("Argument with 'nonnull' attribute passed null",
- "API"));
-
- BugReport *R =
- new BugReport(*BT, "Null pointer passed as an argument to a "
- "'nonnull' parameter", errorNode);
-
- // Highlight the range of the argument that was null.
- R->addRange(Call.getArgSourceRange(idx));
- if (const Expr *ArgE = Call.getArgExpr(idx))
- bugreporter::trackNullOrUndefValue(errorNode, ArgE, *R);
- // Emit the bug report.
- C.emitReport(R);
- }
-
- // Always return. Either we cached out or we just emitted an error.
- return;
- }
-
- // If a pointer value passed the check we should assume that it is
- // indeed not null from this point forward.
- assert(stateNotNull);
- state = stateNotNull;
- }
-
- // If we reach here all of the arguments passed the nonnull check.
- // If 'state' has been updated generated a new node.
- C.addTransition(state);
-}
-
-void ento::registerAttrNonNullChecker(CheckerManager &mgr) {
- mgr.registerChecker<AttrNonNullChecker>();
-}
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 26dbb7f250..fdb6bbbe52 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -384,7 +384,7 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
return;
// FIXME: The rest of this just checks that the argument is non-null.
- // It should probably be refactored and combined with AttrNonNullChecker.
+ // It should probably be refactored and combined with NonNullParamChecker.
// Get the argument's value.
const Expr *Arg = CE->getArg(0);
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 60d1e3e834..b7df10e7ff 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -7,7 +7,6 @@ add_clang_library(clangStaticAnalyzerCheckers
AnalyzerStatsChecker.cpp
ArrayBoundChecker.cpp
ArrayBoundCheckerV2.cpp
- AttrNonNullChecker.cpp
BasicObjCFoundationChecks.cpp
BoolAssignmentChecker.cpp
BuiltinFunctionChecker.cpp
@@ -43,6 +42,7 @@ add_clang_library(clangStaticAnalyzerCheckers
MallocSizeofChecker.cpp
NSAutoreleasePoolChecker.cpp
NSErrorChecker.cpp
+ NonNullParamChecker.cpp
NoReturnFunctionChecker.cpp
ObjCAtSyncChecker.cpp
ObjCContainersASTChecker.cpp
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index 5170b7a149..bbcf9aa438 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -60,9 +60,9 @@ def CallAndMessageChecker : Checker<"CallAndMessage">,
HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers)">,
DescFile<"CallAndMessageChecker.cpp">;
-def AttrNonNullChecker : Checker<"AttributeNonNull">,
- HelpText<"Check for null pointers passed as arguments to a function whose arguments are marked with the 'nonnull' attribute">,
- DescFile<"AttrNonNullChecker.cpp">;
+def NonNullParamChecker : Checker<"NonNullParamChecker">,
+ HelpText<"Check for null pointers passed as arguments to a function whose arguments are references or marked with the 'nonnull' attribute">,
+ DescFile<"NonNullParamChecker.cpp">;
def VLASizeChecker : Checker<"VLASize">,
HelpText<"Check for declarations of VLA of undefined or zero size">,
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index f412c049c7..28a2999f04 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -168,12 +168,13 @@ public:
private:
void initIdentifierInfo(ASTContext &C) const;
+ ///@{
/// Check if this is one of the functions which can allocate/reallocate memory
/// pointed to by one of its arguments.
bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const;
bool isFreeFunction(const FunctionDecl *FD, ASTContext &C) const;
bool isAllocationFunction(const FunctionDecl *FD, ASTContext &C) const;
-
+ ///@}
static ProgramStateRef MallocMemReturnsAttr(CheckerContext &C,
const CallExpr *CE,
const OwnershipAttr* Att);
@@ -218,10 +219,13 @@ private:
bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
const Stmt *S = 0) const;
- /// Check if the function is not known to us. So, for example, we could
- /// conservatively assume it can free/reallocate it's pointer arguments.
- bool doesNotFreeMemory(const CallEvent *Call,
- ProgramStateRef State) const;
+ /// Check if the function is known not to free memory, or if it is
+ /// "interesting" and should be modeled explicitly.
+ ///
+ /// We assume that pointers do not escape through calls to system functions
+ /// not handled by this checker.
+ bool doesNotFreeMemOrInteresting(const CallEvent *Call,
+ ProgramStateRef State) const;
static bool SummarizeValue(raw_ostream &os, SVal V);
static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
@@ -495,14 +499,30 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
C.addTransition(State);
}
-static bool isFreeWhenDoneSetToZero(const ObjCMethodCall &Call) {
+static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call) {
+ // If the first selector piece is one of the names below, assume that the
+ // object takes ownership of the memory, promising to eventually deallocate it
+ // with free().
+ // Ex: [NSData dataWithBytesNoCopy:bytes length:10];
+ // (...unless a 'freeWhenDone' parameter is false, but that's checked later.)
+ StringRef FirstSlot = Call.getSelector().getNameForSlot(0);
+ if (FirstSlot == "dataWithBytesNoCopy" ||
+ FirstSlot == "initWithBytesNoCopy" ||
+ FirstSlot == "initWithCharactersNoCopy")
+ return true;
+
+ return false;
+}
+
+static Optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) {
Selector S = Call.getSelector();
+
+ // FIXME: We should not rely on fully-constrained symbols being folded.
for (unsigned i = 1; i < S.getNumArgs(); ++i)
if (S.getNameForSlot(i).equals("freeWhenDone"))
- if (Call.getArgSVal(i).isConstant(0))
- return true;
+ return !Call.getArgSVal(i).isZeroConstant();
- return false;
+ return None;
}
void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
@@ -510,25 +530,20 @@ void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
if (C.wasInlined)
return;
- // If the first selector is dataWithBytesNoCopy, assume that the memory will
- // be released with 'free' by the new object.
- // Ex: [NSData dataWithBytesNoCopy:bytes length:10];
- // Unless 'freeWhenDone' param set to 0.
- // TODO: Check that the memory was allocated with malloc.
- bool ReleasedAllocatedMemory = false;
- Selector S = Call.getSelector();
- if ((S.getNameForSlot(0) == "dataWithBytesNoCopy" ||
- S.getNameForSlot(0) == "initWithBytesNoCopy" ||
- S.getNameForSlot(0) == "initWithCharactersNoCopy") &&
- !isFreeWhenDoneSetToZero(Call)){
- unsigned int argIdx = 0;
- ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(argIdx),
- Call.getOriginExpr(), C.getState(), true,
- ReleasedAllocatedMemory,
- /* RetNullOnFailure*/ true);
-
- C.addTransition(State);
- }
+ if (!isKnownDeallocObjCMethodName(Call))
+ return;
+
+ if (Optional<bool> FreeWhenDone = getFreeWhenDoneArg(Call))
+ if (!*FreeWhenDone)
+ return;
+
+ bool ReleasedAllocatedMemory;
+ ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(0),
+ Call.getOriginExpr(), C.getState(),
+ /*Hold=*/true, ReleasedAllocatedMemory,
+ /*RetNullOnFailure=*/true);
+
+ C.addTransition(State);
}
ProgramStateRef MallocChecker::MallocMemReturnsAttr(CheckerContext &C,
@@ -1356,12 +1371,8 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
return state;
}
-// Check if the function is known to us. So, for example, we could
-// conservatively assume it can free/reallocate its pointer arguments.
-// (We assume that the pointers cannot escape through calls to system
-// functions not handled by this checker.)
-bool MallocChecker::doesNotFreeMemory(const CallEvent *Call,
- ProgramStateRef State) const {
+bool MallocChecker::doesNotFreeMemOrInteresting(const CallEvent *Call,
+ ProgramStateRef State) const {
assert(Call);
// For now, assume that any C++ call can free memory.
@@ -1378,24 +1389,23 @@ bool MallocChecker::doesNotFreeMemory(const CallEvent *Call,
if (!Call->isInSystemHeader() || Call->hasNonZeroCallbackArg())
return false;
- Selector S = Msg->getSelector();
-
- // Whitelist the ObjC methods which do free memory.
- // - Anything containing 'freeWhenDone' param set to 1.
- // Ex: dataWithBytesNoCopy:length:freeWhenDone.
- for (unsigned i = 1; i < S.getNumArgs(); ++i) {
- if (S.getNameForSlot(i).equals("freeWhenDone")) {
- if (Call->getArgSVal(i).isConstant(1))
- return false;
- else
- return true;
- }
- }
+ // If it's a method we know about, handle it explicitly post-call.
+ // This should happen before the "freeWhenDone" check below.
+ if (isKnownDeallocObjCMethodName(*Msg))
+ return true;
- // If the first selector ends with NoCopy, assume that the ownership is
- // transferred as well.
- // Ex: [NSData dataWithBytesNoCopy:bytes length:10];
- StringRef FirstSlot = S.getNameForSlot(0);
+ // If there's a "freeWhenDone" parameter, but the method isn't one we know
+ // about, we can't be sure that the object will use free() to deallocate the
+ // memory, so we can't model it explicitly. The best we can do is use it to
+ // decide whether the pointer escapes.
+ if (Optional<bool> FreeWhenDone = getFreeWhenDoneArg(*Msg))
+ return !*FreeWhenDone;
+
+ // If the first selector piece ends with "NoCopy", and there is no
+ // "freeWhenDone" parameter set to zero, we know ownership is being
+ // transferred. Again, though, we can't be sure that the object will use
+ // free() to deallocate the memory, so we can't model it explicitly.
+ StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
if (FirstSlot.endswith("NoCopy"))
return false;
@@ -1504,11 +1514,11 @@ ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State,
const InvalidatedSymbols &Escaped,
const CallEvent *Call,
PointerEscapeKind Kind) const {
- // If we know that the call does not free memory, keep tracking the top
- // level arguments.
+ // If we know that the call does not free memory, or we want to process the
+ // call later, keep tracking the top level arguments.
if ((Kind == PSK_DirectEscapeOnCall ||
Kind == PSK_IndirectEscapeOnCall) &&
- doesNotFreeMemory(Call, State)) {
+ doesNotFreeMemOrInteresting(Call, State)) {
return State;
}
diff --git a/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
new file mode 100644
index 0000000000..273a7a3882
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
@@ -0,0 +1,193 @@
+//===--- NonNullParamChecker.cpp - Undefined arguments checker -*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines NonNullParamChecker, which checks for arguments expected not to
+// be null due to:
+// - the corresponding parameters being declared to have nonnull attribute
+// - the corresponding parameters being references; since the call would form
+// a reference to a null pointer
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/AST/Attr.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class NonNullParamChecker
+ : public Checker< check::PreCall > {
+ mutable OwningPtr<BugType> BTAttrNonNull;
+ mutable OwningPtr<BugType> BTNullRefArg;
+public:
+
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+
+ BugReport *genReportNullAttrNonNull(const ExplodedNode *ErrorN,
+ const Expr *ArgE) const;
+ BugReport *genReportReferenceToNullPointer(const ExplodedNode *ErrorN,
+ const Expr *ArgE) const;
+};
+} // end anonymous namespace
+
+void NonNullParamChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ const Decl *FD = Call.getDecl();
+ if (!FD)
+ return;
+
+ const NonNullAttr *Att = FD->getAttr<NonNullAttr>();
+
+ ProgramStateRef state = C.getState();
+
+ CallEvent::param_type_iterator TyI = Call.param_type_begin(),
+ TyE = Call.param_type_end();
+
+ for (unsigned idx = 0, count = Call.getNumArgs(); idx != count; ++idx){
+
+ // Check if the parameter is a reference. We want to report when reference
+ // to a null pointer is passed as a paramter.
+ bool haveRefTypeParam = false;
+ if (TyI != TyE) {
+ haveRefTypeParam = (*TyI)->isReferenceType();
+ TyI++;
+ }
+
+ bool haveAttrNonNull = Att && Att->isNonNull(idx);
+
+ if (!haveRefTypeParam && !haveAttrNonNull)
+ continue;
+
+ // If the value is unknown or undefined, we can't perform this check.
+ const Expr *ArgE = Call.getArgExpr(idx);
+ SVal V = Call.getArgSVal(idx);
+ Optional<DefinedSVal> DV = V.getAs<DefinedSVal>();
+ if (!DV)
+ continue;
+
+ // Process the case when the argument is not a location.
+ assert(!haveRefTypeParam || DV->getAs<Loc>());
+
+ if (haveAttrNonNull && !DV->getAs<Loc>()) {
+ // If the argument is a union type, we want to handle a potential
+ // transparent_union GCC extension.
+ if (!ArgE)
+ continue;
+
+ QualType T = ArgE->getType();
+ const RecordType *UT = T->getAsUnionType();
+ if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
+ continue;
+
+ if (Optional<nonloc::CompoundVal> CSV =
+ DV->getAs<nonloc::CompoundVal>()) {
+ nonloc::CompoundVal::iterator CSV_I = CSV->begin();
+ assert(CSV_I != CSV->end());
+ V = *CSV_I;
+ DV = V.getAs<DefinedSVal>();
+ assert(++CSV_I == CSV->end());
+ if (!DV)
+ continue;
+ // Retrieve the corresponding expression.
+ if (const CompoundLiteralExpr *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
+ if (const InitListExpr *IE =
+ dyn_cast<InitListExpr>(CE->getInitializer()))
+ ArgE = dyn_cast<Expr>(*(IE->begin()));
+
+ } else {
+ // FIXME: Handle LazyCompoundVals?
+ continue;
+ }
+ }
+
+ ConstraintManager &CM = C.getConstraintManager();
+ ProgramStateRef stateNotNull, stateNull;
+ llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
+
+ if (stateNull && !stateNotNull) {
+ // Generate an error node. Check for a null node in case
+ // we cache out.
+ if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
+
+ BugReport *R = 0;
+ if (haveAttrNonNull)
+ R = genReportNullAttrNonNull(errorNode, ArgE);
+ else if (haveRefTypeParam)
+ R = genReportReferenceToNullPointer(errorNode, ArgE);
+
+ // Highlight the range of the argument that was null.
+ R->addRange(Call.getArgSourceRange(idx));
+
+ // Emit the bug report.
+ C.emitReport(R);
+ }
+
+ // Always return. Either we cached out or we just emitted an error.
+ return;
+ }
+
+ // If a pointer value passed the check we should assume that it is
+ // indeed not null from this point forward.
+ assert(stateNotNull);
+ state = stateNotNull;
+ }
+
+ // If we reach here all of the arguments passed the nonnull check.
+ // If 'state' has been updated generated a new node.
+ C.addTransition(state);
+}
+
+BugReport *NonNullParamChecker::genReportNullAttrNonNull(
+ const ExplodedNode *ErrorNode, const Expr *ArgE) const {
+ // Lazily allocate the BugType object if it hasn't already been
+ // created. Ownership is transferred to the BugReporter object once
+ // the BugReport is passed to 'EmitWarning'.
+ if (!BTAttrNonNull)
+ BTAttrNonNull.reset(new BugType(
+ "Argument with 'nonnull' attribute passed null",
+ "API"));
+
+ BugReport *R = new BugReport(*BTAttrNonNull,
+ "Null pointer passed as an argument to a 'nonnull' parameter",
+ ErrorNode);
+ if (ArgE)
+ bugreporter::trackNullOrUndefValue(ErrorNode, ArgE, *R);
+
+ return R;
+}
+
+BugReport *NonNullParamChecker::genReportReferenceToNullPointer(
+ const ExplodedNode *ErrorNode, const Expr *ArgE) const {
+ if (!BTNullRefArg)
+ BTNullRefArg.reset(new BuiltinBug("Dereference of null pointer"));
+
+ BugReport *R = new BugReport(*BTNullRefArg,
+ "Forming reference to null pointer",
+ ErrorNode);
+ if (ArgE) {
+ const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
+ if (ArgEDeref == 0)
+ ArgEDeref = ArgE;
+ bugreporter::trackNullOrUndefValue(ErrorNode,
+ ArgEDeref,
+ *R);
+ }
+ return R;
+
+}
+
+void ento::registerNonNullParamChecker(CheckerManager &mgr) {
+ mgr.registerChecker<NonNullParamChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 3edc997503..856463a981 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -1133,12 +1133,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
if (S)
break;
- if (RetTy->isPointerType()) {
- if (FD->getAttr<CFAuditedTransferAttr>()) {
- S = getCFCreateGetRuleSummary(FD);
- break;
- }
-
+ if (RetTy->isPointerType()) {
// For CoreFoundation ('CF') types.
if (cocoa::isRefType(RetTy, "CF", FName)) {
if (isRetain(FD, FName))
@@ -1169,6 +1164,11 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
break;
}
+ if (FD->getAttr<CFAuditedTransferAttr>()) {
+ S = getCFCreateGetRuleSummary(FD);
+ break;
+ }
+
break;
}
diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
index 1fa4ab9ff7..7a5d993601 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
@@ -24,9 +24,13 @@ using namespace clang;
using namespace ento;
namespace {
-class ReturnUndefChecker :
- public Checker< check::PreStmt<ReturnStmt> > {
- mutable OwningPtr<BuiltinBug> BT;
+class ReturnUndefChecker : public Checker< check::PreStmt<ReturnStmt> > {
+ mutable OwningPtr<BuiltinBug> BT_Undef;
+ mutable OwningPtr<BuiltinBug> BT_NullReference;
+
+ void emitUndef(CheckerContext &C, const Expr *RetE) const;
+ void checkReference(CheckerContext &C, const Expr *RetE,
+ DefinedOrUnknownSVal RetVal) const;
public:
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
};
@@ -34,43 +38,75 @@ public:
void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
CheckerContext &C) const {
-
const Expr *RetE = RS->getRetValue();
if (!RetE)
return;
-
- if (!C.getState()->getSVal(RetE, C.getLocationContext()).isUndef())
- return;
-
- // "return;" is modeled to evaluate to an UndefinedValue. Allow UndefinedValue
- // to be returned in functions returning void to support the following pattern:
- // void foo() {
- // return;
- // }
- // void test() {
- // return foo();
- // }
+ SVal RetVal = C.getSVal(RetE);
+
const StackFrameContext *SFC = C.getStackFrame();
QualType RT = CallEvent::getDeclaredResultType(SFC->getDecl());
- if (!RT.isNull() && RT->isSpecificBuiltinType(BuiltinType::Void))
+
+ if (RetVal.isUndef()) {
+ // "return;" is modeled to evaluate to an UndefinedVal. Allow UndefinedVal
+ // to be returned in functions returning void to support this pattern:
+ // void foo() {
+ // return;
+ // }
+ // void test() {
+ // return foo();
+ // }
+ if (RT.isNull() || !RT->isVoidType())
+ emitUndef(C, RetE);
return;
+ }
- ExplodedNode *N = C.generateSink();
+ if (RT.isNull())
+ return;
+ if (RT->isReferenceType()) {
+ checkReference(C, RetE, RetVal.castAs<DefinedOrUnknownSVal>());
+ return;
+ }
+}
+
+static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE,
+ const Expr *TrackingE = 0) {
+ ExplodedNode *N = C.generateSink();
if (!N)
return;
-
- if (!BT)
- BT.reset(new BuiltinBug("Garbage return value",
- "Undefined or garbage value returned to caller"));
-
- BugReport *report =
- new BugReport(*BT, BT->getDescription(), N);
-
- report->addRange(RetE->getSourceRange());
- bugreporter::trackNullOrUndefValue(N, RetE, *report);
-
- C.emitReport(report);
+
+ BugReport *Report = new BugReport(BT, BT.getDescription(), N);
+
+ Report->addRange(RetE->getSourceRange());
+ bugreporter::trackNullOrUndefValue(N, TrackingE ? TrackingE : RetE, *Report);
+
+ C.emitReport(Report);
+}
+
+void ReturnUndefChecker::emitUndef(CheckerContext &C, const Expr *RetE) const {
+ if (!BT_Undef)
+ BT_Undef.reset(new BuiltinBug("Garbage return value",
+ "Undefined or garbage value "
+ "returned to caller"));
+ emitBug(C, *BT_Undef, RetE);
+}
+
+void ReturnUndefChecker::checkReference(CheckerContext &C, const Expr *RetE,
+ DefinedOrUnknownSVal RetVal) const {
+ ProgramStateRef StNonNull, StNull;
+ llvm::tie(StNonNull, StNull) = C.getState()->assume(RetVal);
+
+ if (StNonNull) {
+ // Going forward, assume the location is non-null.
+ C.addTransition(StNonNull);
+ return;
+ }
+
+ // The return value is known to be null. Emit a bug report.
+ if (!BT_NullReference)
+ BT_NullReference.reset(new BuiltinBug("Returning null reference"));
+
+ emitBug(C, *BT_NullReference, RetE, bugreporter::getDerefExpr(RetE));
}
void ento::registerReturnUndefChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index 5198f4973a..dca68f71ab 100644
--- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -152,6 +152,12 @@ bool AnalyzerOptions::shouldAvoidSuppressingNullArgumentPaths() {
/* Default = */ false);
}
+bool AnalyzerOptions::shouldSuppressInlinedDefensiveChecks() {
+ return getBooleanOption(SuppressInlinedDefensiveChecks,
+ "suppress-inlined-defensive-checks",
+ /* Default = */ true);
+}
+
int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) {
SmallString<10> StrBuf;
llvm::raw_svector_ostream OS(StrBuf);
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index d712c18b78..517c1a10f8 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -27,6 +27,8 @@
using namespace clang;
using namespace ento;
+using llvm::FoldingSetNodeID;
+
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
@@ -132,13 +134,14 @@ class ReturnVisitor : public BugReporterVisitorImpl<ReturnVisitor> {
const StackFrameContext *StackFrame;
enum {
Initial,
- MaybeSuppress,
+ MaybeUnsuppress,
Satisfied
} Mode;
+ bool InitiallySuppressed;
public:
- ReturnVisitor(const StackFrameContext *Frame)
- : StackFrame(Frame), Mode(Initial) {}
+ ReturnVisitor(const StackFrameContext *Frame, bool Suppressed)
+ : StackFrame(Frame), Mode(Initial), InitiallySuppressed(Suppressed) {}
static void *getTag() {
static int Tag = 0;
@@ -148,6 +151,7 @@ public:
virtual void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(ReturnVisitor::getTag());
ID.AddPointer(StackFrame);
+ ID.AddBoolean(InitiallySuppressed);
}
/// Adds a ReturnVisitor if the given statement represents a call that was
@@ -177,17 +181,39 @@ public:
// Next, step over any post-statement checks.
while (Node && Node->getLocation().getAs<PostStmt>())
Node = Node->getFirstPred();
+ if (!Node)
+ return;
// Finally, see if we inlined the call.
- if (Node) {
- if (Optional<CallExitEnd> CEE = Node->getLocationAs<CallExitEnd>()) {
- const StackFrameContext *CalleeContext = CEE->getCalleeContext();
- if (CalleeContext->getCallSite() == S) {
- BR.markInteresting(CalleeContext);
- BR.addVisitor(new ReturnVisitor(CalleeContext));
- }
- }
- }
+ Optional<CallExitEnd> CEE = Node->getLocationAs<CallExitEnd>();
+ if (!CEE)
+ return;
+
+ const StackFrameContext *CalleeContext = CEE->getCalleeContext();
+ if (CalleeContext->getCallSite() != S)
+ return;
+
+ // Check the return value.
+ ProgramStateRef State = Node->getState();
+ SVal RetVal = State->getSVal(S, Node->getLocationContext());
+
+ // Handle cases where a reference is returned and then immediately used.
+ if (cast<Expr>(S)->isGLValue())
+ if (Optional<Loc> LValue = RetVal.getAs<Loc>())
+ RetVal = State->getSVal(*LValue);
+
+ // See if the return value is NULL. If so, suppress the report.
+ SubEngine *Eng = State->getStateManager().getOwningEngine();
+ assert(Eng && "Cannot file a bug report without an owning engine");
+ AnalyzerOptions &Options = Eng->getAnalysisManager().options;
+
+ bool InitiallySuppressed = false;
+ if (Options.shouldSuppressNullReturnPaths())
+ if (Optional<Loc> RetLoc = RetVal.getAs<Loc>())
+ InitiallySuppressed = !State->assume(*RetLoc, true);
+
+ BR.markInteresting(CalleeContext);
+ BR.addVisitor(new ReturnVisitor(CalleeContext, InitiallySuppressed));
}
/// Returns true if any counter-suppression heuristics are enabled for
@@ -222,13 +248,24 @@ public:
// Don't print any more notes after this one.
Mode = Satisfied;
+ const Expr *RetE = Ret->getRetValue();
+ assert(RetE && "Tracking a return value for a void function");
+
+ // Handle cases where a reference is returned and then immediately used.
+ Optional<Loc> LValue;
+ if (RetE->isGLValue()) {
+ if ((LValue = V.getAs<Loc>())) {
+ SVal RValue = State->getRawSVal(*LValue, RetE->getType());
+ if (RValue.getAs<DefinedSVal>())
+ V = RValue;
+ }
+ }
+
// Ignore aggregate rvalues.
if (V.getAs<nonloc::LazyCompoundVal>() ||
V.getAs<nonloc::CompoundVal>())
return 0;
- const Expr *RetE = Ret->getRetValue();
- assert(RetE && "Tracking a return value for a void function");
RetE = RetE->IgnoreParenCasts();
// If we can't prove the return value is 0, just mark it interesting, and
@@ -247,17 +284,13 @@ public:
llvm::raw_svector_ostream Out(Msg);
if (V.getAs<Loc>()) {
- // If we are pruning null-return paths as unlikely error paths, mark the
- // report invalid. We still want to emit a path note, however, in case
+ // If we have counter-suppression enabled, make sure we keep visiting
+ // future nodes. We want to emit a path note as well, in case
// the report is resurrected as valid later on.
ExprEngine &Eng = BRC.getBugReporter().getEngine();
AnalyzerOptions &Options = Eng.getAnalysisManager().options;
- if (Options.shouldSuppressNullReturnPaths()) {
- if (hasCounterSuppression(Options))
- Mode = MaybeSuppress;
- else
- BR.markInvalid(ReturnVisitor::getTag(), StackFrame);
- }
+ if (InitiallySuppressed && hasCounterSuppression(Options))
+ Mode = MaybeUnsuppress;
if (RetE->getType()->isObjCObjectPointerType())
Out << "Returning nil";
@@ -267,19 +300,35 @@ public:
Out << "Returning zero";
}
- // FIXME: We should have a more generalized location printing mechanism.
- if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE))
- if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
- Out << " (loaded from '" << *DD << "')";
+ if (LValue) {
+ if (const MemRegion *MR = LValue->getAsRegion()) {
+ if (MR->canPrintPretty()) {
+ Out << " (reference to '";
+ MR->printPretty(Out);
+ Out << "')";
+ }
+ }
+ } else {
+ // FIXME: We should have a more generalized location printing mechanism.
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE))
+ if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
+ Out << " (loaded from '" << *DD << "')";
+ }
PathDiagnosticLocation L(Ret, BRC.getSourceManager(), StackFrame);
return new PathDiagnosticEventPiece(L, Out.str());
}
- PathDiagnosticPiece *visitNodeMaybeSuppress(const ExplodedNode *N,
- const ExplodedNode *PrevN,
- BugReporterContext &BRC,
- BugReport &BR) {
+ PathDiagnosticPiece *visitNodeMaybeUnsuppress(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+#ifndef NDEBUG
+ ExprEngine &Eng = BRC.getBugReporter().getEngine();
+ AnalyzerOptions &Options = Eng.getAnalysisManager().options;
+ assert(hasCounterSuppression(Options));
+#endif
+
// Are we at the entry node for this call?
Optional<CallEnter> CE = N->getLocationAs<CallEnter>();
if (!CE)
@@ -290,41 +339,35 @@ public:
Mode = Satisfied;
- ExprEngine &Eng = BRC.getBugReporter().getEngine();
- AnalyzerOptions &Options = Eng.getAnalysisManager().options;
- if (Options.shouldAvoidSuppressingNullArgumentPaths()) {
- // Don't automatically suppress a report if one of the arguments is
- // known to be a null pointer. Instead, start tracking /that/ null
- // value back to its origin.
- ProgramStateManager &StateMgr = BRC.getStateManager();
- CallEventManager &CallMgr = StateMgr.getCallEventManager();
-
- ProgramStateRef State = N->getState();
- CallEventRef<> Call = CallMgr.getCaller(StackFrame, State);
- for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) {
- SVal ArgV = Call->getArgSVal(I);
- if (!ArgV.getAs<Loc>())
- continue;
-
- const Expr *ArgE = Call->getArgExpr(I);
- if (!ArgE)
- continue;
-
- // Is it possible for this argument to be non-null?
- if (State->assume(ArgV.castAs<Loc>(), true))
- continue;
-
- if (bugreporter::trackNullOrUndefValue(N, ArgE, BR, /*IsArg=*/true))
- return 0;
+ // Don't automatically suppress a report if one of the arguments is
+ // known to be a null pointer. Instead, start tracking /that/ null
+ // value back to its origin.
+ ProgramStateManager &StateMgr = BRC.getStateManager();
+ CallEventManager &CallMgr = StateMgr.getCallEventManager();
- // If we /can't/ track the null pointer, we should err on the side of
- // false negatives, and continue towards marking this report invalid.
- // (We will still look at the other arguments, though.)
- }
+ ProgramStateRef State = N->getState();
+ CallEventRef<> Call = CallMgr.getCaller(StackFrame, State);
+ for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) {
+ Optional<Loc> ArgV = Call->getArgSVal(I).getAs<Loc>();
+ if (!ArgV)
+ continue;
+
+ const Expr *ArgE = Call->getArgExpr(I);
+ if (!ArgE)
+ continue;
+
+ // Is it possible for this argument to be non-null?
+ if (State->assume(*ArgV, true))
+ continue;
+
+ if (bugreporter::trackNullOrUndefValue(N, ArgE, BR, /*IsArg=*/true))
+ BR.removeInvalidation(ReturnVisitor::getTag(), StackFrame);
+
+ // If we /can't/ track the null pointer, we should err on the side of
+ // false negatives, and continue towards marking this report invalid.
+ // (We will still look at the other arguments, though.)
}
- // There is no reason not to suppress this report; go ahead and do it.
- BR.markInvalid(ReturnVisitor::getTag(), StackFrame);
return 0;
}
@@ -335,14 +378,22 @@ public:
switch (Mode) {
case Initial:
return visitNodeInitial(N, PrevN, BRC, BR);
- case MaybeSuppress:
- return visitNodeMaybeSuppress(N, PrevN, BRC, BR);
+ case MaybeUnsuppress:
+ return visitNodeMaybeUnsuppress(N, PrevN, BRC, BR);
case Satisfied:
return 0;
}
llvm_unreachable("Invalid visit mode!");
}
+
+ PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR) {
+ if (InitiallySuppressed)
+ BR.markInvalid(ReturnVisitor::getTag(), StackFrame);
+ return 0;
+ }
};
} // end anonymous namespace
@@ -642,25 +693,101 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
return NULL;
}
-bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
+SuppressInlineDefensiveChecksVisitor::
+SuppressInlineDefensiveChecksVisitor(DefinedSVal Value, const ExplodedNode *N)
+ : V(Value), IsSatisfied(false), StartN(N) {
+
+ assert(N->getState()->isNull(V).isConstrainedTrue() &&
+ "The visitor only tracks the cases where V is constrained to 0");
+}
+
+void SuppressInlineDefensiveChecksVisitor::Profile(FoldingSetNodeID &ID) const {
+ static int id = 0;
+ ID.AddPointer(&id);
+ ID.AddPointer(StartN);
+ ID.Add(V);
+}
+
+const char *SuppressInlineDefensiveChecksVisitor::getTag() {
+ return "IDCVisitor";
+}
+
+PathDiagnosticPiece *
+SuppressInlineDefensiveChecksVisitor::getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR) {
+ if (StartN == BR.getErrorNode())
+ StartN = 0;
+ return 0;
+}
+
+PathDiagnosticPiece *
+SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ if (IsSatisfied)
+ return 0;
+
+ // Start tracking after we see node StartN.
+ if (StartN == Succ)
+ StartN = 0;
+ if (StartN)
+ return 0;
+
+ AnalyzerOptions &Options =
+ BRC.getBugReporter().getEngine().getAnalysisManager().options;
+ if (!Options.shouldSuppressInlinedDefensiveChecks())
+ return 0;
+
+ // Check if in the previous state it was feasible for this value
+ // to *not* be null.
+ if (Pred->getState()->assume(V, true)) {
+ IsSatisfied = true;
+
+ assert(!Succ->getState()->assume(V, true));
+
+ // Check if this is inlined defensive checks.
+ const LocationContext *CurLC =Succ->getLocationContext();
+ const LocationContext *ReportLC = BR.getErrorNode()->getLocationContext();
+ if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC))
+ BR.markInvalid("Suppress IDC", CurLC);
+ }
+ return 0;
+}
+
+bool bugreporter::trackNullOrUndefValue(const ExplodedNode *ErrorNode,
+ const Stmt *S,
BugReport &report, bool IsArg) {
- if (!S || !N)
+ if (!S || !ErrorNode)
return false;
if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S))
S = OVE->getSourceExpr();
+ const ExplodedNode *N = ErrorNode;
+
+ const Expr *Inner = 0;
+ if (const Expr *Ex = dyn_cast<Expr>(S)) {
+ Ex = Ex->IgnoreParenCasts();
+ if (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex))
+ Inner = Ex;
+ }
+
if (IsArg) {
assert(N->getLocation().getAs<CallEnter>() && "Tracking arg but not at call");
} else {
// Walk through nodes until we get one that matches the statement exactly.
+ // Alternately, if we hit a known lvalue for the statement, we know we've
+ // gone too far (though we can likely track the lvalue better anyway).
do {
const ProgramPoint &pp = N->getLocation();
if (Optional<PostStmt> ps = pp.getAs<PostStmt>()) {
- if (ps->getStmt() == S)
+ if (ps->getStmt() == S || ps->getStmt() == Inner)
break;
} else if (Optional<CallExitEnd> CEE = pp.getAs<CallExitEnd>()) {
- if (CEE->getCalleeContext()->getCallSite() == S)
+ if (CEE->getCalleeContext()->getCallSite() == S ||
+ CEE->getCalleeContext()->getCallSite() == Inner)
break;
}
N = N->getFirstPred();
@@ -674,91 +801,85 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
// See if the expression we're interested refers to a variable.
// If so, we can track both its contents and constraints on its value.
- if (const Expr *Ex = dyn_cast<Expr>(S)) {
- // Strip off parens and casts. Note that this will never have issues with
- // C++ user-defined implicit conversions, because those have a constructor
- // or function call inside.
- Ex = Ex->IgnoreParenCasts();
+ if (Inner && ExplodedGraph::isInterestingLValueExpr(Inner)) {
+ const MemRegion *R = 0;
- if (ExplodedGraph::isInterestingLValueExpr(Ex)) {
- const MemRegion *R = 0;
-
- // First check if this is a DeclRefExpr for a C++ reference type.
- // For those, we want the location of the reference.
- if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- if (VD->getType()->isReferenceType()) {
- ProgramStateManager &StateMgr = state->getStateManager();
- MemRegionManager &MRMgr = StateMgr.getRegionManager();
- R = MRMgr.getVarRegion(VD, N->getLocationContext());
- }
+ // First check if this is a DeclRefExpr for a C++ reference type.
+ // For those, we want the location of the reference.
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Inner)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ if (VD->getType()->isReferenceType()) {
+ ProgramStateManager &StateMgr = state->getStateManager();
+ MemRegionManager &MRMgr = StateMgr.getRegionManager();
+ R = MRMgr.getVarRegion(VD, N->getLocationContext());
}
}
+ }
- // For all other cases, find the location by scouring the ExplodedGraph.
- if (!R) {
- // Find the ExplodedNode where the lvalue (the value of 'Ex')
- // was computed. We need this for getting the location value.
- const ExplodedNode *LVNode = N;
- const Expr *SearchEx = Ex;
- if (const OpaqueValueExpr *OPE = dyn_cast<OpaqueValueExpr>(Ex)) {
- SearchEx = OPE->getSourceExpr();
- }
- while (LVNode) {
- if (Optional<PostStmt> P = LVNode->getLocation().getAs<PostStmt>()) {
- if (P->getStmt() == SearchEx)
- break;
- }
- LVNode = LVNode->getFirstPred();
- }
- assert(LVNode && "Unable to find the lvalue node.");
- ProgramStateRef LVState = LVNode->getState();
- if (Optional<Loc> L =
- LVState->getSVal(Ex, LVNode->getLocationContext()).getAs<Loc>()) {
- R = L->getAsRegion();
+ // For all other cases, find the location by scouring the ExplodedGraph.
+ if (!R) {
+ // Find the ExplodedNode where the lvalue (the value of 'Ex')
+ // was computed. We need this for getting the location value.
+ const ExplodedNode *LVNode = N;
+ while (LVNode) {
+ if (Optional<PostStmt> P = LVNode->getLocation().getAs<PostStmt>()) {
+ if (P->getStmt() == Inner)
+ break;
}
+ LVNode = LVNode->getFirstPred();
}
+ assert(LVNode && "Unable to find the lvalue node.");
+ ProgramStateRef LVState = LVNode->getState();
+ R = LVState->getSVal(Inner, LVNode->getLocationContext()).getAsRegion();
+ }
- if (R) {
- // Mark both the variable region and its contents as interesting.
- SVal V = state->getRawSVal(loc::MemRegionVal(R));
-
- // If the value matches the default for the variable region, that
- // might mean that it's been cleared out of the state. Fall back to
- // the full argument expression (with casts and such intact).
- if (IsArg) {
- bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant();
- if (!UseArgValue) {
- const SymbolRegionValue *SRV =
- dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol());
- if (SRV)
- UseArgValue = (SRV->getRegion() == R);
- }
- if (UseArgValue)
- V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
+ if (R) {
+ // Mark both the variable region and its contents as interesting.
+ SVal V = state->getRawSVal(loc::MemRegionVal(R));
+
+ // If the value matches the default for the variable region, that
+ // might mean that it's been cleared out of the state. Fall back to
+ // the full argument expression (with casts and such intact).
+ if (IsArg) {
+ bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant();
+ if (!UseArgValue) {
+ const SymbolRegionValue *SRV =
+ dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol());
+ if (SRV)
+ UseArgValue = (SRV->getRegion() == R);
}
+ if (UseArgValue)
+ V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
+ }
- report.markInteresting(R);
- report.markInteresting(V);
- report.addVisitor(new UndefOrNullArgVisitor(R));
+ report.markInteresting(R);
+ report.markInteresting(V);
+ report.addVisitor(new UndefOrNullArgVisitor(R));
- if (isa<SymbolicRegion>(R)) {
- TrackConstraintBRVisitor *VI =
- new TrackConstraintBRVisitor(loc::MemRegionVal(R), false);
- report.addVisitor(VI);
- }
+ if (isa<SymbolicRegion>(R)) {
+ TrackConstraintBRVisitor *VI =
+ new TrackConstraintBRVisitor(loc::MemRegionVal(R), false);
+ report.addVisitor(VI);
+ }
- // If the contents are symbolic, find out when they became null.
- if (V.getAsLocSymbol()) {
- BugReporterVisitor *ConstraintTracker =
- new TrackConstraintBRVisitor(V.castAs<DefinedSVal>(), false);
- report.addVisitor(ConstraintTracker);
+ // If the contents are symbolic, find out when they became null.
+ if (V.getAsLocSymbol()) {
+ BugReporterVisitor *ConstraintTracker =
+ new TrackConstraintBRVisitor(V.castAs<DefinedSVal>(), false);
+ report.addVisitor(ConstraintTracker);
+
+ // Add visitor, which will suppress inline defensive checks.
+ if (ErrorNode->getState()->isNull(V).isConstrainedTrue()) {
+ BugReporterVisitor *IDCSuppressor =
+ new SuppressInlineDefensiveChecksVisitor(V.castAs<DefinedSVal>(),
+ ErrorNode);
+ report.addVisitor(IDCSuppressor);
}
-
- if (Optional<KnownSVal> KV = V.getAs<KnownSVal>())
- report.addVisitor(new FindLastStoreBRVisitor(*KV, R));
- return true;
}
+
+ if (Optional<KnownSVal> KV = V.getAs<KnownSVal>())
+ report.addVisitor(new FindLastStoreBRVisitor(*KV, R));
+ return true;
}
}
@@ -766,6 +887,12 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
// track the constraints on its contents.
SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
+ // If the value came from an inlined function call, we should at least make
+ // sure that function isn't pruned in our output.
+ if (const Expr *E = dyn_cast<Expr>(S))
+ S = E->IgnoreParenCasts();
+ ReturnVisitor::addVisitorIfNecessary(N, S, report);
+
// Uncomment this to find cases where we aren't properly getting the
// base value that was dereferenced.
// assert(!V.isUnknownOrUndef());
@@ -777,18 +904,11 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
const MemRegion *RegionRVal = RVal.getAsRegion();
report.addVisitor(new UndefOrNullArgVisitor(L->getRegion()));
-
if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) {
report.markInteresting(RegionRVal);
report.addVisitor(new TrackConstraintBRVisitor(
loc::MemRegionVal(RegionRVal), false));
}
- } else {
- // Otherwise, if the value came from an inlined function call,
- // we should at least make sure that function isn't pruned in our output.
- if (const Expr *E = dyn_cast<Expr>(S))
- S = E->IgnoreParenCasts();
- ReturnVisitor::addVisitorIfNecessary(N, S, report);
}
return true;
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index 933df48988..c482978ca2 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -271,7 +271,6 @@ bool CallEvent::isCallStmt(const Stmt *S) {
|| isa<CXXNewExpr>(S);
}
-/// \brief Returns the result type, adjusted for references.
QualType CallEvent::getDeclaredResultType(const Decl *D) {
assert(D);
if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D))
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 9bc890847c..2f2eb8628a 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -649,6 +649,8 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
break;
}
+ assert(SrcBlock && "missing function entry");
+
// Find the last expression in the predecessor block. That is the
// expression that is used for the value of the ternary expression.
bool hasValue = false;
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index 12e43537aa..b3a1e65b19 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -195,6 +195,10 @@ DefinedOrUnknownSVal TypedValueRegion::getExtent(SValBuilder &svalBuilder) const
}
DefinedOrUnknownSVal FieldRegion::getExtent(SValBuilder &svalBuilder) const {
+ // Force callers to deal with bitfields explicitly.
+ if (getDecl()->isBitField())
+ return UnknownVal();
+
DefinedOrUnknownSVal Extent = DeclRegion::getExtent(svalBuilder);
// A zero-length array at the end of a struct often stands for dynamically-
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 400569e49a..64205f8d99 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -324,6 +324,16 @@ ProgramStateRef ProgramState::assumeInBound(DefinedOrUnknownSVal Idx,
return CM.assume(this, inBound.castAs<DefinedSVal>(), Assumption);
}
+ConditionTruthVal ProgramState::isNull(SVal V) const {
+ if (V.isZeroConstant())
+ return true;
+
+ SymbolRef Sym = V.getAsSymbol();
+ if (!Sym)
+ return false;
+ return getStateManager().ConstraintMgr->isNull(this, Sym);
+}
+
ProgramStateRef ProgramStateManager::getInitialState(const LocationContext *InitLoc) {
ProgramState State(this,
EnvMgr.getInitialEnvironment(),
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index b93c10d680..82db23dd6b 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -757,9 +757,7 @@ collectSubRegionBindings(SmallVectorImpl<BindingPair> &Bindings,
TopKey = BindingKey::Make(Top, BindingKey::Default);
}
- // This assumes the region being invalidated is char-aligned. This isn't
- // true for bitfields, but since bitfields have no subregions they shouldn't
- // be using this function anyway.
+ // Find the length (in bits) of the region being invalidated.
uint64_t Length = UINT64_MAX;
SVal Extent = Top->getExtent(SVB);
if (Optional<nonloc::ConcreteInt> ExtentCI =
@@ -768,6 +766,9 @@ collectSubRegionBindings(SmallVectorImpl<BindingPair> &Bindings,
assert(ExtentInt.isNonNegative() || ExtentInt.isUnsigned());
// Extents are in bytes but region offsets are in bits. Be careful!
Length = ExtentInt.getLimitedValue() * SVB.getContext().getCharWidth();
+ } else if (const FieldRegion *FR = dyn_cast<FieldRegion>(Top)) {
+ if (FR->getDecl()->isBitField())
+ Length = FR->getDecl()->getBitWidthValue(SVB.getContext());
}
for (ClusterBindings::iterator I = Cluster.begin(), E = Cluster.end();
diff --git a/lib/Tooling/JSONCompilationDatabase.cpp b/lib/Tooling/JSONCompilationDatabase.cpp
index 9013f2143f..254b069952 100644
--- a/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/lib/Tooling/JSONCompilationDatabase.cpp
@@ -49,7 +49,9 @@ class CommandLineArgumentParser {
bool parseStringInto(std::string &String) {
do {
if (*Position == '"') {
- if (!parseQuotedStringInto(String)) return false;
+ if (!parseDoubleQuotedStringInto(String)) return false;
+ } else if (*Position == '\'') {
+ if (!parseSingleQuotedStringInto(String)) return false;
} else {
if (!parseFreeStringInto(String)) return false;
}
@@ -57,7 +59,7 @@ class CommandLineArgumentParser {
return true;
}
- bool parseQuotedStringInto(std::string &String) {
+ bool parseDoubleQuotedStringInto(std::string &String) {
if (!next()) return false;
while (*Position != '"') {
if (!skipEscapeCharacter()) return false;
@@ -67,12 +69,21 @@ class CommandLineArgumentParser {
return next();
}
+ bool parseSingleQuotedStringInto(std::string &String) {
+ if (!next()) return false;
+ while (*Position != '\'') {
+ String.push_back(*Position);
+ if (!next()) return false;
+ }
+ return next();
+ }
+
bool parseFreeStringInto(std::string &String) {
do {
if (!skipEscapeCharacter()) return false;
String.push_back(*Position);
if (!next()) return false;
- } while (*Position != ' ' && *Position != '"');
+ } while (*Position != ' ' && *Position != '"' && *Position != '\'');
return true;
}
diff --git a/test/Analysis/Inputs/system-header-simulator-for-malloc.h b/test/Analysis/Inputs/system-header-simulator-for-malloc.h
new file mode 100644
index 0000000000..e76455655e
--- /dev/null
+++ b/test/Analysis/Inputs/system-header-simulator-for-malloc.h
@@ -0,0 +1,34 @@
+// Like the compiler, the static analyzer treats some functions differently if
+// they come from a system header -- for example, it is assumed that system
+// functions do not arbitrarily free() their parameters, and that some bugs
+// found in system headers cannot be fixed by the user and should be
+// suppressed.
+#pragma clang system_header
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void *calloc(size_t, size_t);
+void free(void *);
+
+
+#if __OBJC__
+
+#import "system-header-simulator-objc.h"
+
+@interface Wrapper : NSData
+- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)len;
+@end
+
+@implementation Wrapper
+- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)len {
+ return [self initWithBytesNoCopy:bytes length:len freeWhenDone:1]; // no-warning
+}
+@end
+
+@interface CustomData : NSData
++ (id)somethingNoCopy:(char *)bytes;
++ (id)somethingNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)freeBuffer;
++ (id)something:(char *)bytes freeWhenDone:(BOOL)freeBuffer;
+@end
+
+#endif
diff --git a/test/Analysis/diagnostics/deref-track-symbolic-region.c b/test/Analysis/diagnostics/deref-track-symbolic-region.c
index e2ec8fc5f3..94774dd61d 100644
--- a/test/Analysis/diagnostics/deref-track-symbolic-region.c
+++ b/test/Analysis/diagnostics/deref-track-symbolic-region.c
@@ -9,22 +9,19 @@ struct S {
int *foo();
-void inlined(struct S *s, int m) {
- if (s->x)
+void test(struct S syz, int *pp) {
+ int m = 0;
+ syz.x = foo(); // expected-note{{Value assigned to 'syz.x'}}
+
+ struct S *ps = &syz;
+ if (ps->x)
//expected-note@-1{{Taking false branch}}
//expected-note@-2{{Assuming pointer value is null}}
m++;
-}
-void test(struct S syz, int *pp) {
- int m = 0;
- syz.x = foo(); // expected-note{{Value assigned to 'syz.x'}}
- inlined(&syz, m);
- // expected-note@-1{{Calling 'inlined'}}
- // expected-note@-2{{Returning from 'inlined'}}
m += *syz.x; // expected-warning{{Dereference of null pointer (loaded from field 'x')}}
- // expected-note@-1{{Dereference of null pointer (loaded from field 'x')}}
+ // expected-note@-1{{Dereference of null pointer (loaded from field 'x')}}
}
// CHECK: <key>diagnostics</key>
@@ -40,12 +37,12 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -53,12 +50,12 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -70,7 +67,7 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -78,12 +75,12 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -103,12 +100,12 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -116,89 +113,12 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>23</integer>
-// CHECK-NEXT: <key>col</key><integer>9</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>23</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>23</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>23</integer>
-// CHECK-NEXT: <key>col</key><integer>18</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Calling &apos;inlined&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;inlined&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>12</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;test&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;test&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>12</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>12</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>13</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -214,12 +134,12 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -227,13 +147,13 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>13</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
@@ -244,7 +164,7 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -252,53 +172,24 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>13</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Assuming pointer value is null</string>
// CHECK-NEXT: <key>message</key>
// CHECK-NEXT: <string>Assuming pointer value is null</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>23</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>23</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>23</integer>
-// CHECK-NEXT: <key>col</key><integer>18</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Returning from &apos;inlined&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Returning from &apos;inlined&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
// CHECK-NEXT: <key>edges</key>
// CHECK-NEXT: <array>
@@ -306,25 +197,25 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>23</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>23</integer>
-// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -340,12 +231,12 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -353,12 +244,12 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -370,7 +261,7 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -378,12 +269,12 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -401,12 +292,14 @@ void test(struct S syz, int *pp) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test</string>
-// CHECK-NEXT: <key>issue_hash</key><string>6</string>
+// CHECK-NEXT: <key>issue_hash</key><string>11</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </plist>
diff --git a/test/Analysis/diagnostics/deref-track-symbolic-region.cpp b/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
index bc2dcbdc26..e166109ef8 100644
--- a/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
+++ b/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
@@ -14,3 +14,15 @@ void test(S *p) {
r.y = 5; // expected-warning {{Access to field 'y' results in a dereference of a null pointer (loaded from variable 'r')}}
// expected-note@-1{{Access to field 'y' results in a dereference of a null pointer (loaded from variable 'r')}}
}
+
+void testRefParam(int *ptr) {
+ int &ref = *ptr; // expected-note {{'ref' initialized here}}
+ if (ptr)
+ // expected-note@-1{{Assuming 'ptr' is null}}
+ // expected-note@-2{{Taking false branch}}
+ return;
+
+ extern void use(int &ref);
+ use(ref); // expected-warning{{Forming reference to null pointer}}
+ // expected-note@-1{{Forming reference to null pointer}}
+} \ No newline at end of file
diff --git a/test/Analysis/fields.c b/test/Analysis/fields.c
index 12e8bbf367..863a21aaf6 100644
--- a/test/Analysis/fields.c
+++ b/test/Analysis/fields.c
@@ -29,6 +29,10 @@ void test() {
(void)(p = getit()).x;
}
+#define true ((bool)1)
+#define false ((bool)0)
+typedef _Bool bool;
+
void testLazyCompoundVal() {
Point p = {42, 0};
@@ -36,3 +40,86 @@ void testLazyCompoundVal() {
clang_analyzer_eval((q = p).x == 42); // expected-warning{{TRUE}}
clang_analyzer_eval(q.x == 42); // expected-warning{{TRUE}}
}
+
+
+struct Bits {
+ unsigned a : 1;
+ unsigned b : 2;
+ unsigned c : 1;
+
+ bool x;
+
+ struct InnerBits {
+ bool y;
+
+ unsigned d : 16;
+ unsigned e : 6;
+ unsigned f : 2;
+ } inner;
+};
+
+void testBitfields() {
+ struct Bits bits;
+
+ if (foo() && bits.b) // expected-warning {{garbage}}
+ return;
+ if (foo() && bits.inner.e) // expected-warning {{garbage}}
+ return;
+
+ bits.c = 1;
+ clang_analyzer_eval(bits.c == 1); // expected-warning {{TRUE}}
+
+ if (foo() && bits.b) // expected-warning {{garbage}}
+ return;
+ if (foo() && bits.x) // expected-warning {{garbage}}
+ return;
+
+ bits.x = true;
+ clang_analyzer_eval(bits.x == true); // expected-warning{{TRUE}}
+ bits.b = 2;
+ clang_analyzer_eval(bits.x == true); // expected-warning{{TRUE}}
+ if (foo() && bits.c) // no-warning
+ return;
+
+ bits.inner.e = 50;
+ if (foo() && bits.inner.e) // no-warning
+ return;
+ if (foo() && bits.inner.y) // expected-warning {{garbage}}
+ return;
+ if (foo() && bits.inner.f) // expected-warning {{garbage}}
+ return;
+
+ extern struct InnerBits getInner();
+ bits.inner = getInner();
+
+ if (foo() && bits.inner.e) // no-warning
+ return;
+ if (foo() && bits.inner.y) // no-warning
+ return;
+ if (foo() && bits.inner.f) // no-warning
+ return;
+
+ bits.inner.f = 1;
+
+ if (foo() && bits.inner.e) // no-warning
+ return;
+ if (foo() && bits.inner.y) // no-warning
+ return;
+ if (foo() && bits.inner.f) // no-warning
+ return;
+
+ if (foo() && bits.a) // expected-warning {{garbage}}
+ return;
+}
+
+
+//-----------------------------------------------------------------------------
+// Incorrect behavior
+//-----------------------------------------------------------------------------
+
+void testTruncation() {
+ struct Bits bits;
+ bits.c = 0x11; // expected-warning{{implicit truncation}}
+ // FIXME: We don't model truncation of bitfields.
+ clang_analyzer_eval(bits.c == 1); // expected-warning {{FALSE}}
+}
diff --git a/test/Analysis/initializer.cpp b/test/Analysis/initializer.cpp
index ab2eb90143..3f7802c56d 100644
--- a/test/Analysis/initializer.cpp
+++ b/test/Analysis/initializer.cpp
@@ -68,8 +68,7 @@ void testReferenceMember() {
void testReferenceMember2() {
int *p = 0;
- // FIXME: We should warn here, since we're creating the reference here.
- RefWrapper X(*p); // expected-warning@-12 {{Dereference of null pointer}}
+ RefWrapper X(*p); // expected-warning {{Forming reference to null pointer}}
}
diff --git a/test/Analysis/inline-plist.c b/test/Analysis/inline-plist.c
index ed0c867325..a2dd98a6d0 100644
--- a/test/Analysis/inline-plist.c
+++ b/test/Analysis/inline-plist.c
@@ -63,7 +63,7 @@ void test_block__capture_null() {
}
void test_block_ret() {
- int *p = ^(){ // expected-note {{Calling anonymous block}} expected-note{{Returning to caller}} expected-note {{'p' initialized to a null pointer value}}
+ int *p = ^int*(){ // expected-note {{Calling anonymous block}} expected-note{{Returning to caller}} expected-note {{'p' initialized to a null pointer value}}
int *q = 0; // expected-note {{'q' initialized to a null pointer value}}
return q; // expected-note {{Returning null pointer (loaded from 'q')}}
}();
diff --git a/test/Analysis/inlining/eager-reclamation-path-notes.cpp b/test/Analysis/inlining/eager-reclamation-path-notes.cpp
new file mode 100644
index 0000000000..3ee9d92b01
--- /dev/null
+++ b/test/Analysis/inlining/eager-reclamation-path-notes.cpp
@@ -0,0 +1,419 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config graph-trim-interval=5 -analyzer-config suppress-null-return-paths=false -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config graph-trim-interval=5 -analyzer-config suppress-null-return-paths=false %s -o %t.plist
+// RUN: FileCheck --input-file=%t.plist %s
+
+typedef struct {
+ int getValue();
+} IntWrapper;
+
+IntWrapper *getNullWrapper() {
+ return 0;
+ // expected-note@-1 {{Returning null pointer}}
+}
+
+int memberCallBaseDisappears() {
+ // In this case, we need the lvalue-to-rvalue cast for 'ptr' to disappear,
+ // which means we need to trigger reclamation between that and the ->
+ // operator.
+ //
+ // Note that this test is EXTREMELY brittle because it's a negative test:
+ // we want to show that even if the node for the rvalue of 'ptr' disappears,
+ // we get the same results as if it doesn't. The test should never fail even
+ // if our node reclamation policy changes, but it could easily not be testing
+ // anything at that point.
+ IntWrapper *ptr = getNullWrapper();
+ // expected-note@-1 {{Calling 'getNullWrapper'}}
+ // expected-note@-2 {{Returning from 'getNullWrapper'}}
+ // expected-note@-3 {{'ptr' initialized to a null pointer value}}
+
+ // Burn some nodes to trigger reclamation.
+ int unused = 1;
+ (void)unused;
+
+ return ptr->getValue(); // expected-warning {{Called C++ object pointer is null}}
+ // expected-note@-1 {{Called C++ object pointer is null}}
+}
+
+// CHECK: <key>diagnostics</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>34</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>36</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;getNullWrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;getNullWrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>9</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;memberCallBaseDisappears&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;memberCallBaseDisappears&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>9</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>9</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>36</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;getNullWrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;getNullWrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>34</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>34</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;ptr&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;ptr&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Called C++ object pointer is null</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>memberCallBaseDisappears</string>
+// CHECK-NEXT: <key>issue_hash</key><string>19</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
diff --git a/test/Analysis/inlining/false-positive-suppression.cpp b/test/Analysis/inlining/false-positive-suppression.cpp
index 6fbf739220..f27c7cf364 100644
--- a/test/Analysis/inlining/false-positive-suppression.cpp
+++ b/test/Analysis/inlining/false-positive-suppression.cpp
@@ -1,10 +1,6 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -DSUPPRESSED=1 %s
-#ifdef SUPPRESSED
-// expected-no-diagnostics
-#endif
-
namespace rdar12676053 {
// Delta-reduced from a preprocessed file.
template<class T>
@@ -33,4 +29,99 @@ namespace rdar12676053 {
protected:
RefCount<ParserInputState> inputState;
};
-} \ No newline at end of file
+}
+
+
+// This is the standard placement new.
+inline void* operator new(__typeof__(sizeof(int)), void* __p) throw()
+{
+ return __p;
+}
+
+extern bool coin();
+
+namespace References {
+ class Map {
+ int *&getNewBox();
+ int *firstBox;
+
+ public:
+ int *&getValue(int key) {
+ if (coin()) {
+ return firstBox;
+ } else {
+ int *&newBox = getNewBox();
+ newBox = 0;
+ return newBox;
+ }
+ }
+
+ int *&getValueIndirectly(int key) {
+ int *&valueBox = getValue(key);
+ return valueBox;
+ }
+ };
+
+ void testMap(Map &m, int i) {
+ *m.getValue(i) = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+
+ *m.getValueIndirectly(i) = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+
+ int *&box = m.getValue(i);
+ extern int *getPointer();
+ box = getPointer();
+ *box = 1; // no-warning
+
+ int *&box2 = m.getValue(i);
+ box = 0;
+ *box = 1; // expected-warning {{Dereference of null pointer}}
+ }
+
+ class SomeClass {
+ public:
+ void doSomething();
+ };
+
+ SomeClass *&getSomeClass() {
+ if (coin()) {
+ extern SomeClass *&opaqueClass();
+ return opaqueClass();
+ } else {
+ static SomeClass *sharedClass;
+ sharedClass = 0;
+ return sharedClass;
+ }
+ }
+
+ void testClass() {
+ getSomeClass()->doSomething();
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+#endif
+
+ // Separate the lvalue-to-rvalue conversion from the subsequent dereference.
+ SomeClass *object = getSomeClass();
+ object->doSomething();
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+#endif
+ }
+
+ SomeClass *getNull() {
+ return 0;
+ }
+
+ SomeClass &returnNullReference() {
+ SomeClass *x = getNull();
+ return *x;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Returning null reference}}
+#endif
+ }
+}
diff --git a/test/Analysis/inlining/inline-defensive-checks.c b/test/Analysis/inlining/inline-defensive-checks.c
new file mode 100644
index 0000000000..df3a8f2281
--- /dev/null
+++ b/test/Analysis/inlining/inline-defensive-checks.c
@@ -0,0 +1,99 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-inlined-defensive-checks=true -verify %s
+
+// Perform inline defensive checks.
+void idc(int *p) {
+ if (p)
+ ;
+}
+
+int test01(int *p) {
+ if (p)
+ ;
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+int test02(int *p, int *x) {
+ if (p)
+ ;
+ idc(p);
+ if (x)
+ ;
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+int test03(int *p, int *x) {
+ idc(p);
+ if (p)
+ ;
+ return *p; // False negative
+}
+
+int deref04(int *p) {
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+int test04(int *p) {
+ if (p)
+ ;
+ idc(p);
+ return deref04(p);
+}
+
+int test11(int *q, int *x) {
+ int *p = q;
+ if (q)
+ ;
+ if (x)
+ ;
+ return *p; // expected-warning{{Dereference of null pointer}}
+}
+
+int test12(int *q) {
+ int *p = q;
+ idc(q);
+ return *p;
+}
+
+int test13(int *q) {
+ int *p = q;
+ idc(p);
+ return *p;
+}
+
+int test21(int *q, int *x) {
+ if (q)
+ ;
+ if (x)
+ ;
+ int *p = q;
+ return *p; // expected-warning{{Dereference of null pointer}}
+}
+
+int test22(int *q, int *x) {
+ idc(q);
+ if (x)
+ ;
+ int *p = q;
+ return *p;
+}
+
+int test23(int *q, int *x) {
+ idc(q);
+ if (x)
+ ;
+ int *p = q;
+ if (!p)
+ ;
+ return *p; // False negative
+}
+
+void use(char *p) {
+ if (!p)
+ return;
+ p[0] = 'a';
+}
+
+void test24(char *buffer) {
+ use(buffer);
+ buffer[1] = 'b';
+}
diff --git a/test/Analysis/inlining/inline-defensive-checks.cpp b/test/Analysis/inlining/inline-defensive-checks.cpp
new file mode 100644
index 0000000000..c77961d03c
--- /dev/null
+++ b/test/Analysis/inlining/inline-defensive-checks.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// expected-no-diagnostics
+
+class ButterFly {
+private:
+ ButterFly() { }
+public:
+ int triggerderef() {
+ return 0;
+ }
+};
+ButterFly *getInP();
+class X{
+ ButterFly *p;
+ void setP(ButterFly *inP) {
+ if(inP)
+ ;
+ p = inP;
+ };
+ void subtest1() {
+ ButterFly *inP = getInP();
+ setP(inP);
+ }
+ int subtest2() {
+ int c = p->triggerderef(); // no-warning
+ return c;
+ }
+ int test() {
+ subtest1();
+ return subtest2();
+ }
+}; \ No newline at end of file
diff --git a/test/Analysis/inlining/inline-defensive-checks.m b/test/Analysis/inlining/inline-defensive-checks.m
new file mode 100644
index 0000000000..bafc812486
--- /dev/null
+++ b/test/Analysis/inlining/inline-defensive-checks.m
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-inlined-defensive-checks=true -verify %s
+
+typedef signed char BOOL;
+typedef struct objc_class *Class;
+typedef struct objc_object {
+ Class isa;
+} *id;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@interface NSObject <NSObject> {}
++(id)alloc;
++(id)new;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+- (Class)class;
+-(id)retain;
+@end
+
+// expected-no-diagnostics
+// Check that inline defensive checks is triggered for null expressions
+// within CompoundLiteralExpr.
+typedef union {
+ struct dispatch_object_s *_do;
+ struct dispatch_source_s *_ds;
+} dispatch_object_t __attribute__((__transparent_union__));
+typedef struct dispatch_source_s *dispatch_source_t;
+
+extern __attribute__((visibility("default"))) __attribute__((__nonnull__)) __attribute__((__nothrow__))
+void
+dispatch_resume(dispatch_object_t object);
+
+@interface AppDelegate : NSObject {
+@protected
+ dispatch_source_t p;
+}
+@end
+@implementation AppDelegate
+- (void)updateDeleteTimer {
+ if (p != ((void*)0))
+ ;
+}
+- (void)createAndStartDeleteTimer {
+ [self updateDeleteTimer];
+ dispatch_resume(p); // no warning
+}
+@end
diff --git a/test/Analysis/inlining/path-notes.c b/test/Analysis/inlining/path-notes.c
index a2d603c00a..b128aabf7e 100644
--- a/test/Analysis/inlining/path-notes.c
+++ b/test/Analysis/inlining/path-notes.c
@@ -15,20 +15,12 @@ void testZero(int *a) {
// expected-note@-1 {{Dereference of null pointer (loaded from variable 'a')}}
}
-
-void check(int *p) {
- if (p) {
- // expected-note@-1 + {{Assuming 'p' is null}}
+void testCheck(int *a) {
+ if (a) {
+ // expected-note@-1 + {{Assuming 'a' is null}}
// expected-note@-2 + {{Taking false branch}}
- return;
+ ;
}
- return;
-}
-
-void testCheck(int *a) {
- check(a);
- // expected-note@-1 {{Calling 'check'}}
- // expected-note@-2 {{Returning from 'check'}}
*a = 1; // expected-warning{{Dereference of null pointer}}
// expected-note@-1 {{Dereference of null pointer (loaded from variable 'a')}}
}
@@ -39,9 +31,11 @@ int *getPointer();
void testInitCheck() {
int *a = getPointer();
// expected-note@-1 {{'a' initialized here}}
- check(a);
- // expected-note@-1 {{Calling 'check'}}
- // expected-note@-2 {{Returning from 'check'}}
+ if (a) {
+ // expected-note@-1 + {{Assuming 'a' is null}}
+ // expected-note@-2 + {{Taking false branch}}
+ ;
+ }
*a = 1; // expected-warning{{Dereference of null pointer}}
// expected-note@-1 {{Dereference of null pointer (loaded from variable 'a')}}
}
@@ -49,9 +43,11 @@ void testInitCheck() {
void testStoreCheck(int *a) {
a = getPointer();
// expected-note@-1 {{Value assigned to 'a'}}
- check(a);
- // expected-note@-1 {{Calling 'check'}}
- // expected-note@-2 {{Returning from 'check'}}
+ if (a) {
+ // expected-note@-1 + {{Assuming 'a' is null}}
+ // expected-note@-2 + {{Taking false branch}}
+ ;
+ }
*a = 1; // expected-warning{{Dereference of null pointer}}
// expected-note@-1 {{Dereference of null pointer (loaded from variable 'a')}}
}
@@ -332,49 +328,6 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>path</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Calling &apos;check&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;check&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testCheck&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testCheck&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
// CHECK-NEXT: <key>edges</key>
// CHECK-NEXT: <array>
@@ -383,45 +336,11 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -429,12 +348,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -446,7 +365,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -454,22 +373,22 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <string>Assuming &apos;a&apos; is null</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <string>Assuming &apos;a&apos; is null</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -479,75 +398,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Returning from &apos;check&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Returning from &apos;check&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -555,12 +411,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -572,7 +428,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -580,12 +436,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -603,10 +459,10 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testCheck</string>
-// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -618,7 +474,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -626,12 +482,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -651,12 +507,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -664,89 +520,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Calling &apos;check&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;check&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testInitCheck&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testInitCheck&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -762,12 +541,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -775,12 +554,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -792,7 +571,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -800,22 +579,22 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <string>Assuming &apos;a&apos; is null</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <string>Assuming &apos;a&apos; is null</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -825,75 +604,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Returning from &apos;check&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Returning from &apos;check&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -901,12 +617,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>45</integer>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>45</integer>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -918,7 +634,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>45</integer>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -926,12 +642,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>45</integer>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>45</integer>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -949,10 +665,10 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testInitCheck</string>
-// CHECK-NEXT: <key>issue_hash</key><string>6</string>
+// CHECK-NEXT: <key>issue_hash</key><string>8</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>45</integer>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -964,7 +680,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -972,12 +688,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -997,12 +713,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1010,89 +726,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Calling &apos;check&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;check&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testStoreCheck&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testStoreCheck&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1108,12 +747,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1121,12 +760,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1138,7 +777,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1146,22 +785,22 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <string>Assuming &apos;a&apos; is null</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <string>Assuming &apos;a&apos; is null</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1171,75 +810,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Returning from &apos;check&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Returning from &apos;check&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1247,12 +823,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1264,7 +840,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1272,12 +848,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1295,10 +871,10 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testStoreCheck</string>
-// CHECK-NEXT: <key>issue_hash</key><string>6</string>
+// CHECK-NEXT: <key>issue_hash</key><string>8</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1314,12 +890,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1327,12 +903,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1344,7 +920,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1352,12 +928,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1373,7 +949,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1391,12 +967,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1404,12 +980,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1421,7 +997,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1429,12 +1005,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1454,12 +1030,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1467,12 +1043,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1484,7 +1060,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1492,12 +1068,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1513,7 +1089,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1521,12 +1097,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1546,12 +1122,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1559,12 +1135,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1580,12 +1156,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1593,12 +1169,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1610,7 +1186,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1618,12 +1194,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1644,7 +1220,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1660,12 +1236,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1673,12 +1249,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1690,7 +1266,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1698,12 +1274,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1719,7 +1295,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1737,12 +1313,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1750,12 +1326,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1767,7 +1343,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1775,12 +1351,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1800,12 +1376,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1813,12 +1389,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1830,7 +1406,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1838,12 +1414,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1859,7 +1435,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1867,12 +1443,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1892,12 +1468,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1905,12 +1481,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1926,12 +1502,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1939,12 +1515,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1956,7 +1532,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1964,12 +1540,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1990,7 +1566,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2006,12 +1582,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2019,12 +1595,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2036,7 +1612,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2044,12 +1620,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2065,7 +1641,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2083,12 +1659,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2096,12 +1672,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2113,7 +1689,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2121,12 +1697,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2146,12 +1722,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2159,12 +1735,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2176,7 +1752,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2184,12 +1760,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2205,7 +1781,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2213,12 +1789,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2238,12 +1814,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2251,12 +1827,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2272,12 +1848,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2285,12 +1861,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2302,7 +1878,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2310,12 +1886,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2335,12 +1911,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2348,12 +1924,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>87</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>87</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2365,7 +1941,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>87</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2373,12 +1949,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>87</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>87</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2399,7 +1975,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>87</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2415,12 +1991,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2428,12 +2004,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2445,7 +2021,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2453,12 +2029,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2474,7 +2050,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2492,12 +2068,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2505,12 +2081,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2522,7 +2098,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2530,12 +2106,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2555,12 +2131,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2568,12 +2144,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2585,7 +2161,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2593,12 +2169,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2614,7 +2190,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2622,12 +2198,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2647,12 +2223,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2660,12 +2236,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2681,12 +2257,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2694,12 +2270,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2711,7 +2287,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2719,12 +2295,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2744,12 +2320,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2757,12 +2333,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2774,7 +2350,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2782,12 +2358,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2808,7 +2384,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2824,12 +2400,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2837,12 +2413,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2854,7 +2430,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2862,12 +2438,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2883,7 +2459,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2901,12 +2477,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2914,12 +2490,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2931,7 +2507,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2939,12 +2515,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2964,12 +2540,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2977,12 +2553,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2994,7 +2570,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3002,12 +2578,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3023,7 +2599,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3031,12 +2607,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3056,12 +2632,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3069,12 +2645,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3086,7 +2662,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3094,12 +2670,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3115,7 +2691,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3123,12 +2699,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3144,7 +2720,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>100</integer>
+// CHECK-NEXT: <key>line</key><integer>96</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3162,12 +2738,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>100</integer>
+// CHECK-NEXT: <key>line</key><integer>96</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>100</integer>
+// CHECK-NEXT: <key>line</key><integer>96</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3175,12 +2751,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3192,7 +2768,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3200,12 +2776,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3226,7 +2802,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
diff --git a/test/Analysis/inlining/path-notes.cpp b/test/Analysis/inlining/path-notes.cpp
index 8140e98170..6c63e1400c 100644
--- a/test/Analysis/inlining/path-notes.cpp
+++ b/test/Analysis/inlining/path-notes.cpp
@@ -155,6 +155,44 @@ namespace defaulted {
// expected-note@-2 {{Calling '~Dereferencer'}}
}
+namespace ReturnZeroNote {
+ int getZero() {
+ return 0;
+ // expected-note@-1 {{Returning zero}}
+ }
+
+ const int &getZeroByRef() {
+ static int zeroVar;
+ zeroVar = 0;
+ // expected-note@-1 {{The value 0 is assigned to 'zeroVar'}}
+ return zeroVar;
+ // expected-note@-1 {{Returning zero (reference to 'zeroVar')}}
+ }
+
+ void test() {
+ int problem = 1 / getZero(); // expected-warning {{Division by zero}}
+ // expected-note@-1 {{Calling 'getZero'}}
+ // expected-note@-2 {{Returning from 'getZero'}}
+ // expected-note@-3 {{Division by zero}}
+ }
+
+ void testRef() {
+ int problem = 1 / getZeroByRef(); // expected-warning {{Division by zero}}
+ // expected-note@-1 {{Calling 'getZeroByRef'}}
+ // expected-note@-2 {{Returning from 'getZeroByRef'}}
+ // expected-note@-3 {{Division by zero}}
+ }
+}
+
+
+int &returnNullReference() {
+ int *x = 0;
+ // expected-note@-1 {{'x' initialized to a null pointer value}}
+ return *x; // expected-warning{{Returning null reference}}
+ // expected-note@-1 {{Returning null reference}}
+}
+
+
// CHECK: <key>diagnostics</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
@@ -2522,4 +2560,776 @@ namespace defaulted {
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>29</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;getZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;getZero&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZero&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>29</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>29</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Division by zero</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Division by zero</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>34</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>36</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;getZeroByRef&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;getZeroByRef&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>164</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testRef&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testRef&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>164</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>164</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>165</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>165</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>165</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>165</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>The value 0 is assigned to &apos;zeroVar&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>The value 0 is assigned to &apos;zeroVar&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>168</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>168</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>168</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>168</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>168</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning zero (reference to &apos;zeroVar&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning zero (reference to &apos;zeroVar&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>36</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZeroByRef&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZeroByRef&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>34</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>34</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>36</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Division by zero</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Division by zero</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testRef</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>189</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>189</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>189</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;x&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;x&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>189</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>189</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning null reference</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning null reference</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Returning null reference</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Returning null reference</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>returnNullReference</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>191</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
diff --git a/test/Analysis/malloc.mm b/test/Analysis/malloc.mm
index f2a195ce1d..2f583b45fd 100644
--- a/test/Analysis/malloc.mm
+++ b/test/Analysis/malloc.mm
@@ -1,19 +1,6 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -fblocks %s
-#include "Inputs/system-header-simulator-objc.h"
-
-typedef __typeof(sizeof(int)) size_t;
-void *malloc(size_t);
-void free(void *);
-
-@interface Wrapper : NSData
-- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)len;
-@end
-
-@implementation Wrapper
-- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)len {
- return [self initWithBytesNoCopy:bytes length:len freeWhenDone:1]; // no-warning
-}
-@end
+#import "Inputs/system-header-simulator-objc.h"
+#import "Inputs/system-header-simulator-for-malloc.h"
// Done with headers. Start testing.
void testNSDatafFreeWhenDoneNoError(NSUInteger dataLength) {
@@ -79,6 +66,11 @@ void testNSStringFreeWhenDoneNO2(NSUInteger dataLength) {
NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}}
}
+void testOffsetFree() {
+ int *p = (int *)malloc(sizeof(int));
+ NSData *nsdata = [NSData dataWithBytesNoCopy:++p length:sizeof(int) freeWhenDone:1]; // expected-warning{{Argument to free() is offset by 4 bytes from the start of memory allocated by malloc()}}
+}
+
void testRelinquished1() {
void *data = malloc(42);
NSData *nsdata = [NSData dataWithBytesNoCopy:data length:42 freeWhenDone:1];
@@ -92,6 +84,31 @@ void testRelinquished2() {
[NSData dataWithBytesNoCopy:data length:42]; // expected-warning {{Attempt to free released memory}}
}
+void testNoCopy() {
+ char *p = (char *)calloc(sizeof(int), 1);
+ CustomData *w = [CustomData somethingNoCopy:p]; // no-warning
+}
+
+void testFreeWhenDone() {
+ char *p = (char *)calloc(sizeof(int), 1);
+ CustomData *w = [CustomData something:p freeWhenDone:1]; // no-warning
+}
+
+void testFreeWhenDonePositive() {
+ char *p = (char *)calloc(sizeof(int), 1);
+ CustomData *w = [CustomData something:p freeWhenDone:0]; // expected-warning{{leak}}
+}
+
+void testFreeWhenDoneNoCopy() {
+ int *p = (int *)malloc(sizeof(int));
+ CustomData *w = [CustomData somethingNoCopy:p length:sizeof(int) freeWhenDone:1]; // no-warning
+}
+
+void testFreeWhenDoneNoCopyPositive() {
+ int *p = (int *)malloc(sizeof(int));
+ CustomData *w = [CustomData somethingNoCopy:p length:sizeof(int) freeWhenDone:0]; // expected-warning{{leak}}
+}
+
// Test CF/NS...NoCopy. PR12100: Pointers can escape when custom deallocators are provided.
void testNSDatafFreeWhenDone(NSUInteger dataLength) {
CFStringRef str;
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index a7fbd66d68..bb22c25998 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -1193,7 +1193,7 @@ static void RDar8424269_B(RDar8424269_A *p, unsigned char *RDar8424269_D,
tmp2 = tmp2t[2];
}
-// <rdar://problem/8642434> - Handle transparent unions with the AttrNonNullChecker.
+// <rdar://problem/8642434> - Handle transparent unions with the NonNullParamChecker.
typedef union {
struct rdar_8642434_typeA *_dq;
}
diff --git a/test/Analysis/objc-method-coverage.m b/test/Analysis/objc-method-coverage.m
index cb66bff19b..489c19ba6c 100644
--- a/test/Analysis/objc-method-coverage.m
+++ b/test/Analysis/objc-method-coverage.m
@@ -1,3 +1,4 @@
+// REQUIRES: asserts
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-stats -fblocks %s 2>&1 | FileCheck %s
@interface I
int f() {
@@ -13,4 +14,4 @@ int f() {
// CHECK: ... Statistics Collected ...
// CHECK: 2 AnalysisConsumer - The # of functions and blocks analyzed (as top level with inlining turned on).
-// CHECK: 100 AnalysisConsumer - The % of reachable basic blocks. \ No newline at end of file
+// CHECK: 100 AnalysisConsumer - The % of reachable basic blocks.
diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp
index ce0ee8ed57..8dd0baf8c3 100644
--- a/test/Analysis/reference.cpp
+++ b/test/Analysis/reference.cpp
@@ -135,21 +135,92 @@ void testFunctionPointerReturn(void *opaque) {
clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
}
+int &testReturnNullReference() {
+ int *x = 0;
+ return *x; // expected-warning{{Returning null reference}}
+}
+
+char &refFromPointer() {
+ return *ptr();
+}
+
+void testReturnReference() {
+ clang_analyzer_eval(ptr() == 0); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(&refFromPointer() == 0); // expected-warning{{FALSE}}
+}
+
+void intRefParam(int &r) {
+ ;
+}
-// ------------------------------------
-// False negatives
-// ------------------------------------
+void test(int *ptr) {
+ clang_analyzer_eval(ptr == 0); // expected-warning{{UNKNOWN}}
+
+ extern void use(int &ref);
+ use(*ptr);
+
+ clang_analyzer_eval(ptr == 0); // expected-warning{{FALSE}}
+}
+
+void testIntRefParam() {
+ int i = 0;
+ intRefParam(i); // no-warning
+}
+
+int refParam(int &byteIndex) {
+ return byteIndex;
+}
+
+void testRefParam(int *p) {
+ if (p)
+ ;
+ refParam(*p); // expected-warning {{Forming reference to null pointer}}
+}
+
+int ptrRefParam(int *&byteIndex) {
+ return *byteIndex; // expected-warning {{Dereference of null pointer}}
+}
+void testRefParam2() {
+ int *p = 0;
+ int *&rp = p;
+ ptrRefParam(rp);
+}
+
+int *maybeNull() {
+ extern bool coin();
+ static int x;
+ return coin() ? &x : 0;
+}
+
+void use(int &x) {
+ x = 1; // no-warning
+}
+
+void testSuppression() {
+ use(*maybeNull());
+}
namespace rdar11212286 {
class B{};
B test() {
B *x = 0;
- return *x; // should warn here!
+ return *x; // expected-warning {{Forming reference to null pointer}}
}
- B &testRef() {
- B *x = 0;
- return *x; // should warn here!
+ B testif(B *x) {
+ if (x)
+ ;
+ return *x; // expected-warning {{Forming reference to null pointer}}
+ }
+
+ void idc(B *x) {
+ if (x)
+ ;
+ }
+
+ B testidc(B *x) {
+ idc(x);
+ return *x; // no-warning
}
}
diff --git a/test/Analysis/retain-release-cf-audited.m b/test/Analysis/retain-release-cf-audited.m
new file mode 100644
index 0000000000..c89172f70b
--- /dev/null
+++ b/test/Analysis/retain-release-cf-audited.m
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -verify %s -x objective-c++
+
+// The special thing about this file is that CFRetain and CFRelease are marked
+// as cf_audited_transfer.
+
+#pragma clang arc_cf_code_audited begin
+typedef const void * CFTypeRef;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+extern void CFRelease(CFTypeRef cf);
+
+extern CFTypeRef CFCreateSomethingAudited();
+#pragma clang arc_cf_code_audited end
+
+extern CFTypeRef CFCreateSomethingUnaudited();
+
+void testAudited() {
+ CFTypeRef obj = CFCreateSomethingAudited(); // no-warning
+ CFRelease(obj); // no-warning
+
+ CFTypeRef obj2 = CFCreateSomethingAudited(); // expected-warning{{leak}}
+ CFRetain(obj2); // no-warning
+ CFRelease(obj2); // no-warning
+}
+
+void testUnaudited() {
+ CFTypeRef obj = CFCreateSomethingUnaudited(); // no-warning
+ CFRelease(obj); // no-warning
+
+ CFTypeRef obj2 = CFCreateSomethingUnaudited(); // expected-warning{{leak}}
+ CFRetain(obj2); // no-warning
+ CFRelease(obj2); // no-warning
+}
diff --git a/test/Analysis/stats.c b/test/Analysis/stats.c
index 6beadbeb41..5701dc71f5 100644
--- a/test/Analysis/stats.c
+++ b/test/Analysis/stats.c
@@ -1,3 +1,4 @@
+// REQUIRES: asserts
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-stats %s 2>&1 | FileCheck %s
void foo() {
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
index d2afd5d83f..9632fda296 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
@@ -33,5 +33,5 @@ namespace test1 {
// specifiers.
namespace test2 {
template <class T> struct bar {};
- template <class T> struct foo : bar<foo> {}; // expected-error {{use of class template foo requires template arguments}} expected-note {{template is declared here}}
+ template <class T> struct foo : bar<foo> {}; // expected-error {{use of class template 'foo' requires template arguments}} expected-note {{template is declared here}}
}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp
index 5467a9222c..e03c2164ba 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
void nondecl(int (*f)(int x = 5)) // expected-error {{default arguments can only be specified}}
{
@@ -8,6 +8,9 @@ void nondecl(int (*f)(int x = 5)) // expected-error {{default arguments can only
struct X0 {
int (*f)(int = 17); // expected-error{{default arguments can only be specified for parameters in a function declaration}}
+ void (*g())(int = 22); // expected-error{{default arguments can only be specified for parameters in a function declaration}}
+ void (*h(int = 49))(int);
+ auto i(int) -> void (*)(int = 9); // expected-error{{default arguments can only be specified for parameters in a function declaration}}
void mem8(int (*fp)(int) = (int (*)(int = 17))0); // expected-error{{default arguments can only be specified for parameters in a function declaration}}
};
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
index 4f6dcc1105..33efac0248 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
@@ -27,3 +27,21 @@ void test_f2(int *ip, float *fp) {
f2(ip, ip); // okay
f2(ip, fp); // expected-error{{no matching function}}
}
+
+namespace test3 {
+ template<typename T>
+ struct bar { };
+
+ template<typename T>
+ struct foo {
+ operator bar<T>();
+ };
+
+ template<typename T>
+ void func(bar<T>) { // expected-note {{candidate template ignored: could not match 'bar' against 'foo'}}
+ }
+
+ void test() {
+ func(foo<int>()); // expected-error {{no matching function}}
+ }
+}
diff --git a/test/CodeGen/2008-04-08-NoExceptions.c b/test/CodeGen/2008-04-08-NoExceptions.c
index 254d30ac3c..1213492d1d 100644
--- a/test/CodeGen/2008-04-08-NoExceptions.c
+++ b/test/CodeGen/2008-04-08-NoExceptions.c
@@ -2,11 +2,11 @@
void f(void);
void g(void) {
- // CHECK: define void @g() #0
+ // CHECK: define void @g() [[NUW:#[0-9]+]]
// CHECK-NOT: call void @f() nounwind
f();
}
-// CHECK-NOT: declare void @f() #0
+// CHECK-NOT: declare void @f() [[NUW]]
-// CHECK: attributes #0 = { nounwind{{.*}} }
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGen/address-safety-attr.cpp b/test/CodeGen/address-safety-attr.cpp
index 29ba5a8375..f94efd62c9 100644
--- a/test/CodeGen/address-safety-attr.cpp
+++ b/test/CodeGen/address-safety-attr.cpp
@@ -1,42 +1,55 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address | FileCheck -check-prefix=ASAN %s
-// RUN: echo "src:%s" > %t
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address -fsanitize-blacklist=%t | FileCheck -check-prefix=BL %s
+// RUN: echo "src:%s" > %t.file.blacklist
+// RUN: echo "fun:*BlacklistedFunction*" > %t.func.blacklist
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address -fsanitize-blacklist=%t.file.blacklist | FileCheck -check-prefix=BLFILE %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address -fsanitize-blacklist=%t.func.blacklist | FileCheck -check-prefix=BLFUNC %s
-// FIXME: %t is like "src:x:\path\to\clang\test\CodeGen\address-safety-attr.cpp"
+// FIXME: %t.file.blacklist is like "src:x:\path\to\clang\test\CodeGen\address-safety-attr.cpp"
// REQUIRES: shell
// The sanitize_address attribute should be attached to functions
// when AddressSanitizer is enabled, unless no_sanitize_address attribute
// is present.
-// WITHOUT: NoAddressSafety1{{.*}}) #[[NOATTR:[0-9]+]]
-// BL: NoAddressSafety1{{.*}}) #[[NOATTR:[0-9]+]]
-// ASAN: NoAddressSafety1{{.*}}) #[[NOATTR:[0-9]+]]
+// WITHOUT: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
+// BLFILE: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
+// BLFUNC: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
+// ASAN: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
__attribute__((no_sanitize_address))
int NoAddressSafety1(int *a) { return *a; }
-// WITHOUT: NoAddressSafety2{{.*}}) #[[NOATTR]]
-// BL: NoAddressSafety2{{.*}}) #[[NOATTR]]
-// ASAN: NoAddressSafety2{{.*}}) #[[NOATTR]]
+// WITHOUT: NoAddressSafety2{{.*}}) [[NOATTR]]
+// BLFILE: NoAddressSafety2{{.*}}) [[NOATTR]]
+// BLFUNC: NoAddressSafety2{{.*}}) [[NOATTR]]
+// ASAN: NoAddressSafety2{{.*}}) [[NOATTR]]
__attribute__((no_sanitize_address))
int NoAddressSafety2(int *a);
int NoAddressSafety2(int *a) { return *a; }
-// WITHOUT: AddressSafetyOk{{.*}}) #[[NOATTR]]
-// BL: AddressSafetyOk{{.*}}) #[[NOATTR]]
-// ASAN: AddressSafetyOk{{.*}}) #[[WITH:[0-9]+]]
+// WITHOUT: AddressSafetyOk{{.*}}) [[NOATTR]]
+// BLFILE: AddressSafetyOk{{.*}}) [[NOATTR]]
+// BLFUNC: AddressSafetyOk{{.*}}) [[WITH:#[0-9]+]]
+// ASAN: AddressSafetyOk{{.*}}) [[WITH:#[0-9]+]]
int AddressSafetyOk(int *a) { return *a; }
-// WITHOUT: TemplateAddressSafetyOk{{.*}}) #[[NOATTR]]
-// BL: TemplateAddressSafetyOk{{.*}}) #[[NOATTR]]
-// ASAN: TemplateAddressSafetyOk{{.*}}) #[[WITH]]
+// WITHOUT: BlacklistedFunction{{.*}}) [[NOATTR]]
+// BLFILE: BlacklistedFunction{{.*}}) [[NOATTR]]
+// BLFUNC: BlacklistedFunction{{.*}}) [[NOATTR]]
+// ASAN: BlacklistedFunction{{.*}}) [[WITH]]
+int BlacklistedFunction(int *a) { return *a; }
+
+// WITHOUT: TemplateAddressSafetyOk{{.*}}) [[NOATTR]]
+// BLFILE: TemplateAddressSafetyOk{{.*}}) [[NOATTR]]
+// BLFUNC: TemplateAddressSafetyOk{{.*}}) [[WITH]]
+// ASAN: TemplateAddressSafetyOk{{.*}}) [[WITH]]
template<int i>
int TemplateAddressSafetyOk() { return i; }
-// WITHOUT: TemplateNoAddressSafety{{.*}}) #[[NOATTR]]
-// BL: TemplateNoAddressSafety{{.*}}) #[[NOATTR]]
-// ASAN: TemplateNoAddressSafety{{.*}}) #[[NOATTR]]
+// WITHOUT: TemplateNoAddressSafety{{.*}}) [[NOATTR]]
+// BLFILE: TemplateNoAddressSafety{{.*}}) [[NOATTR]]
+// BLFUNC: TemplateNoAddressSafety{{.*}}) [[NOATTR]]
+// ASAN: TemplateNoAddressSafety{{.*}}) [[NOATTR]]
template<int i>
__attribute__((no_sanitize_address))
int TemplateNoAddressSafety() { return i; }
@@ -47,12 +60,21 @@ int force_instance = TemplateAddressSafetyOk<42>()
// Check that __cxx_global_var_init* get the sanitize_address attribute.
int global1 = 0;
int global2 = *(int*)((char*)&global1+1);
-// WITHOUT: @__cxx_global_var_init{{.*}}#[[NOATTR]]
-// BL: @__cxx_global_var_init{{.*}}#[[NOATTR]]
-// ASAN: @__cxx_global_var_init{{.*}}#[[WITH]]
+// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]]
+// BLFILE: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]]
+// BLFUNC: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]]
+// ASAN: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]]
+
+// WITHOUT: attributes [[NOATTR]] = { nounwind{{.*}} }
+// WITHOUT: attributes [[NOATTR_NO_TF]] = { nounwind }
+
+// BLFILE: attributes [[NOATTR]] = { nounwind{{.*}} }
+// BLFILE: attributes [[NOATTR_NO_TF]] = { nounwind }
-// WITHOUT: attributes #[[NOATTR]] = { nounwind{{.*}} }
-// BL: attributes #[[NOATTR]] = { nounwind{{.*}} }
+// BLFUNC: attributes [[NOATTR]] = { nounwind{{.*}} }
+// BLFUNC: attributes [[WITH]] = { nounwind sanitize_address{{.*}} }
+// BLFUNC: attributes [[WITH_NO_TF]] = { nounwind sanitize_address }
-// ASAN: attributes #[[NOATTR]] = { nounwind{{.*}} }
-// ASAN: attributes #[[WITH]] = {{.*}}sanitize_address
+// ASAN: attributes [[NOATTR]] = { nounwind{{.*}} }
+// ASAN: attributes [[WITH]] = { nounwind sanitize_address{{.*}} }
+// ASAN: attributes [[WITH_NO_TF]] = { nounwind sanitize_address }
diff --git a/test/CodeGen/atomic_ops.c b/test/CodeGen/atomic_ops.c
index 481d1e06fb..910e9b9505 100644
--- a/test/CodeGen/atomic_ops.c
+++ b/test/CodeGen/atomic_ops.c
@@ -15,9 +15,4 @@ void foo(int x)
// CHECK: sdiv i32
// CHECK: cmpxchg i16*
- // These should be emitting atomicrmw instructions, but they aren't yet
- i += 2; // CHECK: cmpxchg
- i -= 2; // CHECK: cmpxchg
- i++; // CHECK: cmpxchg
- i--; // CHECK: cmpxchg
}
diff --git a/test/CodeGen/builtins-ppc-altivec.c b/test/CodeGen/builtins-ppc-altivec.c
index e885cb03aa..9427a8a57c 100644
--- a/test/CodeGen/builtins-ppc-altivec.c
+++ b/test/CodeGen/builtins-ppc-altivec.c
@@ -484,20 +484,20 @@ void test6() {
res_vf = vec_lvx(0, &param_f); // CHECK: @llvm.ppc.altivec.lvx
/* vec_lde */
- res_vsc = vec_lde(0, &vsc); // CHECK: @llvm.ppc.altivec.lvebx
- res_vuc = vec_lde(0, &vuc); // CHECK: @llvm.ppc.altivec.lvebx
- res_vs = vec_lde(0, &vs); // CHECK: @llvm.ppc.altivec.lvehx
- res_vus = vec_lde(0, &vus); // CHECK: @llvm.ppc.altivec.lvehx
- res_vi = vec_lde(0, &vi); // CHECK: @llvm.ppc.altivec.lvewx
- res_vui = vec_lde(0, &vui); // CHECK: @llvm.ppc.altivec.lvewx
- res_vf = vec_lde(0, &vf); // CHECK: @llvm.ppc.altivec.lvewx
- res_vsc = vec_lvebx(0, &vsc); // CHECK: @llvm.ppc.altivec.lvebx
- res_vuc = vec_lvebx(0, &vuc); // CHECK: @llvm.ppc.altivec.lvebx
- res_vs = vec_lvehx(0, &vs); // CHECK: @llvm.ppc.altivec.lvehx
- res_vus = vec_lvehx(0, &vus); // CHECK: @llvm.ppc.altivec.lvehx
- res_vi = vec_lvewx(0, &vi); // CHECK: @llvm.ppc.altivec.lvewx
- res_vui = vec_lvewx(0, &vui); // CHECK: @llvm.ppc.altivec.lvewx
- res_vf = vec_lvewx(0, &vf); // CHECK: @llvm.ppc.altivec.lvewx
+ res_vsc = vec_lde(0, &param_sc); // CHECK: @llvm.ppc.altivec.lvebx
+ res_vuc = vec_lde(0, &param_uc); // CHECK: @llvm.ppc.altivec.lvebx
+ res_vs = vec_lde(0, &param_s); // CHECK: @llvm.ppc.altivec.lvehx
+ res_vus = vec_lde(0, &param_us); // CHECK: @llvm.ppc.altivec.lvehx
+ res_vi = vec_lde(0, &param_i); // CHECK: @llvm.ppc.altivec.lvewx
+ res_vui = vec_lde(0, &param_ui); // CHECK: @llvm.ppc.altivec.lvewx
+ res_vf = vec_lde(0, &param_f); // CHECK: @llvm.ppc.altivec.lvewx
+ res_vsc = vec_lvebx(0, &param_sc); // CHECK: @llvm.ppc.altivec.lvebx
+ res_vuc = vec_lvebx(0, &param_uc); // CHECK: @llvm.ppc.altivec.lvebx
+ res_vs = vec_lvehx(0, &param_s); // CHECK: @llvm.ppc.altivec.lvehx
+ res_vus = vec_lvehx(0, &param_us); // CHECK: @llvm.ppc.altivec.lvehx
+ res_vi = vec_lvewx(0, &param_i); // CHECK: @llvm.ppc.altivec.lvewx
+ res_vui = vec_lvewx(0, &param_ui); // CHECK: @llvm.ppc.altivec.lvewx
+ res_vf = vec_lvewx(0, &param_f); // CHECK: @llvm.ppc.altivec.lvewx
/* vec_ldl */
res_vsc = vec_ldl(0, &vsc); // CHECK: @llvm.ppc.altivec.lvxl
diff --git a/test/CodeGen/c11atomics-ios.c b/test/CodeGen/c11atomics-ios.c
new file mode 100644
index 0000000000..d1c9b14330
--- /dev/null
+++ b/test/CodeGen/c11atomics-ios.c
@@ -0,0 +1,214 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-apple-ios -std=c11 | FileCheck %s
+
+// There isn't really anything special about iOS; it just happens to
+// only deploy on processors with native atomics support, so it's a good
+// way to test those code-paths.
+
+// This work was done in pursuit of <rdar://13338582>.
+
+// CHECK: define arm_aapcscc void @testFloat(float*
+void testFloat(_Atomic(float) *fp) {
+// CHECK: [[FP:%.*]] = alloca float*
+// CHECK-NEXT: [[X:%.*]] = alloca float
+// CHECK-NEXT: [[F:%.*]] = alloca float
+// CHECK-NEXT: store float* {{%.*}}, float** [[FP]]
+
+// CHECK-NEXT: [[T0:%.*]] = load float** [[FP]]
+// CHECK-NEXT: store float 1.000000e+00, float* [[T0]], align 4
+ __c11_atomic_init(fp, 1.0f);
+
+// CHECK-NEXT: store float 2.000000e+00, float* [[X]], align 4
+ _Atomic(float) x = 2.0f;
+
+// CHECK-NEXT: [[T0:%.*]] = load float** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast float* [[T0]] to i32*
+// CHECK-NEXT: [[T2:%.*]] = load atomic i32* [[T1]] seq_cst, align 4
+// CHECK-NEXT: [[T3:%.*]] = bitcast i32 [[T2]] to float
+// CHECK-NEXT: store float [[T3]], float* [[F]]
+ float f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = load float* [[F]], align 4
+// CHECK-NEXT: [[T1:%.*]] = load float** [[FP]], align 4
+// CHECK-NEXT: [[T2:%.*]] = bitcast float [[T0]] to i32
+// CHECK-NEXT: [[T3:%.*]] = bitcast float* [[T1]] to i32*
+// CHECK-NEXT: store atomic i32 [[T2]], i32* [[T3]] seq_cst, align 4
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+// CHECK: define arm_aapcscc void @testComplexFloat([[CF:{ float, float }]]*
+void testComplexFloat(_Atomic(_Complex float) *fp) {
+// CHECK: [[FP:%.*]] = alloca [[CF]]*, align 4
+// CHECK-NEXT: [[X:%.*]] = alloca [[CF]], align 8
+// CHECK-NEXT: [[F:%.*]] = alloca [[CF]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = alloca [[CF]], align 8
+// CHECK-NEXT: [[TMP1:%.*]] = alloca [[CF]], align 8
+// CHECK-NEXT: store [[CF]]*
+
+// CHECK-NEXT: [[P:%.*]] = load [[CF]]** [[FP]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[P]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[P]], i32 0, i32 1
+// CHECK-NEXT: store float 1.000000e+00, float* [[T0]]
+// CHECK-NEXT: store float 0.000000e+00, float* [[T1]]
+ __c11_atomic_init(fp, 1.0f);
+
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[X]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[X]], i32 0, i32 1
+// CHECK-NEXT: store float 2.000000e+00, float* [[T0]]
+// CHECK-NEXT: store float 0.000000e+00, float* [[T1]]
+ _Atomic(_Complex float) x = 2.0f;
+
+// CHECK-NEXT: [[T0:%.*]] = load [[CF]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[CF]]* [[T0]] to i64*
+// CHECK-NEXT: [[T2:%.*]] = load atomic i64* [[T1]] seq_cst, align 8
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[CF]]* [[TMP0]] to i64*
+// CHECK-NEXT: store i64 [[T2]], i64* [[T3]], align 8
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[TMP0]], i32 0, i32 0
+// CHECK-NEXT: [[R:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[TMP0]], i32 0, i32 1
+// CHECK-NEXT: [[I:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 1
+// CHECK-NEXT: store float [[R]], float* [[T0]]
+// CHECK-NEXT: store float [[I]], float* [[T1]]
+ _Complex float f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 0
+// CHECK-NEXT: [[R:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 1
+// CHECK-NEXT: [[I:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[DEST:%.*]] = load [[CF]]** [[FP]], align 4
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[TMP1]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[TMP1]], i32 0, i32 1
+// CHECK-NEXT: store float [[R]], float* [[T0]]
+// CHECK-NEXT: store float [[I]], float* [[T1]]
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[CF]]* [[TMP1]] to i64*
+// CHECK-NEXT: [[T1:%.*]] = load i64* [[T0]], align 8
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[CF]]* [[DEST]] to i64*
+// CHECK-NEXT: store atomic i64 [[T1]], i64* [[T2]] seq_cst, align 8
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+typedef struct { short x, y, z, w; } S;
+// CHECK: define arm_aapcscc void @testStruct([[S:.*]]*
+void testStruct(_Atomic(S) *fp) {
+// CHECK: [[FP:%.*]] = alloca [[S]]*, align 4
+// CHECK-NEXT: [[X:%.*]] = alloca [[S]], align 8
+// CHECK-NEXT: [[F:%.*]] = alloca [[S:%.*]], align 2
+// CHECK-NEXT: [[TMP0:%.*]] = alloca [[S]], align 8
+// CHECK-NEXT: store [[S]]*
+
+// CHECK-NEXT: [[P:%.*]] = load [[S]]** [[FP]]
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[S]]* [[P]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 3
+// CHECK-NEXT: store i16 4, i16* [[T0]], align 2
+ __c11_atomic_init(fp, (S){1,2,3,4});
+
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[S]]* [[X]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 3
+// CHECK-NEXT: store i16 4, i16* [[T0]], align 2
+ _Atomic(S) x = (S){1,2,3,4};
+
+// CHECK-NEXT: [[T0:%.*]] = load [[S]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[S]]* [[T0]] to i64*
+// CHECK-NEXT: [[T2:%.*]] = load atomic i64* [[T1]] seq_cst, align 8
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[S]]* [[F]] to i64*
+// CHECK-NEXT: store i64 [[T2]], i64* [[T3]], align 2
+ S f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = load [[S]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[S]]* [[TMP0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[S]]* [[F]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[T1]], i8* [[T2]], i32 8, i32 2, i1 false)
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[S]]* [[TMP0]] to i64*
+// CHECK-NEXT: [[T4:%.*]] = load i64* [[T3]], align 8
+// CHECK-NEXT: [[T5:%.*]] = bitcast [[S]]* [[T0]] to i64*
+// CHECK-NEXT: store atomic i64 [[T4]], i64* [[T5]] seq_cst, align 8
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+typedef struct { short x, y, z; } PS;
+// CHECK: define arm_aapcscc void @testPromotedStruct([[APS:.*]]*
+void testPromotedStruct(_Atomic(PS) *fp) {
+// CHECK: [[FP:%.*]] = alloca [[APS]]*, align 4
+// CHECK-NEXT: [[X:%.*]] = alloca [[APS]], align 8
+// CHECK-NEXT: [[F:%.*]] = alloca [[PS:%.*]], align 2
+// CHECK-NEXT: [[TMP0:%.*]] = alloca [[APS]], align 8
+// CHECK-NEXT: [[TMP1:%.*]] = alloca [[APS]], align 8
+// CHECK-NEXT: store [[APS]]*
+
+// CHECK-NEXT: [[P:%.*]] = load [[APS]]** [[FP]]
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[APS]]* [[P]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[P]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T1]], align 2
+ __c11_atomic_init(fp, (PS){1,2,3});
+
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[APS]]* [[X]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[X]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T1]], align 2
+ _Atomic(PS) x = (PS){1,2,3};
+
+// CHECK-NEXT: [[T0:%.*]] = load [[APS]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[APS]]* [[T0]] to i64*
+// CHECK-NEXT: [[T2:%.*]] = load atomic i64* [[T1]] seq_cst, align 8
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[APS]]* [[TMP0]] to i64*
+// CHECK-NEXT: store i64 [[T2]], i64* [[T3]], align 8
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[TMP0]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[PS]]* [[F]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[PS]]* [[T0]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[T1]], i8* [[T2]], i32 6, i32 2, i1 false)
+ PS f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = load [[APS]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[APS]]* [[TMP1]], i32 0, i32 0
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[PS]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[PS]]* [[F]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[T2]], i8* [[T3]], i32 6, i32 2, i1 false)
+// CHECK-NEXT: [[T4:%.*]] = bitcast [[APS]]* [[TMP1]] to i64*
+// CHECK-NEXT: [[T5:%.*]] = load i64* [[T4]], align 8
+// CHECK-NEXT: [[T6:%.*]] = bitcast [[APS]]* [[T0]] to i64*
+// CHECK-NEXT: store atomic i64 [[T5]], i64* [[T6]] seq_cst, align 8
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+void testPromotedStructOps(_Atomic(PS) *p) {
+ PS a = __c11_atomic_load(p, 5);
+ __c11_atomic_store(p, a, 5);
+ PS b = __c11_atomic_exchange(p, a, 5);
+
+ _Bool v = __c11_atomic_compare_exchange_strong(p, &b, a, 5, 5);
+ v = __c11_atomic_compare_exchange_weak(p, &b, a, 5, 5);
+}
diff --git a/test/CodeGen/c11atomics.c b/test/CodeGen/c11atomics.c
new file mode 100644
index 0000000000..8d298af019
--- /dev/null
+++ b/test/CodeGen/c11atomics.c
@@ -0,0 +1,344 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-unknown-freebsd -std=c11 | FileCheck %s
+
+// Test that we are generating atomicrmw instructions, rather than
+// compare-exchange loops for common atomic ops. This makes a big difference
+// on RISC platforms, where the compare-exchange loop becomes a ll/sc pair for
+// the load and then another ll/sc in the loop, expanding to about 30
+// instructions when it should be only 4. It has a smaller, but still
+// noticeable, impact on platforms like x86 and RISC-V, where there are atomic
+// RMW instructions.
+//
+// We currently emit cmpxchg loops for most operations on _Bools, because
+// they're sufficiently rare that it's not worth making sure that the semantics
+// are correct.
+
+typedef int __attribute__((vector_size(16))) vector;
+
+_Atomic(_Bool) b;
+_Atomic(int) i;
+_Atomic(long long) l;
+_Atomic(short) s;
+_Atomic(char*) p;
+_Atomic(float) f;
+_Atomic(vector) v;
+
+// CHECK: testinc
+void testinc(void)
+{
+ // Special case for suffix bool++, sets to true and returns the old value.
+ // CHECK: atomicrmw xchg i8* @b, i8 1 seq_cst
+ b++;
+ // CHECK: atomicrmw add i32* @i, i32 1 seq_cst
+ i++;
+ // CHECK: atomicrmw add i64* @l, i64 1 seq_cst
+ l++;
+ // CHECK: atomicrmw add i16* @s, i16 1 seq_cst
+ s++;
+ // Prefix increment
+ // Special case for bool: set to true and return true
+ // CHECK: store atomic i8 1, i8* @b seq_cst, align 1
+ ++b;
+ // Currently, we have no variant of atomicrmw that returns the new value, so
+ // we have to generate an atomic add, which returns the old value, and then a
+ // non-atomic add.
+ // CHECK: atomicrmw add i32* @i, i32 1 seq_cst
+ // CHECK: add i32
+ ++i;
+ // CHECK: atomicrmw add i64* @l, i64 1 seq_cst
+ // CHECK: add i64
+ ++l;
+ // CHECK: atomicrmw add i16* @s, i16 1 seq_cst
+ // CHECK: add i16
+ ++s;
+}
+// CHECK: testdec
+void testdec(void)
+{
+ // CHECK: cmpxchg i8* @b
+ b--;
+ // CHECK: atomicrmw sub i32* @i, i32 1 seq_cst
+ i--;
+ // CHECK: atomicrmw sub i64* @l, i64 1 seq_cst
+ l--;
+ // CHECK: atomicrmw sub i16* @s, i16 1 seq_cst
+ s--;
+ // CHECK: cmpxchg i8* @b
+ --b;
+ // CHECK: atomicrmw sub i32* @i, i32 1 seq_cst
+ // CHECK: sub i32
+ --i;
+ // CHECK: atomicrmw sub i64* @l, i64 1 seq_cst
+ // CHECK: sub i64
+ --l;
+ // CHECK: atomicrmw sub i16* @s, i16 1 seq_cst
+ // CHECK: sub i16
+ --s;
+}
+// CHECK: testaddeq
+void testaddeq(void)
+{
+ // CHECK: cmpxchg i8* @b
+ // CHECK: atomicrmw add i32* @i, i32 42 seq_cst
+ // CHECK: atomicrmw add i64* @l, i64 42 seq_cst
+ // CHECK: atomicrmw add i16* @s, i16 42 seq_cst
+ b += 42;
+ i += 42;
+ l += 42;
+ s += 42;
+}
+// CHECK: testsubeq
+void testsubeq(void)
+{
+ // CHECK: cmpxchg i8* @b
+ // CHECK: atomicrmw sub i32* @i, i32 42 seq_cst
+ // CHECK: atomicrmw sub i64* @l, i64 42 seq_cst
+ // CHECK: atomicrmw sub i16* @s, i16 42 seq_cst
+ b -= 42;
+ i -= 42;
+ l -= 42;
+ s -= 42;
+}
+// CHECK: testxoreq
+void testxoreq(void)
+{
+ // CHECK: cmpxchg i8* @b
+ // CHECK: atomicrmw xor i32* @i, i32 42 seq_cst
+ // CHECK: atomicrmw xor i64* @l, i64 42 seq_cst
+ // CHECK: atomicrmw xor i16* @s, i16 42 seq_cst
+ b ^= 42;
+ i ^= 42;
+ l ^= 42;
+ s ^= 42;
+}
+// CHECK: testoreq
+void testoreq(void)
+{
+ // CHECK: cmpxchg i8* @b
+ // CHECK: atomicrmw or i32* @i, i32 42 seq_cst
+ // CHECK: atomicrmw or i64* @l, i64 42 seq_cst
+ // CHECK: atomicrmw or i16* @s, i16 42 seq_cst
+ b |= 42;
+ i |= 42;
+ l |= 42;
+ s |= 42;
+}
+// CHECK: testandeq
+void testandeq(void)
+{
+ // CHECK: cmpxchg i8* @b
+ // CHECK: atomicrmw and i32* @i, i32 42 seq_cst
+ // CHECK: atomicrmw and i64* @l, i64 42 seq_cst
+ // CHECK: atomicrmw and i16* @s, i16 42 seq_cst
+ b &= 42;
+ i &= 42;
+ l &= 42;
+ s &= 42;
+}
+
+// CHECK: define arm_aapcscc void @testFloat(float*
+void testFloat(_Atomic(float) *fp) {
+// CHECK: [[FP:%.*]] = alloca float*
+// CHECK-NEXT: [[X:%.*]] = alloca float
+// CHECK-NEXT: [[F:%.*]] = alloca float
+// CHECK-NEXT: [[TMP0:%.*]] = alloca float
+// CHECK-NEXT: [[TMP1:%.*]] = alloca float
+// CHECK-NEXT: store float* {{%.*}}, float** [[FP]]
+
+// CHECK-NEXT: [[T0:%.*]] = load float** [[FP]]
+// CHECK-NEXT: store float 1.000000e+00, float* [[T0]], align 4
+ __c11_atomic_init(fp, 1.0f);
+
+// CHECK-NEXT: store float 2.000000e+00, float* [[X]], align 4
+ _Atomic(float) x = 2.0f;
+
+// CHECK-NEXT: [[T0:%.*]] = load float** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast float* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast float* [[TMP0]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_load(i32 4, i8* [[T1]], i8* [[T2]], i32 5)
+// CHECK-NEXT: [[T3:%.*]] = load float* [[TMP0]], align 4
+// CHECK-NEXT: store float [[T3]], float* [[F]]
+ float f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = load float* [[F]], align 4
+// CHECK-NEXT: [[T1:%.*]] = load float** [[FP]], align 4
+// CHECK-NEXT: store float [[T0]], float* [[TMP1]], align 4
+// CHECK-NEXT: [[T2:%.*]] = bitcast float* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = bitcast float* [[TMP1]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_store(i32 4, i8* [[T2]], i8* [[T3]], i32 5)
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+// CHECK: define arm_aapcscc void @testComplexFloat([[CF:{ float, float }]]*
+void testComplexFloat(_Atomic(_Complex float) *fp) {
+// CHECK: [[FP:%.*]] = alloca [[CF]]*, align 4
+// CHECK-NEXT: [[X:%.*]] = alloca [[CF]], align 8
+// CHECK-NEXT: [[F:%.*]] = alloca [[CF]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = alloca [[CF]], align 8
+// CHECK-NEXT: [[TMP1:%.*]] = alloca [[CF]], align 8
+// CHECK-NEXT: store [[CF]]*
+
+// CHECK-NEXT: [[P:%.*]] = load [[CF]]** [[FP]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[P]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[P]], i32 0, i32 1
+// CHECK-NEXT: store float 1.000000e+00, float* [[T0]]
+// CHECK-NEXT: store float 0.000000e+00, float* [[T1]]
+ __c11_atomic_init(fp, 1.0f);
+
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[X]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[X]], i32 0, i32 1
+// CHECK-NEXT: store float 2.000000e+00, float* [[T0]]
+// CHECK-NEXT: store float 0.000000e+00, float* [[T1]]
+ _Atomic(_Complex float) x = 2.0f;
+
+// CHECK-NEXT: [[T0:%.*]] = load [[CF]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[CF]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[CF]]* [[TMP0]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_load(i32 8, i8* [[T1]], i8* [[T2]], i32 5)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[TMP0]], i32 0, i32 0
+// CHECK-NEXT: [[R:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[TMP0]], i32 0, i32 1
+// CHECK-NEXT: [[I:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 1
+// CHECK-NEXT: store float [[R]], float* [[T0]]
+// CHECK-NEXT: store float [[I]], float* [[T1]]
+ _Complex float f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 0
+// CHECK-NEXT: [[R:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 1
+// CHECK-NEXT: [[I:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[DEST:%.*]] = load [[CF]]** [[FP]], align 4
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[TMP1]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[TMP1]], i32 0, i32 1
+// CHECK-NEXT: store float [[R]], float* [[T0]]
+// CHECK-NEXT: store float [[I]], float* [[T1]]
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[CF]]* [[DEST]] to i8*
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[CF]]* [[TMP1]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_store(i32 8, i8* [[T0]], i8* [[T1]], i32 5)
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+typedef struct { short x, y, z, w; } S;
+// CHECK: define arm_aapcscc void @testStruct([[S:.*]]*
+void testStruct(_Atomic(S) *fp) {
+// CHECK: [[FP:%.*]] = alloca [[S]]*, align 4
+// CHECK-NEXT: [[X:%.*]] = alloca [[S]], align 8
+// CHECK-NEXT: [[F:%.*]] = alloca [[S:%.*]], align 2
+// CHECK-NEXT: [[TMP0:%.*]] = alloca [[S]], align 8
+// CHECK-NEXT: store [[S]]*
+
+// CHECK-NEXT: [[P:%.*]] = load [[S]]** [[FP]]
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[S]]* [[P]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 3
+// CHECK-NEXT: store i16 4, i16* [[T0]], align 2
+ __c11_atomic_init(fp, (S){1,2,3,4});
+
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[S]]* [[X]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 3
+// CHECK-NEXT: store i16 4, i16* [[T0]], align 2
+ _Atomic(S) x = (S){1,2,3,4};
+
+// CHECK-NEXT: [[T0:%.*]] = load [[S]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[S]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[S]]* [[F]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_load(i32 8, i8* [[T1]], i8* [[T2]], i32 5)
+ S f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = load [[S]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[S]]* [[TMP0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[S]]* [[F]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[T1]], i8* [[T2]], i32 8, i32 2, i1 false)
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[S]]* [[T0]] to i8*
+// CHECK-NEXT: [[T4:%.*]] = bitcast [[S]]* [[TMP0]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_store(i32 8, i8* [[T3]], i8* [[T4]], i32 5)
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+typedef struct { short x, y, z; } PS;
+// CHECK: define arm_aapcscc void @testPromotedStruct([[APS:.*]]*
+void testPromotedStruct(_Atomic(PS) *fp) {
+// CHECK: [[FP:%.*]] = alloca [[APS]]*, align 4
+// CHECK-NEXT: [[X:%.*]] = alloca [[APS]], align 8
+// CHECK-NEXT: [[F:%.*]] = alloca [[PS:%.*]], align 2
+// CHECK-NEXT: [[TMP0:%.*]] = alloca [[APS]], align 8
+// CHECK-NEXT: [[TMP1:%.*]] = alloca [[APS]], align 8
+// CHECK-NEXT: store [[APS]]*
+
+// CHECK-NEXT: [[P:%.*]] = load [[APS]]** [[FP]]
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[APS]]* [[P]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[P]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T1]], align 2
+ __c11_atomic_init(fp, (PS){1,2,3});
+
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[APS]]* [[X]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[X]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T1]], align 2
+ _Atomic(PS) x = (PS){1,2,3};
+
+// CHECK-NEXT: [[T0:%.*]] = load [[APS]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[APS]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[APS]]* [[TMP0]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_load(i32 8, i8* [[T1]], i8* [[T2]], i32 5)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[TMP0]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[PS]]* [[F]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[PS]]* [[T0]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[T1]], i8* [[T2]], i32 6, i32 2, i1 false)
+ PS f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = load [[APS]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[APS]]* [[TMP1]], i32 0, i32 0
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[PS]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[PS]]* [[F]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[T2]], i8* [[T3]], i32 6, i32 2, i1 false)
+// CHECK-NEXT: [[T4:%.*]] = bitcast [[APS]]* [[T0]] to i8*
+// CHECK-NEXT: [[T5:%.*]] = bitcast [[APS]]* [[TMP1]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_store(i32 8, i8* [[T4]], i8* [[T5]], i32 5)
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+// CHECK: define arm_aapcscc void @testPromotedStructOps([[APS:.*]]*
+
+// FIXME: none of these look right, but we can leave the "test" here
+// to make sure they at least don't crash.
+void testPromotedStructOps(_Atomic(PS) *p) {
+ PS a = __c11_atomic_load(p, 5);
+ __c11_atomic_store(p, a, 5);
+ PS b = __c11_atomic_exchange(p, a, 5);
+ _Bool v = __c11_atomic_compare_exchange_strong(p, &b, a, 5, 5);
+ v = __c11_atomic_compare_exchange_weak(p, &b, a, 5, 5);
+}
diff --git a/test/CodeGen/compound-literal.c b/test/CodeGen/compound-literal.c
index a8eec615ad..e4bf962e12 100644
--- a/test/CodeGen/compound-literal.c
+++ b/test/CodeGen/compound-literal.c
@@ -32,3 +32,37 @@ void f() {
s = (S){s.y,s.x};
// CHECK-NEXT: ret void
}
+
+// CHECK: define i48 @g(
+struct G { short x, y, z; };
+struct G g(int x, int y, int z) {
+ // CHECK: [[RESULT:%.*]] = alloca [[G:%.*]], align 2
+ // CHECK-NEXT: [[X:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[Y:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[Z:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[COERCE_TEMP:%.*]] = alloca i48
+ // CHECK-NEXT: store i32
+ // CHECK-NEXT: store i32
+ // CHECK-NEXT: store i32
+
+ // Evaluate the compound literal directly in the result value slot.
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[G]]* [[RESULT]], i32 0, i32 0
+ // CHECK-NEXT: [[T1:%.*]] = load i32* [[X]], align 4
+ // CHECK-NEXT: [[T2:%.*]] = trunc i32 [[T1]] to i16
+ // CHECK-NEXT: store i16 [[T2]], i16* [[T0]], align 2
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[G]]* [[RESULT]], i32 0, i32 1
+ // CHECK-NEXT: [[T1:%.*]] = load i32* [[Y]], align 4
+ // CHECK-NEXT: [[T2:%.*]] = trunc i32 [[T1]] to i16
+ // CHECK-NEXT: store i16 [[T2]], i16* [[T0]], align 2
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[G]]* [[RESULT]], i32 0, i32 2
+ // CHECK-NEXT: [[T1:%.*]] = load i32* [[Z]], align 4
+ // CHECK-NEXT: [[T2:%.*]] = trunc i32 [[T1]] to i16
+ // CHECK-NEXT: store i16 [[T2]], i16* [[T0]], align 2
+ return (struct G) { x, y, z };
+
+ // CHECK-NEXT: [[T0:%.*]] = bitcast i48* [[COERCE_TEMP]] to i8*
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[G]]* [[RESULT]] to i8*
+ // CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T0]], i8* [[T1]], i64 6
+ // CHECK-NEXT: [[T0:%.*]] = load i48* [[COERCE_TEMP]]
+ // CHECK-NEXT: ret i48 [[T0]]
+}
diff --git a/test/CodeGen/function-attributes.c b/test/CodeGen/function-attributes.c
index 8ad00fa80d..25ca9163a1 100644
--- a/test/CodeGen/function-attributes.c
+++ b/test/CodeGen/function-attributes.c
@@ -43,7 +43,7 @@ void f9b(void) { f9a(); }
// FIXME: We should be setting nounwind on calls.
// CHECK: call i32 @f10_t()
-// CHECK: [[NUW]]
+// CHECK: [[NUW_RN:#[0-9]+]]
// CHECK: {
int __attribute__((const)) f10_t(void);
int f10(void) { return f10_t(); }
@@ -119,6 +119,8 @@ void f19(void) {
// CHECK: attributes [[NUW]] = { nounwind optsize readnone{{.*}} }
// CHECK: attributes [[AI]] = { alwaysinline nounwind optsize readnone{{.*}} }
-// CHECK: attributes [[NR]] = { noreturn nounwind optsize }
// CHECK: attributes [[ALIGN]] = { nounwind optsize readnone alignstack=16{{.*}} }
-// CHECK: attributes [[RT]] = { nounwind optsize returns_twice }
+// CHECK: attributes [[RT]] = { nounwind optsize returns_twice{{.*}} }
+// CHECK: attributes [[NR]] = { noreturn nounwind optsize }
+// CHECK: attributes [[NUW_RN]] = { nounwind optsize readnone }
+// CHECK: attributes [[RT_CALL]] = { nounwind optsize returns_twice }
diff --git a/test/CodeGen/mips-constraint-regs.c b/test/CodeGen/mips-constraint-regs.c
index c42a888fcf..0d533f5fc7 100644
--- a/test/CodeGen/mips-constraint-regs.c
+++ b/test/CodeGen/mips-constraint-regs.c
@@ -2,9 +2,7 @@
// RUN: | FileCheck %s
// This checks that the frontend will accept inline asm constraints
-// c', 'l' and 'x'. Semantic checking will happen in the
-// llvm backend. Any bad constraint letters will cause the frontend to
-// error out.
+// c', 'l' and 'x'.
int main()
{
diff --git a/test/CodeGen/mips-constraints-mem.c b/test/CodeGen/mips-constraints-mem.c
new file mode 100644
index 0000000000..ea6bcaff97
--- /dev/null
+++ b/test/CodeGen/mips-constraints-mem.c
@@ -0,0 +1,26 @@
+// RUN: %clang -target mipsel-unknown-linux -S -o - -emit-llvm %s \
+// RUN: | FileCheck %s
+
+// This checks that the frontend will accept inline asm memory constraints.
+
+int foo()
+{
+
+ // 'R': An address that can be used in a non-macro load or stor'
+ // This test will result in the higher and lower nibbles being
+ // switched due to the lwl/lwr instruction pairs.
+ // CHECK: %{{[0-9]+}} = call i32 asm sideeffect "lwl $0, 1 + $1\0A\09lwr $0, 2 + $1\0A\09", "=r,*R"(i32* %{{[0-9,a-f]+}}) #1, !srcloc !0
+
+ int c = 0xffbbccdd;
+
+ int *p = &c;
+ int out = 0;
+
+ __asm volatile (
+ "lwl %0, 1 + %1\n\t"
+ "lwr %0, 2 + %1\n\t"
+ : "=r"(out)
+ : "R"(*p)
+ );
+ return 0;
+}
diff --git a/test/CodeGen/sanitize-thread-attr.cpp b/test/CodeGen/sanitize-thread-attr.cpp
index 2dec3c48c6..fe5d81026d 100644
--- a/test/CodeGen/sanitize-thread-attr.cpp
+++ b/test/CodeGen/sanitize-thread-attr.cpp
@@ -9,33 +9,33 @@
// when ThreadSanitizer is enabled, unless no_sanitize_thread attribute
// is present.
-// WITHOUT: NoTSAN1{{.*}}) #[[NOATTR:[0-9]+]]
-// BL: NoTSAN1{{.*}}) #[[NOATTR:[0-9]+]]
-// TSAN: NoTSAN1{{.*}}) #[[NOATTR:[0-9]+]]
+// WITHOUT: NoTSAN1{{.*}}) [[NOATTR:#[0-9]+]]
+// BL: NoTSAN1{{.*}}) [[NOATTR:#[0-9]+]]
+// TSAN: NoTSAN1{{.*}}) [[NOATTR:#[0-9]+]]
__attribute__((no_sanitize_thread))
int NoTSAN1(int *a) { return *a; }
-// WITHOUT: NoTSAN2{{.*}}) #[[NOATTR]]
-// BL: NoTSAN2{{.*}}) #[[NOATTR]]
-// TSAN: NoTSAN2{{.*}}) #[[NOATTR]]
+// WITHOUT: NoTSAN2{{.*}}) [[NOATTR]]
+// BL: NoTSAN2{{.*}}) [[NOATTR]]
+// TSAN: NoTSAN2{{.*}}) [[NOATTR]]
__attribute__((no_sanitize_thread))
int NoTSAN2(int *a);
int NoTSAN2(int *a) { return *a; }
-// WITHOUT: TSANOk{{.*}}) #[[NOATTR]]
-// BL: TSANOk{{.*}}) #[[NOATTR]]
-// TSAN: TSANOk{{.*}}) #[[WITH:[0-9]+]]
+// WITHOUT: TSANOk{{.*}}) [[NOATTR]]
+// BL: TSANOk{{.*}}) [[NOATTR]]
+// TSAN: TSANOk{{.*}}) [[WITH:#[0-9]+]]
int TSANOk(int *a) { return *a; }
-// WITHOUT: TemplateTSANOk{{.*}}) #[[NOATTR]]
-// BL: TemplateTSANOk{{.*}}) #[[NOATTR]]
-// TSAN: TemplateTSANOk{{.*}}) #[[WITH]]
+// WITHOUT: TemplateTSANOk{{.*}}) [[NOATTR]]
+// BL: TemplateTSANOk{{.*}}) [[NOATTR]]
+// TSAN: TemplateTSANOk{{.*}}) [[WITH]]
template<int i>
int TemplateTSANOk() { return i; }
-// WITHOUT: TemplateNoTSAN{{.*}}) #[[NOATTR]]
-// BL: TemplateNoTSAN{{.*}}) #[[NOATTR]]
-// TSAN: TemplateNoTSAN{{.*}}) #[[NOATTR]]
+// WITHOUT: TemplateNoTSAN{{.*}}) [[NOATTR]]
+// BL: TemplateNoTSAN{{.*}}) [[NOATTR]]
+// TSAN: TemplateNoTSAN{{.*}}) [[NOATTR]]
template<int i>
__attribute__((no_sanitize_thread))
int TemplateNoTSAN() { return i; }
@@ -46,12 +46,16 @@ int force_instance = TemplateTSANOk<42>()
// Check that __cxx_global_var_init* get the sanitize_thread attribute.
int global1 = 0;
int global2 = *(int*)((char*)&global1+1);
-// WITHOUT: @__cxx_global_var_init{{.*}}#[[NOATTR]]
-// BL: @__cxx_global_var_init{{.*}}#[[NOATTR]]
-// TSAN: @__cxx_global_var_init{{.*}}#[[WITH]]
+// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]]
+// BL: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]]
+// TSAN: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]]
-// WITHOUT: attributes #[[NOATTR]] = { nounwind{{.*}} }
-// BL: attributes #[[NOATTR]] = { nounwind{{.*}} }
+// WITHOUT: attributes [[NOATTR]] = { nounwind{{.*}} }
+// WITHOUT: attributes [[NOATTR_NO_TF]] = { nounwind }
-// TSAN: attributes #[[NOATTR]] = { nounwind{{.*}} }
-// TSAN: attributes #[[WITH]] = { nounwind{{.*}} sanitize_thread
+// BL: attributes [[NOATTR]] = { nounwind{{.*}} }
+// BL: attributes [[NOATTR_NO_TF]] = { nounwind{{.*}} }
+
+// TSAN: attributes [[NOATTR]] = { nounwind{{.*}} }
+// TSAN: attributes [[WITH]] = { nounwind sanitize_thread{{.*}} }
+// TSAN: attributes [[WITH_NO_TF]] = { nounwind sanitize_thread }
diff --git a/test/CodeGen/string-literal.c b/test/CodeGen/string-literal.c
index 962b19d3dd..8bc97f1887 100644
--- a/test/CodeGen/string-literal.c
+++ b/test/CodeGen/string-literal.c
@@ -1,87 +1,107 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=C %s
-// RUN: %clang_cc1 -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=C %s
-// RUN: %clang_cc1 -x c++ -std=c++11 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CPP0X %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-C %s
+// RUN: %clang_cc1 -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-C %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-CXX11 %s
+// RUN: %clang_cc1 -x c -std=c11 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-C11 %s
#include <stddef.h>
+#ifndef __cplusplus
+typedef __WCHAR_TYPE__ wchar_t;
+typedef __CHAR16_TYPE__ char16_t;
+typedef __CHAR32_TYPE__ char32_t;
+#endif
+
int main() {
// CHECK-C: private unnamed_addr constant [10 x i8] c"abc\00\00\00\00\00\00\00", align 1
- // CHECK-CPP0X: private unnamed_addr constant [10 x i8] c"abc\00\00\00\00\00\00\00", align 1
+ // CHECK-C11: private unnamed_addr constant [10 x i8] c"abc\00\00\00\00\00\00\00", align 1
+ // CHECK-CXX11: private unnamed_addr constant [10 x i8] c"abc\00\00\00\00\00\00\00", align 1
char a[10] = "abc";
// This should convert to utf8.
// CHECK-C: private unnamed_addr constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
- // CHECK-CPP0X: private unnamed_addr constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
+ // CHECK-C11: private unnamed_addr constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
+ // CHECK-CXX11: private unnamed_addr constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
char b[10] = "\u1120\u0220\U00102030";
// CHECK-C: private unnamed_addr constant [3 x i32] [i32 65, i32 66, i32 0], align 4
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 65, i32 66, i32 0], align 4
+ // CHECK-C11: private unnamed_addr constant [3 x i32] [i32 65, i32 66, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 65, i32 66, i32 0], align 4
const wchar_t *foo = L"AB";
// CHECK-C: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110027, i32 0], align 4
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110027, i32 0], align 4
+ // CHECK-C11: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110027, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110027, i32 0], align 4
const wchar_t *bar = L"\u1234\U0010F00B";
// CHECK-C: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110028, i32 0], align 4
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110028, i32 0], align 4
+ // CHECK-C11: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110028, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110028, i32 0], align 4
const wchar_t *baz = L"\u1234" "\U0010F00C";
-#if __cplusplus >= 201103L
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 67, i32 68, i32 0], align 4
+#if __cplusplus >= 201103L || __STDC_VERSION__ >= 201112L
+ // CHECK-C11: private unnamed_addr constant [3 x i32] [i32 67, i32 68, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 67, i32 68, i32 0], align 4
const char32_t *c = U"CD";
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 4661, i32 1110028, i32 0], align 4
+ // CHECK-C11: private unnamed_addr constant [3 x i32] [i32 4661, i32 1110028, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 4661, i32 1110028, i32 0], align 4
const char32_t *d = U"\u1235\U0010F00C";
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 4661, i32 1110027, i32 0], align 4
+ // CHECK-C11: private unnamed_addr constant [3 x i32] [i32 4661, i32 1110027, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 4661, i32 1110027, i32 0], align 4
const char32_t *o = "\u1235" U"\U0010F00B";
- // CHECK-CPP0X: private unnamed_addr constant [3 x i16] [i16 69, i16 70, i16 0], align 2
+ // CHECK-C11: private unnamed_addr constant [3 x i16] [i16 69, i16 70, i16 0], align 2
+ // CHECK-CXX11: private unnamed_addr constant [3 x i16] [i16 69, i16 70, i16 0], align 2
const char16_t *e = u"EF";
// This should convert to utf16.
- // CHECK-CPP0X: private unnamed_addr constant [5 x i16] [i16 4384, i16 544, i16 -9272, i16 -9168, i16 0], align 2
+ // CHECK-C11: private unnamed_addr constant [5 x i16] [i16 4384, i16 544, i16 -9272, i16 -9168, i16 0], align 2
+ // CHECK-CXX11: private unnamed_addr constant [5 x i16] [i16 4384, i16 544, i16 -9272, i16 -9168, i16 0], align 2
const char16_t *f = u"\u1120\u0220\U00102030";
// This should convert to utf16.
- // CHECK-CPP0X: private unnamed_addr constant [5 x i16] [i16 4384, i16 800, i16 -9272, i16 -9168, i16 0], align 2
+ // CHECK-C11: private unnamed_addr constant [5 x i16] [i16 4384, i16 800, i16 -9272, i16 -9168, i16 0], align 2
+ // CHECK-CXX11: private unnamed_addr constant [5 x i16] [i16 4384, i16 800, i16 -9272, i16 -9168, i16 0], align 2
const char16_t *p = u"\u1120\u0320" "\U00102030";
- // CHECK-CPP0X: private unnamed_addr constant [4 x i8] c"def\00", align 1
+ // CHECK-C11: private unnamed_addr constant [4 x i8] c"def\00", align 1
+ // CHECK-CXX11: private unnamed_addr constant [4 x i8] c"def\00", align 1
const char *g = u8"def";
- // CHECK-CPP0X: private unnamed_addr constant [4 x i8] c"ghi\00", align 1
+#ifdef __cplusplus
+ // CHECK-CXX11: private unnamed_addr constant [4 x i8] c"ghi\00", align 1
const char *h = R"foo(ghi)foo";
- // CHECK-CPP0X: private unnamed_addr constant [4 x i8] c"jkl\00", align 1
+ // CHECK-CXX11: private unnamed_addr constant [4 x i8] c"jkl\00", align 1
const char *i = u8R"bar(jkl)bar";
- // CHECK-CPP0X: private unnamed_addr constant [3 x i16] [i16 71, i16 72, i16 0], align 2
+ // CHECK-CXX11: private unnamed_addr constant [3 x i16] [i16 71, i16 72, i16 0], align 2
const char16_t *j = uR"foo(GH)foo";
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 73, i32 74, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 73, i32 74, i32 0], align 4
const char32_t *k = UR"bar(IJ)bar";
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 75, i32 76, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 75, i32 76, i32 0], align 4
const wchar_t *l = LR"bar(KL)bar";
- // CHECK-CPP0X: private unnamed_addr constant [9 x i8] c"abc\5Cndef\00", align 1
+ // CHECK-CXX11: private unnamed_addr constant [9 x i8] c"abc\5Cndef\00", align 1
const char *m = R"(abc\ndef)";
- // CHECK-CPP0X: private unnamed_addr constant [8 x i8] c"abc\0Adef\00", align 1
+ // CHECK-CXX11: private unnamed_addr constant [8 x i8] c"abc\0Adef\00", align 1
const char *n = R"(abc
def)";
- // CHECK-CPP0X: private unnamed_addr constant [11 x i8] c"abc\0Adefghi\00", align 1
+ // CHECK-CXX11: private unnamed_addr constant [11 x i8] c"abc\0Adefghi\00", align 1
const char *q = R"(abc
def)" "ghi";
- // CHECK-CPP0X: private unnamed_addr constant [13 x i8] c"abc\5C\0A??=\0Adef\00", align 1
+ // CHECK-CXX11: private unnamed_addr constant [13 x i8] c"abc\5C\0A??=\0Adef\00", align 1
const char *r = R\
"(abc\
??=
def)";
-
+#endif
#endif
}
diff --git a/test/CodeGen/unwind-attr.c b/test/CodeGen/unwind-attr.c
index 1a7d3cdd1c..e505a6e9e2 100644
--- a/test/CodeGen/unwind-attr.c
+++ b/test/CodeGen/unwind-attr.c
@@ -3,7 +3,7 @@
int opaque();
-// CHECK: define [[INT:i.*]] @test0() {
+// CHECK: define [[INT:i.*]] @test0() [[TF:#[0-9]+]] {
// CHECK-NOEXC: define [[INT:i.*]] @test0() [[NUW:#[0-9]+]] {
int test0(void) {
return opaque();
@@ -17,12 +17,13 @@ int test1(void) {
}
// <rdar://problem/8283071>: not for weak functions
-// CHECK: define weak [[INT:i.*]] @test2() {
+// CHECK: define weak [[INT:i.*]] @test2() [[TF]] {
// CHECK-NOEXC: define weak [[INT:i.*]] @test2() [[NUW]] {
__attribute__((weak)) int test2(void) {
return 0;
}
+// CHECK: attributes [[TF]] = { "{{.*}} }
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
// CHECK-NOEXC: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp b/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp
index 6b61d92580..3828388d48 100644
--- a/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp
+++ b/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp
@@ -3,16 +3,19 @@ int c(void) __attribute__((const));
int p(void) __attribute__((pure));
int t(void);
-// CHECK: define i32 @_Z1fv() {
+// CHECK: define i32 @_Z1fv() [[TF:#[0-9]+]] {
int f(void) {
- // CHECK: call i32 @_Z1cv() [[NUW_RN:#[0-9]+]]
- // CHECK: call i32 @_Z1pv() [[NUW_RO:#[0-9]+]]
+ // CHECK: call i32 @_Z1cv() [[NUW_RN_CALL:#[0-9]+]]
+ // CHECK: call i32 @_Z1pv() [[NUW_RO_CALL:#[0-9]+]]
return c() + p() + t();
}
-// CHECK: declare i32 @_Z1cv() #0
-// CHECK: declare i32 @_Z1pv() #1
-// CHECK: declare i32 @_Z1tv()
+// CHECK: declare i32 @_Z1cv() [[NUW_RN:#[0-9]+]]
+// CHECK: declare i32 @_Z1pv() [[NUW_RO:#[0-9]+]]
+// CHECK: declare i32 @_Z1tv() [[TF]]
-// CHECK: attributes [[NUW_RN]] = { nounwind readnone }
-// CHECK: attributes [[NUW_RO]] = { nounwind readonly }
+// CHECK: attributes [[TF]] = { {{.*}} }
+// CHECK: attributes [[NUW_RN]] = { nounwind readnone{{.*}} }
+// CHECK: attributes [[NUW_RO]] = { nounwind readonly{{.*}} }
+// CHECK: attributes [[NUW_RN_CALL]] = { nounwind readnone }
+// CHECK: attributes [[NUW_RO_CALL]] = { nounwind readonly }
diff --git a/test/CodeGenCXX/attr.cpp b/test/CodeGenCXX/attr.cpp
index 6db214e327..4748cda8cc 100644
--- a/test/CodeGenCXX/attr.cpp
+++ b/test/CodeGenCXX/attr.cpp
@@ -31,4 +31,4 @@ int test1() { return 10; }
// CHECK at top of file
extern "C" int test2() __attribute__((alias("_Z5test1v")));
-// CHECK: attributes [[NUW]] = { nounwind }
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/blocks-cxx11.cpp b/test/CodeGenCXX/blocks-cxx11.cpp
index 996db1afe6..3f0380abbd 100644
--- a/test/CodeGenCXX/blocks-cxx11.cpp
+++ b/test/CodeGenCXX/blocks-cxx11.cpp
@@ -82,3 +82,33 @@ namespace test_complex_int_ref_mutable {
}
}
+// rdar://13295759
+namespace test_block_in_lambda {
+ void takeBlock(void (^block)());
+
+ // The captured variable has to be non-POD so that we have a copy expression.
+ struct A {
+ void *p;
+ A(const A &);
+ ~A();
+ void use() const;
+ };
+
+ void test(A a) {
+ auto lambda = [a]() {
+ takeBlock(^{ a.use(); });
+ };
+ lambda(); // make sure we emit the invocation function
+ }
+ // CHECK: define internal void @"_ZZN20test_block_in_lambda4testENS_1AEENK3$_0clEv"(
+ // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
+ // CHECK: [[THIS:%.*]] = load [[LAMBDA_T:%.*]]**
+ // CHECK: [[TO_DESTROY:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+ // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[LAMBDA_T]]* [[THIS]], i32 0, i32 0
+ // CHECK-NEXT: call void @_ZN20test_block_in_lambda1AC1ERKS0_({{.*}}* [[T0]], {{.*}}* [[T1]])
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
+ // CHECK-NEXT: call void @_ZN20test_block_in_lambda9takeBlockEU13block_pointerFvvE(void ()* [[T0]])
+ // CHECK-NEXT: call void @_ZN20test_block_in_lambda1AD1Ev({{.*}}* [[TO_DESTROY]])
+ // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenCXX/cxx11-exception-spec.cpp b/test/CodeGenCXX/cxx11-exception-spec.cpp
index 5fd1fd8f14..49ca8610f2 100644
--- a/test/CodeGenCXX/cxx11-exception-spec.cpp
+++ b/test/CodeGenCXX/cxx11-exception-spec.cpp
@@ -10,7 +10,7 @@ template<typename T> struct S {
static void g() noexcept(sizeof(T) == 4);
};
-// CHECK: define {{.*}} @_Z1fIsEvv() {
+// CHECK: define {{.*}} @_Z1fIsEvv() [[NONE:#[0-9]+]] {
template<> void f<short>() { h(); }
// CHECK: define {{.*}} @_Z1fIA2_sEvv() [[NUW:#[0-9]+]] {
template<> void f<short[2]>() noexcept { h(); }
@@ -21,7 +21,7 @@ template<> void S<short>::f() { h(); }
// CHECK: define {{.*}} @_ZN1SIA2_sE1fEv() [[NUW]]
template<> void S<short[2]>::f() noexcept { h(); }
-// CHECK: define {{.*}} @_Z1fIDsEvv() {
+// CHECK: define {{.*}} @_Z1fIDsEvv() [[NONE]] {
template void f<char16_t>();
// CHECK: define {{.*}} @_Z1fIA2_DsEvv() [[NUW]] {
template void f<char16_t[2]>();
@@ -35,7 +35,7 @@ template void S<char16_t[2]>::f();
void h() {
// CHECK: define {{.*}} @_Z1fIiEvv() [[NUW]] {
f<int>();
- // CHECK: define {{.*}} @_Z1fIA2_iEvv() {
+ // CHECK: define {{.*}} @_Z1fIA2_iEvv() [[NONE]] {
f<int[2]>();
// CHECK: define {{.*}} @_ZN1SIiE1fEv() [[NUW]]
@@ -46,7 +46,7 @@ void h() {
// CHECK: define {{.*}} @_Z1fIfEvv() [[NUW]] {
void (*f1)() = &f<float>;
- // CHECK: define {{.*}} @_Z1fIdEvv() {
+ // CHECK: define {{.*}} @_Z1fIdEvv() [[NONE]] {
void (*f2)() = &f<double>;
// CHECK: define {{.*}} @_ZN1SIfE1fEv() [[NUW]]
@@ -57,7 +57,7 @@ void h() {
// CHECK: define {{.*}} @_Z1fIA4_cEvv() [[NUW]] {
(void)&f<char[4]>;
- // CHECK: define {{.*}} @_Z1fIcEvv() {
+ // CHECK: define {{.*}} @_Z1fIcEvv() [[NONE]] {
(void)&f<char>;
// CHECK: define {{.*}} @_ZN1SIA4_cE1fEv() [[NUW]]
@@ -119,4 +119,5 @@ void j() {
Nested<long>().f<false, long>();
}
-// CHECK: attributes [[NUW]] = { nounwind }
+// CHECK: attributes [[NONE]] = { {{.*}} }
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/default-destructor-synthesis.cpp b/test/CodeGenCXX/default-destructor-synthesis.cpp
index f9e13eb526..af780044d1 100644
--- a/test/CodeGenCXX/default-destructor-synthesis.cpp
+++ b/test/CodeGenCXX/default-destructor-synthesis.cpp
@@ -24,7 +24,7 @@ struct M : Q, P {
Q q_arr[2][3];
};
-// CHECK: define i32 @_Z1fv() #0
+// CHECK: define i32 @_Z1fv() [[NUW:#[0-9]+]]
int f() {
{
count = 1;
@@ -35,4 +35,4 @@ int f() {
return count;
}
-// CHECK: attributes #0 = { nounwind{{.*}} }
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/derived-to-base.cpp b/test/CodeGenCXX/derived-to-base.cpp
index fa03fee8d6..c69b45630e 100644
--- a/test/CodeGenCXX/derived-to-base.cpp
+++ b/test/CodeGenCXX/derived-to-base.cpp
@@ -15,7 +15,7 @@ void f() {
b.f();
}
-// CHECK: define %struct.B* @_Z1fP1A(%struct.A* %a) #0
+// CHECK: define %struct.B* @_Z1fP1A(%struct.A* %a) [[NUW:#[0-9]+]]
B *f(A *a) {
// CHECK-NOT: br label
// CHECK: ret %struct.B*
@@ -25,7 +25,7 @@ B *f(A *a) {
// PR5965
namespace PR5965 {
-// CHECK: define %struct.A* @_ZN6PR59651fEP1B(%struct.B* %b) #0
+// CHECK: define %struct.A* @_ZN6PR59651fEP1B(%struct.B* %b) [[NUW]]
A *f(B* b) {
// CHECK-NOT: br label
// CHECK: ret %struct.A*
@@ -46,4 +46,4 @@ namespace test3 {
}
}
-// CHECK: attributes #0 = { nounwind{{.*}} }
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/exceptions.cpp b/test/CodeGenCXX/exceptions.cpp
index fb0a9b2e5e..f6f5079791 100644
--- a/test/CodeGenCXX/exceptions.cpp
+++ b/test/CodeGenCXX/exceptions.cpp
@@ -526,6 +526,4 @@ namespace test11 {
// (After this is a terminate landingpad.)
}
-// CHECK: attributes [[NUW]] = { nounwind }
// CHECK: attributes [[NI_NR_NUW]] = { noinline noreturn nounwind }
-// CHECK: attributes [[NR_NUW]] = { noreturn nounwind }
diff --git a/test/CodeGenCXX/extern-c.cpp b/test/CodeGenCXX/extern-c.cpp
index ca5cd7372c..a8c4f0cdbd 100644
--- a/test/CodeGenCXX/extern-c.cpp
+++ b/test/CodeGenCXX/extern-c.cpp
@@ -1,16 +1,38 @@
-// RUN: %clang_cc1 -emit-llvm %s -o %t
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
namespace foo {
-// RUN: not grep "@a = global i32" %t
+// CHECK-NOT: @a = global i32
extern "C" int a;
-// RUN: not grep "@_ZN3foo1bE = global i32" %t
+// CHECK-NOT: @_ZN3foo1bE = global i32
extern int b;
-// RUN: grep "@_ZN3foo1cE = global i32" %t | count 1
+// CHECK: @_ZN3foo1cE = global i32
int c = 5;
-// RUN: not grep "@_ZN3foo1dE" %t
+// CHECK-NOT: @_ZN3foo1dE
extern "C" struct d;
}
+
+namespace test1 {
+ namespace {
+ struct X {};
+ }
+ extern "C" {
+ // CHECK: @test1_b = global
+ X test1_b = X();
+ }
+ void *use = &test1_b;
+ // CHECK: @_ZN5test13useE = global
+}
+
+namespace test2 {
+ namespace {
+ struct X {};
+ }
+
+ // CHECK: @test2_b = global
+ extern "C" X test2_b;
+ X test2_b;
+}
diff --git a/test/CodeGenCXX/global-dtor-no-atexit.cpp b/test/CodeGenCXX/global-dtor-no-atexit.cpp
index 0b323e9a42..7c4b6aa1e0 100644
--- a/test/CodeGenCXX/global-dtor-no-atexit.cpp
+++ b/test/CodeGenCXX/global-dtor-no-atexit.cpp
@@ -5,12 +5,12 @@
// CHECK: call void @_ZN1AC1Ev([[A:%.*]]* @a)
// CHECK-NEXT: call i32 @atexit(void ()* @__dtor_a)
-// CHECK: define internal void @__dtor_a() #0
+// CHECK: define internal void @__dtor_a() [[NUW:#[0-9]+]]
// CHECK: call void @_ZN1AD1Ev([[A]]* @a)
// CHECK: call void @_ZN1AC1Ev([[A]]* @b)
// CHECK-NEXT: call i32 @atexit(void ()* @__dtor_b)
-// CHECK: define internal void @__dtor_b() #0
+// CHECK: define internal void @__dtor_b() [[NUW]]
// CHECK: call void @_ZN1AD1Ev([[A]]* @b)
class A {
@@ -33,14 +33,14 @@ A a, b;
// CHECK-NEXT: call i32 @atexit(void ()* @__dtor__ZZ4funcvE2a2)
// CHECK-NEXT: call void @__cxa_guard_release(i64* @_ZGVZ4funcvE2a2)
-// CHECK: define internal void @__dtor__ZZ4funcvE2a1() #0
+// CHECK: define internal void @__dtor__ZZ4funcvE2a1() [[NUW]]
// CHECK: call void @_ZN1AD1Ev([[A]]* @_ZZ4funcvE2a1)
-// CHECK: define internal void @__dtor__ZZ4funcvE2a2() #0
+// CHECK: define internal void @__dtor__ZZ4funcvE2a2() [[NUW]]
// CHECK: call void @_ZN1AD1Ev([[A]]* @_ZZ4funcvE2a2)
void func() {
static A a1, a2;
}
-// CHECK: attributes #0 = { nounwind }
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenCXX/member-initializers.cpp b/test/CodeGenCXX/member-initializers.cpp
index 69a63b2e44..c22b99d606 100644
--- a/test/CodeGenCXX/member-initializers.cpp
+++ b/test/CodeGenCXX/member-initializers.cpp
@@ -21,7 +21,7 @@ int f() {
}
// Test that we don't try to fold the default value of j when initializing i.
-// CHECK: define i32 @_Z9test_foldv() #0
+// CHECK: define i32 @_Z9test_foldv() [[NUW_RN:#[0-9]+]]
int test_fold() {
struct A {
A(const int j = 1) : i(j) { }
@@ -32,4 +32,4 @@ int test_fold() {
return A(2).i;
}
-// CHECK: attributes #0 = { nounwind readnone{{.*}} }
+// CHECK: attributes [[NUW_RN]] = { nounwind readnone{{.*}} }
diff --git a/test/CodeGenCXX/microsoft-abi-array-cookies.cpp b/test/CodeGenCXX/microsoft-abi-array-cookies.cpp
index c0bbbaf2f8..1ba1f6a5f2 100644
--- a/test/CodeGenCXX/microsoft-abi-array-cookies.cpp
+++ b/test/CodeGenCXX/microsoft-abi-array-cookies.cpp
@@ -5,7 +5,7 @@ struct ClassWithoutDtor {
};
void check_array_no_cookies() {
-// CHECK: define void @"\01?check_array_no_cookies@@YAXXZ"() #0
+// CHECK: define void @"\01?check_array_no_cookies@@YAXXZ"() [[NUW:#[0-9]+]]
// CHECK: call noalias i8* @"\01??_U@YAPAXI@Z"(i32 42)
ClassWithoutDtor *array = new ClassWithoutDtor[42];
@@ -58,4 +58,4 @@ void check_array_cookies_aligned() {
// CHECK: getelementptr inbounds i8* [[ARRAY_AS_CHAR]], i64 -8
}
-// CHECK: attributes #0 = { nounwind{{.*}} }
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/no-exceptions.cpp b/test/CodeGenCXX/no-exceptions.cpp
index ecc5201138..ceb3b8e803 100644
--- a/test/CodeGenCXX/no-exceptions.cpp
+++ b/test/CodeGenCXX/no-exceptions.cpp
@@ -11,4 +11,4 @@ void f() throw (int) {
// CHECK: ret void
}
-// CHECK: attributes [[NUW]] = { nounwind }
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/pod-member-memcpys.cpp b/test/CodeGenCXX/pod-member-memcpys.cpp
index 1e76c08899..534d5d19e9 100644
--- a/test/CodeGenCXX/pod-member-memcpys.cpp
+++ b/test/CodeGenCXX/pod-member-memcpys.cpp
@@ -86,6 +86,12 @@ struct ReferenceMember {
int &d;
};
+struct __attribute__((packed)) PackedMembers {
+ char c;
+ NonPOD np;
+ int w, x, y, z;
+};
+
// COPY-ASSIGNMENT OPERATORS:
// Assignment operators are output in the order they're encountered.
@@ -99,6 +105,7 @@ CALL_AO(ArrayMember)
CALL_AO(VolatileMember)
CALL_AO(BitfieldMember)
CALL_AO(InnerClassMember)
+CALL_AO(PackedMembers)
// Basic copy-assignment:
// CHECK: define linkonce_odr %struct.Basic* @_ZN5BasicaSERKS_(%struct.Basic* %this, %struct.Basic*)
@@ -151,6 +158,12 @@ CALL_AO(InnerClassMember)
// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
// CHECK: ret %struct.InnerClassMember* %this
+// PackedMembers copy-assignment:
+// CHECK: define linkonce_odr %struct.PackedMembers* @_ZN13PackedMembersaSERKS_(%struct.PackedMembers* %this, %struct.PackedMembers*)
+// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 1{{.*}})
+// CHECK: ret %struct.PackedMembers* %this
+
// COPY-CONSTRUCTORS:
// Clang outputs copy-constructors in the reverse of the order that
@@ -159,6 +172,7 @@ CALL_AO(InnerClassMember)
#define CALL_CC(T) T callCC##T(const T& b) { return b; }
+CALL_CC(PackedMembers)
CALL_CC(BitfieldMember2)
CALL_CC(ReferenceMember)
CALL_CC(InnerClassMember)
@@ -234,3 +248,9 @@ CALL_CC(Basic)
// CHECK-2: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4, i1 false)
// CHECK-2: call void @_ZN6NonPODC1ERKS_
// CHECK-2: ret void
+
+// PackedMembers copy-assignment:
+// CHECK: define linkonce_odr void @_ZN13PackedMembersC2ERKS_(%struct.PackedMembers* %this, %struct.PackedMembers*)
+// CHECK: tail call void @_ZN6NonPODC1ERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 1{{.*}})
+// CHECK: ret void
diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp
index 841209e84e..7335c97dd9 100644
--- a/test/CodeGenCXX/pointers-to-data-members.cpp
+++ b/test/CodeGenCXX/pointers-to-data-members.cpp
@@ -151,13 +151,13 @@ struct A {
A() : a() {}
};
-// CHECK-O3: define zeroext i1 @_ZN6PR71395checkEv() [[NUW_RO:#[0-9]+]]
+// CHECK-O3: define zeroext i1 @_ZN6PR71395checkEv() [[NUW:#[0-9]+]]
bool check() {
// CHECK-O3: ret i1 true
return A().a.data == 0;
}
-// CHECK-O3: define zeroext i1 @_ZN6PR71396check2Ev() [[NUW_RO]]
+// CHECK-O3: define zeroext i1 @_ZN6PR71396check2Ev() [[NUW]]
bool check2() {
// CHECK-O3: ret i1 true
return ptr_to_member_type() == 0;
@@ -255,4 +255,4 @@ namespace PR13097 {
// CHECK: call void @_ZN7PR130971XC1ERKS0_
}
-// CHECK-O3: attributes [[NUW_RO]] = { nounwind readnone{{.*}} }
+// CHECK-O3: attributes [[NUW]] = { nounwind readnone{{.*}} }
diff --git a/test/CodeGenCXX/reference-cast.cpp b/test/CodeGenCXX/reference-cast.cpp
index f440cf5a47..f157ae99f9 100644
--- a/test/CodeGenCXX/reference-cast.cpp
+++ b/test/CodeGenCXX/reference-cast.cpp
@@ -193,4 +193,4 @@ namespace PR10650 {
// CHECK: store i64
}
-// CHECK: attributes [[NUW]] = { nounwind }
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/runtimecc.cpp b/test/CodeGenCXX/runtimecc.cpp
new file mode 100644
index 0000000000..66d3f41589
--- /dev/null
+++ b/test/CodeGenCXX/runtimecc.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 %s -triple=armv7-apple-darwin10 -emit-llvm -o - -fexceptions -fcxx-exceptions | FileCheck %s
+
+// Check that we annotate all compiler-synthesized runtime calls and
+// functions with the actual ABI-determined CC. This usually doesn't
+// matter as long as we're internally consistent (and the LLVM-default
+// CC is consistent with the real one), but it's possible for user
+// translation units to define these runtime functions (or, equivalently,
+// for us to get LTO'ed with such a translation unit), and then the
+// mismatch will kill us.
+//
+// rdar://12818655
+
+// CHECK: [[A:%.*]] = type { double }
+
+namespace test0 {
+ struct A {
+ double d;
+ A();
+ ~A();
+ };
+
+ A global;
+// CHECK: define internal arm_aapcscc void @__cxx_global_var_init()
+// CHECK: call arm_aapcscc [[A]]* @_ZN5test01AC1Ev([[A]]* @_ZN5test06globalE)
+// CHECK-NEXT: call arm_aapcscc i32 @__cxa_atexit(void (i8*)* bitcast ([[A]]* ([[A]]*)* @_ZN5test01AD1Ev to void (i8*)*), i8* bitcast ([[A]]* @_ZN5test06globalE to i8*), i8* @__dso_handle) [[NOUNWIND:#[0-9]+]]
+// CHECK-NEXT: ret void
+}
+
+// CHECK: declare arm_aapcscc i32 @__cxa_atexit(void (i8*)*, i8*, i8*) [[NOUNWIND]]
+
+namespace test1 {
+ void test() {
+ throw 0;
+ }
+
+// CHECK: define arm_aapcscc void @_ZN5test14testEv()
+// CHECK: [[T0:%.*]] = call arm_aapcscc i8* @__cxa_allocate_exception(i32 4) [[NOUNWIND]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i32*
+// CHECK-NEXT: store i32 0, i32* [[T1]]
+// CHECK-NEXT: call arm_aapcscc void @__cxa_throw(i8* [[T0]], i8* bitcast (i8** @_ZTIi to i8*), i8* null) [[NORETURN:#[0-9]+]]
+// CHECK-NEXT: unreachable
+}
+
+// CHECK: declare arm_aapcscc i8* @__cxa_allocate_exception(i32)
+
+// CHECK: declare arm_aapcscc void @__cxa_throw(i8*, i8*, i8*)
+
+// CHECK: define internal arm_aapcscc void @_GLOBAL__I_a()
+// CHECK: call arm_aapcscc void @__cxx_global_var_init()
+
+
+// CHECK: attributes [[NOUNWIND]] = { nounwind }
+// CHECK: attributes [[NORETURN]] = { noreturn }
diff --git a/test/CodeGenCXX/threadsafe-statics.cpp b/test/CodeGenCXX/threadsafe-statics.cpp
index 9e6550d094..9aecc2d0db 100644
--- a/test/CodeGenCXX/threadsafe-statics.cpp
+++ b/test/CodeGenCXX/threadsafe-statics.cpp
@@ -22,6 +22,6 @@ void g() {
// NO-TSS-NOT: call void @__cxa_guard_release
// NO-TSS: ret void
-// WITH-TSS: attributes [[NUW]] = { nounwind }
+// WITH-TSS: attributes [[NUW]] = { nounwind{{.*}} }
-// NO-TSS: attributes [[NUW]] = { nounwind }
+// NO-TSS: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/virtual-function-calls.cpp b/test/CodeGenCXX/virtual-function-calls.cpp
index 46e7b2d37f..e1b380fe73 100644
--- a/test/CodeGenCXX/virtual-function-calls.cpp
+++ b/test/CodeGenCXX/virtual-function-calls.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - | FileCheck %s
// PR5021
namespace PR5021 {
@@ -36,3 +36,16 @@ namespace Test1 {
b->f();
}
}
+
+namespace VirtualNoreturn {
+ struct A {
+ [[noreturn]] virtual void f();
+ };
+
+ // CHECK: @_ZN15VirtualNoreturn1f
+ void f(A *p) {
+ p->f();
+ // CHECK: call void %{{[^#]*$}}
+ // CHECK-NOT: unreachable
+ }
+}
diff --git a/test/CodeGenObjC/arc-arm.m b/test/CodeGenObjC/arc-arm.m
index 2ab8cb6ef5..3989f56308 100644
--- a/test/CodeGenObjC/arc-arm.m
+++ b/test/CodeGenObjC/arc-arm.m
@@ -11,9 +11,9 @@ void test1(void) {
extern id test1_helper(void);
// CHECK: [[T0:%.*]] = call arm_aapcscc i8* @test1_helper()
// CHECK-NEXT: call void asm sideeffect "mov\09r7, r7
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: [[T1:%.*]] = call arm_aapcscc i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: store i8* [[T1]],
- // CHECK-NEXT: call void @objc_storeStrong(
+ // CHECK-NEXT: call arm_aapcscc void @objc_storeStrong(
// CHECK-NEXT: ret void
id x = test1_helper();
}
diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m
index c5141a1e59..48f012a42b 100644
--- a/test/CodeGenObjC/arc.m
+++ b/test/CodeGenObjC/arc.m
@@ -1486,3 +1486,4 @@ void test70(id i) {
// ARC-ALIEN: attributes [[NLB]] = { nonlazybind }
// ARC-NATIVE: attributes [[NLB]] = { nonlazybind }
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/debug-info-ivars-extension.m b/test/CodeGenObjC/debug-info-ivars-extension.m
new file mode 100644
index 0000000000..733d146875
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-ivars-extension.m
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -g %s -o - | FileCheck %s
+
+// Make sure we generate debug symbols for ivars added by a class extension.
+
+@interface I
+{
+ @public int a;
+}
+@end
+
+void foo(I* pi) {
+ // poking into pi for primary class ivars.
+ int _a = pi->a;
+}
+
+@interface I()
+{
+ @public int b;
+}
+@end
+
+void gorf (I* pg) {
+ // poking into pg for ivars for class extension
+ int _b = pg->b;
+}
+
+// CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"I", {{.*}}} ; [ DW_TAG_structure_type ]
+// Check for "a".
+// CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"a", metadata !{{[0-9]*}}, i32 7, i64 32, i64 32, i64 0, i32 0, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [a] [line 7, size 32, align 32, offset 0] [from int]
+// Make sure we don't output the same type twice.
+// CHECK-NOT: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"I", {{.*}}} ; [ DW_TAG_structure_type ]
+// Check for "b".
+// CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"b", metadata !{{[0-9]*}}, i32 18, i64 32, i64 32, i64 0, i32 0, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [b] [line 18, size 32, align 32, offset 0] [from int]
diff --git a/test/CodeGenObjC/debug-info-ivars-indirect.m b/test/CodeGenObjC/debug-info-ivars-indirect.m
new file mode 100644
index 0000000000..9f7f940133
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-ivars-indirect.m
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -g %s -o - | FileCheck %s
+
+// Make sure we generate debug symbols for an indirectly referenced
+// extension to an interface.
+
+@interface I
+{
+ @public int a;
+}
+@end
+
+void foo(I* pi) {
+ int _a = pi->a;
+}
+
+// another layer of indirection
+struct S
+{
+ I* i;
+};
+
+@interface I()
+{
+ @public int b;
+}
+@end
+
+void gorf (struct S* s) {
+ int _b = s->i->b;
+}
+
+// CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"b", metadata !{{[0-9]*}}, i32 24, i64 32, i64 32, i64 0, i32 0, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [b] [line 24, size 32, align 32, offset 0] [from int]
diff --git a/test/CodeGenObjC/debug-info-ivars-private.m b/test/CodeGenObjC/debug-info-ivars-private.m
new file mode 100644
index 0000000000..0a555c2a8b
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-ivars-private.m
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -g %s -o - | FileCheck %s
+
+// Debug symbols for private ivars. This test ensures that we are
+// generating debug info for ivars added by the implementation.
+__attribute((objc_root_class)) @interface NSObject {
+ id isa;
+}
+@end
+
+@protocol Protocol
+@end
+
+@interface Delegate : NSObject<Protocol> {
+ @protected int foo;
+}
+@end
+
+@interface Delegate(NSObject)
+- (void)f;
+@end
+
+@implementation Delegate(NSObject)
+- (void)f { return; }
+@end
+
+@implementation Delegate {
+ int bar;
+}
+
+- (void)g:(NSObject*) anObject {
+ bar = foo;
+}
+@end
+
+// CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"foo", metadata !{{[0-9]*}}, i32 14, i64 32, i64 32, i64 0, i32 2, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [foo] [line 14, size 32, align 32, offset 0] [protected] [from int]
+// CHECK: metadata !{i32 {{[0-9]*}}, metadata !{{[0-9]*}}, metadata !"bar", metadata !{{[0-9]*}}, i32 27, i64 32, i64 32, i64 0, i32 1, metadata !{{[0-9]*}}, null} ; [ DW_TAG_member ] [bar] [line 27, size 32, align 32, offset 0] [private] [from int]
diff --git a/test/CodeGenObjC/gnu-exceptions.m b/test/CodeGenObjC/gnu-exceptions.m
index 4a046e2134..7aa9709a87 100644
--- a/test/CodeGenObjC/gnu-exceptions.m
+++ b/test/CodeGenObjC/gnu-exceptions.m
@@ -6,7 +6,7 @@ void log(int i);
@class C;
-// CHECK: define void @test0() {
+// CHECK: define void @test0() [[TF:#[0-9]+]] {
void test0() {
@try {
// CHECK: invoke void @opaque()
@@ -30,3 +30,5 @@ void test0() {
log(1);
}
+
+// CHECK: attributes [[TF]] = { "{{.*}} }
diff --git a/test/CodeGenObjCXX/arc-attrs.mm b/test/CodeGenObjCXX/arc-attrs.mm
new file mode 100644
index 0000000000..57ccb6cdea
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-attrs.mm
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -emit-llvm -fobjc-arc -O0 -o - %s | FileCheck %s
+
+id makeObject1() __attribute__((ns_returns_retained));
+id makeObject2() __attribute__((ns_returns_retained));
+void releaseObject(__attribute__((ns_consumed)) id);
+
+// CHECK: define void @_Z10sanityTestv
+void sanityTest() {
+ // CHECK: [[X:%.*]] = alloca i8*, align 8
+ // CHECK-NEXT: [[OBJ1:%.*]] = call i8* @_Z11makeObject1v()
+ // CHECK-NEXT: store i8* [[OBJ1]], i8** [[X]], align 8
+ id x = makeObject1();
+
+ // CHECK-NEXT: [[OBJ2:%.*]] = call i8* @_Z11makeObject2v()
+ // CHECK-NEXT: call void @_Z13releaseObjectP11objc_object(i8* [[OBJ2]])
+ releaseObject(makeObject2());
+
+ // CHECK-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null)
+ // CHECK-NEXT: ret void
+}
+
+
+template <typename T>
+T makeObjectT1() __attribute__((ns_returns_retained));
+template <typename T>
+T makeObjectT2() __attribute__((ns_returns_retained));
+
+template <typename T>
+void releaseObjectT(__attribute__((ns_consumed)) T);
+
+// CHECK: define void @_Z12templateTestv
+void templateTest() {
+ // CHECK: [[X:%.*]] = alloca i8*, align 8
+ // CHECK-NEXT: [[OBJ1:%.*]] = call i8* @_Z12makeObjectT1IU8__strongP11objc_objectET_v()
+ // CHECK-NEXT: store i8* [[OBJ1]], i8** [[X]], align 8
+ id x = makeObjectT1<id>();
+
+ // CHECK-NEXT: [[OBJ2:%.*]] = call i8* @_Z12makeObjectT2IU8__strongP11objc_objectET_v()
+ // CHECK-NEXT: call void @_Z13releaseObjectP11objc_object(i8* [[OBJ2]])
+ releaseObject(makeObjectT2<id>());
+
+ // CHECK-NEXT: [[OBJ3:%.*]] = call i8* @_Z11makeObject1v()
+ // CHECK-NEXT: call void @_Z14releaseObjectTIU8__strongP11objc_objectEvT_(i8* [[OBJ3]])
+ releaseObjectT(makeObject1());
+
+ // CHECK-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null)
+ // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenObjCXX/message.mm b/test/CodeGenObjCXX/message.mm
new file mode 100644
index 0000000000..1268a79d63
--- /dev/null
+++ b/test/CodeGenObjCXX/message.mm
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-10.7 -emit-llvm -o - %s | FileCheck %s
+
+// Properly instantiate a non-dependent message expression which
+// requires a contextual conversion to ObjC pointer type.
+// <rdar://13305374>
+@interface Test0
+- (void) foo;
+@end
+namespace test0 {
+ struct A {
+ operator Test0*();
+ };
+ template <class T> void foo() {
+ A a;
+ [a foo];
+ }
+ template void foo<int>();
+ // CHECK: define weak_odr void @_ZN5test03fooIiEEvv()
+ // CHECK: [[T0:%.*]] = call [[TEST0:%.*]]* @_ZN5test01AcvP5Test0Ev(
+ // CHECK-NEXT: [[T1:%.*]] = load i8**
+ // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST0]]* [[T0]] to i8*
+ // CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*)*)(i8* [[T2]], i8* [[T1]])
+ // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenObjCXX/unknown-anytype.mm b/test/CodeGenObjCXX/unknown-anytype.mm
new file mode 100644
index 0000000000..0e146d42c9
--- /dev/null
+++ b/test/CodeGenObjCXX/unknown-anytype.mm
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fdebugger-support -funknown-anytype -emit-llvm -o - %s | FileCheck %s
+
+// rdar://13025708
+
+@interface A @end
+void test0(A *a) {
+ (void) [a test0: (float) 2.0];
+}
+// CHECK: define void @_Z5test0P1A(
+// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, float)*)(
+
+@interface B
+- (void) test1: (__unknown_anytype) x;
+@end
+void test1(B *b) {
+ (void) [b test1: (float) 2.0];
+}
+// CHECK: define void @_Z5test1P1B(
+// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, float)*)(
+
diff --git a/test/CodeGenOpenCL/addr-space-struct-arg.cl b/test/CodeGenOpenCL/addr-space-struct-arg.cl
new file mode 100644
index 0000000000..f04923d39c
--- /dev/null
+++ b/test/CodeGenOpenCL/addr-space-struct-arg.cl
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -ffake-address-space-map -triple i686-pc-darwin | FileCheck %s
+
+typedef struct {
+ int cells[9];
+} Mat3X3;
+
+typedef struct {
+ int cells[16];
+} Mat4X4;
+
+Mat4X4 __attribute__((noinline)) foo(Mat3X3 in) {
+ Mat4X4 out;
+ return out;
+}
+
+kernel void ker(global Mat3X3 *in, global Mat4X4 *out) {
+ out[0] = foo(in[1]);
+}
+
+// Expect two mem copies: one for the argument "in", and one for
+// the return value.
+// CHECK: call void @llvm.memcpy.p0i8.p1i8.i32(i8*
+// CHECK: call void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)*
diff --git a/test/CodeGenOpenCL/kernel-attributes.cl b/test/CodeGenOpenCL/kernel-attributes.cl
index de16a41453..1166f9384f 100644
--- a/test/CodeGenOpenCL/kernel-attributes.cl
+++ b/test/CodeGenOpenCL/kernel-attributes.cl
@@ -1,12 +1,16 @@
// RUN: %clang_cc1 -emit-llvm -O0 -o - %s | FileCheck %s
-kernel __attribute__((reqd_work_group_size(1,2,4))) void kernel1(int a) {}
+typedef unsigned int uint4 __attribute__((ext_vector_type(4)));
-kernel __attribute__((work_group_size_hint(8,16,32))) void kernel2(int a) {}
+kernel __attribute__((vec_type_hint(int))) __attribute__((reqd_work_group_size(1,2,4))) void kernel1(int a) {}
+
+kernel __attribute__((vec_type_hint(uint4))) __attribute__((work_group_size_hint(8,16,32))) void kernel2(int a) {}
// CHECK: opencl.kernels = !{[[MDNODE0:![0-9]+]], [[MDNODE3:![0-9]+]]}
-// CHECK: [[MDNODE0]] = metadata !{void (i32)* @kernel1, metadata [[MDNODE2:![0-9]+]]}
+// CHECK: [[MDNODE0]] = metadata !{void (i32)* @kernel1, metadata [[MDNODE1:![0-9]+]], metadata [[MDNODE2:![0-9]+]]}
+// CHECK: [[MDNODE1]] = metadata !{metadata !"vec_type_hint", i32 undef, i32 1}
// CHECK: [[MDNODE2]] = metadata !{metadata !"reqd_work_group_size", i32 1, i32 2, i32 4}
-// CHECK: [[MDNODE3]] = metadata !{void (i32)* @kernel2, metadata [[MDNODE5:![0-9]+]]}
+// CHECK: [[MDNODE3]] = metadata !{void (i32)* @kernel2, metadata [[MDNODE4:![0-9]+]], metadata [[MDNODE5:![0-9]+]]}
+// CHECK: [[MDNODE4]] = metadata !{metadata !"vec_type_hint", <4 x i32> undef, i32 0}
// CHECK: [[MDNODE5]] = metadata !{metadata !"work_group_size_hint", i32 8, i32 16, i32 32}
diff --git a/test/Coverage/objc-language-features.inc b/test/Coverage/objc-language-features.inc
index dbbf205fcd..29d8298c82 100644
--- a/test/Coverage/objc-language-features.inc
+++ b/test/Coverage/objc-language-features.inc
@@ -9,6 +9,7 @@
@class B;
@interface Root
+@property(readonly) int p0;
@end
@interface A : Root <P1> {
diff --git a/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbeginT.o b/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbeginT.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbeginT.o
diff --git a/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/lib/x86_64-linux-gnu/.keep b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/lib/x86_64-linux-gnu/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/lib/x86_64-linux-gnu/.keep
diff --git a/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/c++/4.7/backward/.keep b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/c++/4.7/backward/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/c++/4.7/backward/.keep
diff --git a/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/.keep b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/.keep
diff --git a/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/32/.keep b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/32/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/32/.keep
diff --git a/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/.keep b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/.keep
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/.keep
diff --git a/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/crtbegin.o b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/crtbegin.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/crtbegin.o
diff --git a/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o
diff --git a/test/Driver/arm-cortex-cpus.c b/test/Driver/arm-cortex-cpus.c
new file mode 100644
index 0000000000..6fa649aa39
--- /dev/null
+++ b/test/Driver/arm-cortex-cpus.c
@@ -0,0 +1,8 @@
+// RUN: %clang -target armv6m-apple-darwin -arch armv6m -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V6M %s
+// CHECK-V6M: "-cc1"{{.*}} "-triple" "thumbv6m-{{.*}} "-target-cpu" "cortex-m0"
+
+// RUN: %clang -target armv7m-apple-darwin -arch armv7m -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V7M %s
+// CHECK-V7M: "-cc1"{{.*}} "-triple" "thumbv7m-{{.*}} "-target-cpu" "cortex-m3"
+
+// RUN: %clang -target armv7em-apple-darwin -arch armv7em -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V7EM %s
+// CHECK-V7EM: "-cc1"{{.*}} "-triple" "thumbv7em-{{.*}} "-target-cpu" "cortex-m4"
diff --git a/test/Driver/claim-unused.c b/test/Driver/claim-unused.c
new file mode 100644
index 0000000000..c7b798934b
--- /dev/null
+++ b/test/Driver/claim-unused.c
@@ -0,0 +1,3 @@
+// RUN: touch %t.o
+// RUN: %clang --param ssp-buffer-size=1 %t.o -### 2>&1 | FileCheck %s
+// CHECK-NOT: warning: argument unused during compilation: '--param ssp-buffer-size=1'
diff --git a/test/Driver/darwin-iphone-defaults.m b/test/Driver/darwin-iphone-defaults.m
index 4f24d175e0..3e2a9125db 100644
--- a/test/Driver/darwin-iphone-defaults.m
+++ b/test/Driver/darwin-iphone-defaults.m
@@ -1,6 +1,6 @@
// RUN: %clang -target i386-apple-darwin9 -miphoneos-version-min=3.0 -arch armv7 -flto -S -o - %s | FileCheck %s
-// CHECK: @f0() #0
+// CHECK: @f0() [[F0:#[0-9]+]]
// CHECK: @__f0_block_invoke
// CHECK: void @f1
// CHECK-NOT: msgSend_fixup_alloc
@@ -26,5 +26,4 @@ void f1() {
[I1 alloc];
}
-// CHECK: attributes #0 = { ssp{{.*}} }
-// CHECK: attributes #1 = { nonlazybind }
+// CHECK: attributes [[F0]] = { ssp{{.*}} }
diff --git a/test/Driver/hexagon-toolchain.c b/test/Driver/hexagon-toolchain.c
index 53c034d888..bfa627c421 100644
--- a/test/Driver/hexagon-toolchain.c
+++ b/test/Driver/hexagon-toolchain.c
@@ -108,6 +108,22 @@
// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v4"
// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv4"
+// RUN: %clang -march=hexagonv2 -target hexagon-unknown-linux \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
+// RUN: %clang -mcpu=hexagonv2 -target hexagon-unknown-linux \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
+// RUN: %clang -mv2 -target hexagon-unknown-linux \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
+// CHECK-UNKNOWN-V2: error: unknown target CPU 'hexagonv2'
+
+// RUN: %clang -march=hexagonv3 -target hexagon-unknown-linux \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
+// RUN: %clang -mcpu=hexagonv3 -target hexagon-unknown-linux \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
+// RUN: %clang -mv3 -target hexagon-unknown-linux \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
+// CHECK-UNKNOWN-V3: error: unknown target CPU 'hexagonv3'
+
// -----------------------------------------------------------------------------
// Test Linker related args
// -----------------------------------------------------------------------------
diff --git a/test/Driver/linux-header-search.cpp b/test/Driver/linux-header-search.cpp
index 065bd34566..d09f5b27ae 100644
--- a/test/Driver/linux-header-search.cpp
+++ b/test/Driver/linux-header-search.cpp
@@ -16,6 +16,34 @@
// CHECK-UBUNTU-11-04: "-internal-externc-isystem" "[[SYSROOT]]/include"
// CHECK-UBUNTU-11-04: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target x86_64-unknown-linux-gnu \
+// RUN: --sysroot=%S/Inputs/ubuntu_13.04_multiarch_tree \
+// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-13-04 %s
+// CHECK-UBUNTU-13-04: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
+// CHECK-UBUNTU-13-04: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-UBUNTU-13-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7"
+// CHECK-UBUNTU-13-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/backward"
+// CHECK-UBUNTU-13-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/x86_64-linux-gnu/c++/4.7"
+// CHECK-UBUNTU-13-04: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
+// CHECK-UBUNTU-13-04: "-internal-isystem" "{{.*}}/lib{{(64|32)?}}/clang/{{[0-9]\.[0-9]}}/include"
+// CHECK-UBUNTU-13-04: "-internal-externc-isystem" "[[SYSROOT]]/usr/include/x86_64-linux-gnu"
+// CHECK-UBUNTU-13-04: "-internal-externc-isystem" "[[SYSROOT]]/include"
+// CHECK-UBUNTU-13-04: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
+//
+// Test Ubuntu/Debian's new version of multiarch, with -m32.
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target x86_64-unknown-linux-gnu -m32 \
+// RUN: --sysroot=%S/Inputs/ubuntu_13.04_multiarch_tree \
+// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-13-04-M32 %s
+// CHECK-UBUNTU-13-04-M32: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
+// CHECK-UBUNTU-13-04-M32: "-triple" "i386-unknown-linux-gnu"
+// CHECK-UBUNTU-13-04-M32: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-UBUNTU-13-04-M32: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7"
+// CHECK-UBUNTU-13-04-M32: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/x86_64-linux-gnu/32"
+// CHECK-UBUNTU-13-04-M32: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/backward"
+// CHECK-UBUNTU-13-04-M32: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/x86_64-linux-gnu/c++/4.7/32"
+//
// Thoroughly exercise the Debian multiarch environment.
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target i686-linux-gnu \
diff --git a/test/Driver/linux-ld.c b/test/Driver/linux-ld.c
index 06be358860..79282cbf41 100644
--- a/test/Driver/linux-ld.c
+++ b/test/Driver/linux-ld.c
@@ -5,6 +5,7 @@
// RUN: -target i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-32 %s
+// CHECK-LD-32-NOT: warning:
// CHECK-LD-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
// CHECK-LD-32: "{{.*}}/usr/lib/gcc/i386-unknown-linux/4.6.0/crtbegin.o"
// CHECK-LD-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0"
@@ -17,13 +18,66 @@
// RUN: -target x86_64-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-64 %s
+// CHECK-LD-64-NOT: warning:
// CHECK-LD-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-LD-64: "--eh-frame-hdr"
+// CHECK-LD-64: "-m" "elf_x86_64"
+// CHECK-LD-64: "-dynamic-linker"
// CHECK-LD-64: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o"
// CHECK-LD-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
// CHECK-LD-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib"
// CHECK-LD-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../.."
// CHECK-LD-64: "-L[[SYSROOT]]/lib"
// CHECK-LD-64: "-L[[SYSROOT]]/usr/lib"
+// CHECK-LD-64: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+// CHECK-LD-64: "-lc"
+// CHECK-LD-64: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-unknown-linux \
+// RUN: -static-libgcc \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LD-64-STATIC-LIBGCC %s
+// CHECK-LD-64-STATIC-LIBGCC-NOT: warning:
+// CHECK-LD-64-STATIC-LIBGCC: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-LD-64-STATIC-LIBGCC: "--eh-frame-hdr"
+// CHECK-LD-64-STATIC-LIBGCC: "-m" "elf_x86_64"
+// CHECK-LD-64-STATIC-LIBGCC: "-dynamic-linker"
+// CHECK-LD-64-STATIC-LIBGCC: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o"
+// CHECK-LD-64-STATIC-LIBGCC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
+// CHECK-LD-64-STATIC-LIBGCC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib"
+// CHECK-LD-64-STATIC-LIBGCC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../.."
+// CHECK-LD-64-STATIC-LIBGCC: "-L[[SYSROOT]]/lib"
+// CHECK-LD-64-STATIC-LIBGCC: "-L[[SYSROOT]]/usr/lib"
+// CHECK-LD-64-STATIC-LIBGCC: "-lgcc" "-lgcc_eh"
+// CHECK-LD-64-STATIC-LIBGCC: "-lc"
+// CHECK-LD-64-STATIC-LIBGCC: "-lgcc" "-lgcc_eh"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-unknown-linux \
+// RUN: -static \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LD-64-STATIC %s
+// CHECK-LD-64-STATIC-NOT: warning:
+// CHECK-LD-64-STATIC: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-LD-64-STATIC-NOT: "--eh-frame-hdr"
+// CHECK-LD-64-STATIC: "-m" "elf_x86_64"
+// CHECK-LD-64-STATIC-NOT: "-dynamic-linker"
+// CHECK-LD-64-STATIC: "-static"
+// CHECK-LD-64-STATIC: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbeginT.o"
+// CHECK-LD-64-STATIC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
+// CHECK-LD-64-STATIC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib"
+// CHECK-LD-64-STATIC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../.."
+// CHECK-LD-64-STATIC: "-L[[SYSROOT]]/lib"
+// CHECK-LD-64-STATIC: "-L[[SYSROOT]]/usr/lib"
+// CHECK-LD-64-STATIC: "--start-group" "-lgcc" "-lgcc_eh" "-lc" "--end-group"
+//
+// Check that flags can be combined. The -static dominates.
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-unknown-linux \
+// RUN: -static-libgcc -static \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LD-64-STATIC %s
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target i386-unknown-linux -m32 \
diff --git a/test/Driver/modules_integrated_as.c b/test/Driver/modules_integrated_as.c
new file mode 100644
index 0000000000..037cdd0c3c
--- /dev/null
+++ b/test/Driver/modules_integrated_as.c
@@ -0,0 +1,4 @@
+// RUN: %clang -fmodules -no-integrated-as -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: error: modules can only be used with the compiler's integrated assembler
+// CHECK note: '-no-integrated-as' cannot be used with '-fmodules'
diff --git a/test/Driver/objc_default_synth.m b/test/Driver/objc_default_synth.m
new file mode 100644
index 0000000000..a8c7f7e546
--- /dev/null
+++ b/test/Driver/objc_default_synth.m
@@ -0,0 +1,6 @@
+// We should be synthesizing properties by default on all platforms now.
+// RUN: %clang -### -target armv7-unknown-freebsd %s 2>&1 | FileCheck %s
+// RUN: %clang -### -target armv7-apple-ios %s 2>&1 | FileCheck %s
+// RUN: %clang -### -target i686-apple-macosx %s 2>&1 | FileCheck %s
+// REQUIRES: clang-driver
+// CHECK: -fobjc-default-synthesize
diff --git a/test/FixIt/fixit-objc.m b/test/FixIt/fixit-objc.m
index 77099fccc9..ea57fe671b 100644
--- a/test/FixIt/fixit-objc.m
+++ b/test/FixIt/fixit-objc.m
@@ -11,7 +11,7 @@
@protocol X;
void foo() {
- <X> *P; // expected-warning{{protocol qualifiers without 'id' is archaic}}
+ <X> *P; // expected-warning{{protocol has no object type specified; defaults to qualified 'id'}}
}
@class A;
diff --git a/test/Index/complete-documentation-properties.m b/test/Index/complete-documentation-properties.m
new file mode 100644
index 0000000000..d423f84d22
--- /dev/null
+++ b/test/Index/complete-documentation-properties.m
@@ -0,0 +1,68 @@
+// Note: the run lines follow their respective tests, since line/column numbers
+// matter in this test.
+// This test is for when property accessors do not have their own code
+// completion comments. Use those in their properties in this case.
+// rdar://12791315
+
+@interface AppDelegate
+/**
+ \brief This is ReadonlyProperty
+*/
+@property (readonly, getter = ReadonlyGetter) id MyProperty;
+
+/**
+ \brief This is GeneralProperty
+*/
+@property int GeneralProperty;
+
+/**
+ \brief This is PropertyInPrimaryClass
+*/
+@property (copy, nonatomic) id PropertyInPrimaryClass;
+
+- (void) setThisRecord : (id)arg;
+- (id) Record;
+@end
+
+
+@interface AppDelegate()
+- (id) GetterInClassExtension;
+/**
+ \brief This is Record
+*/
+@property (copy, setter = setThisRecord:) id Record;
+@end
+
+@interface AppDelegate()
+/**
+ \brief This is PropertyInClassExtension
+*/
+@property (copy, getter = GetterInClassExtension) id PropertyInClassExtension;
+
+- (id) PropertyInPrimaryClass;
+@end
+
+@implementation AppDelegate
+- (id) PropertyInPrimaryClass {
+ id p = [self ReadonlyGetter];
+ p = [self GetterInClassExtension];
+ p = [self PropertyInPrimaryClass];
+ p = [self Record];
+ [self setThisRecord : (id)0 ];
+ return 0;
+}
+@end
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:47:16 %s | FileCheck -check-prefix=CC1 %s
+// CHECK-CC1: {TypedText ReadonlyGetter}{{.*}}(brief comment: This is ReadonlyProperty)
+
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:48:13 %s | FileCheck -check-prefix=CC2 %s
+// CHECK-CC2: {TypedText GetterInClassExtension}{{.*}}(brief comment: This is PropertyInClassExtension)
+
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:49:13 %s | FileCheck -check-prefix=CC3 %s
+// CHECK-CC3: {TypedText PropertyInPrimaryClass}{{.*}}(brief comment: This is PropertyInPrimaryClass)
+
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:50:13 %s | FileCheck -check-prefix=CC4 %s
+// CHECK-CC4: {TypedText Record}{{.*}}(brief comment: This is Record)
+
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:51:9 %s | FileCheck -check-prefix=CC5 %s
+// CHECK-CC5: {TypedText setThisRecord:}{Placeholder (id)}{{.*}}(brief comment: This is Record)
diff --git a/test/Index/complete-modules.m b/test/Index/complete-modules.m
index d1cf12728a..d63c4b8956 100644
--- a/test/Index/complete-modules.m
+++ b/test/Index/complete-modules.m
@@ -12,3 +12,6 @@
// RUN: c-index-test -code-completion-at=%s:4:14 -fmodules-cache-path=%t -fmodules -F %S/Inputs/Frameworks -I %S/Inputs/Headers %s | FileCheck -check-prefix=CHECK-LIBA %s
// CHECK-LIBA: NotImplemented:{TypedText Extensions} (50)
+// RUN: c-index-test -code-completion-at=%s:4:1 -fmodules-cache-path=%t -fmodules -F %S/Inputs/Frameworks -I %S/Inputs/Headers %s | FileCheck -check-prefix=CHECK-TOP %s
+// CHECK-TOP: NotImplemented:{TypedText @import}{HorizontalSpace }{Placeholder module} (40)
+
diff --git a/test/Index/file-includes.c b/test/Index/file-includes.c
new file mode 100644
index 0000000000..2dfced0c0c
--- /dev/null
+++ b/test/Index/file-includes.c
@@ -0,0 +1,24 @@
+
+#include "targeted-top.h"
+#include "targeted-preamble.h"
+
+extern int LocalVar;
+int LocalVar;
+
+// RUN: c-index-test -write-pch %t.h.pch %S/targeted-top.h -Xclang -detailed-preprocessing-record
+
+// RUN: c-index-test -file-includes-in=%s %s | FileCheck %s -check-prefix=LOCAL
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -file-includes-in=%s %s | FileCheck %s -check-prefix=LOCAL
+// RUN: c-index-test -file-includes-in=%s %s -include %t.h | FileCheck %s -check-prefix=LOCAL
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -file-includes-in=%s %s -include %t.h | FileCheck %s -check-prefix=LOCAL
+
+// LOCAL: inclusion directive=targeted-top.h ({{.*[/\\]}}test{{[/\\]}}Index{{[/\\]}}targeted-top.h) {{.*}}=[2:1 - 2:2]
+// LOCAL: inclusion directive=targeted-preamble.h ({{.*[/\\]}}test{{[/\\]}}Index{{[/\\]}}targeted-preamble.h) =[3:1 - 3:2]
+
+// RUN: c-index-test -file-includes-in=%S/targeted-top.h %s | FileCheck %s -check-prefix=TOP
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -file-includes-in=%S/targeted-top.h %s | FileCheck %s -check-prefix=TOP
+// RUN: c-index-test -file-includes-in=%S/targeted-top.h %s -include %t.h | FileCheck %s -check-prefix=TOP
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -file-includes-in=%S/targeted-top.h %s -include %t.h | FileCheck %s -check-prefix=TOP
+
+// TOP: inclusion directive=targeted-nested1.h ({{.*[/\\]}}test{{[/\\]}}Index{{[/\\]}}targeted-nested1.h) =[5:1 - 5:2]
+// TOP: inclusion directive=targeted-fields.h ({{.*[/\\]}}test{{[/\\]}}Index{{[/\\]}}targeted-fields.h) =[16:1 - 16:2]
diff --git a/test/Lexer/builtin_redef.c b/test/Lexer/builtin_redef.c
new file mode 100644
index 0000000000..c9351dc4a6
--- /dev/null
+++ b/test/Lexer/builtin_redef.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -E 2>&1 | FileCheck %s --check-prefix=CHECK-OUT
+// RUN: %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -E 2>&1 | FileCheck %s --check-prefix=CHECK-WARN
+// RUN: %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -E 2>&1 -pedantic-errors | FileCheck %s --check-prefix=CHECK-ERR
+
+// CHECK-WARN: <command line>:{{.*}} warning: redefining builtin macro
+// CHECK-WARN: <command line>:{{.*}} warning: undefining builtin macro
+
+// CHECK-ERR: <command line>:{{.*}} error: redefining builtin macro
+// CHECK-ERR: <command line>:{{.*}} error: undefining builtin macro
+
+int n = __TIME__;
+__DATE__
+
+#define __FILE__ "my file"
+// CHECK-WARN: :[[@LINE-1]]:9: warning: redefining builtin macro
+// CHECK-ERR: :[[@LINE-2]]:9: error: redefining builtin macro
+
+// CHECK-OUT: int n = 1234;
+// CHECK-OUT: __DATE__
diff --git a/test/Lexer/char-literal.cpp b/test/Lexer/char-literal.cpp
index 8556d468cb..b2fab34e44 100644
--- a/test/Lexer/char-literal.cpp
+++ b/test/Lexer/char-literal.cpp
@@ -1,4 +1,11 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -Wfour-char-constants -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c11 -x c -Wfour-char-constants -fsyntax-only -verify %s
+
+#ifndef __cplusplus
+typedef __WCHAR_TYPE__ wchar_t;
+typedef __CHAR16_TYPE__ char16_t;
+typedef __CHAR32_TYPE__ char32_t;
+#endif
int a = 'ab'; // expected-warning {{multi-character character constant}}
int b = '\xFF\xFF'; // expected-warning {{multi-character character constant}}
@@ -7,7 +14,9 @@ int c = 'APPS'; // expected-warning {{multi-character character constant}}
char d = '⌘'; // expected-error {{character too large for enclosing character literal type}}
char e = '\u2318'; // expected-error {{character too large for enclosing character literal type}}
+#ifdef __cplusplus
auto f = '\xE2\x8C\x98'; // expected-warning {{multi-character character constant}}
+#endif
char16_t g = u'ab'; // expected-error {{Unicode character literals may not contain multiple characters}}
char16_t h = u'\U0010FFFD'; // expected-error {{character too large for enclosing character literal type}}
@@ -24,4 +33,11 @@ char32_t n = U'ab'; // expected-error {{Unicode character literals may not conta
char16_t o = '👽'; // expected-error {{character too large for enclosing character literal type}}
char16_t p[2] = u"\U0000FFFF";
-char16_t q[2] = u"\U00010000"; // expected-error {{too long}}
+char16_t q[2] = u"\U00010000";
+#ifdef __cplusplus
+// expected-error@-2 {{too long}}
+#else
+// FIXME: The above should be accepted in C11 mode.
+// expected-error@-6 {{must be an initializer list}}
+// expected-error@-6 {{must be an initializer list}}
+#endif
diff --git a/test/Lexer/pragma-operators.cpp b/test/Lexer/pragma-operators.cpp
index a76e0b2f97..6a5a498a15 100644
--- a/test/Lexer/pragma-operators.cpp
+++ b/test/Lexer/pragma-operators.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fms-extensions -E %s | FileCheck %s
+// RUN: %clang_cc1 -fms-extensions -std=c++11 -E %s | FileCheck %s
// Test that we properly expand the C99 _Pragma and Microsoft __pragma
// into #pragma directives, with newlines where needed. <rdar://problem/8412013>
@@ -17,3 +17,21 @@
#pragma warning(push)
B(foo)
#pragma warning(pop)
+
+#define pragma_L _Pragma(L"GCC diagnostic push")
+#define pragma_u8 _Pragma(u8"system_header")
+#define pragma_u _Pragma(u"GCC diagnostic pop")
+#define pragma_U _Pragma(U"comment(lib, \"libfoo\")")
+#define pragma_R _Pragma(R"(clang diagnostic ignored "-Wunused")")
+#define pragma_UR _Pragma(UR"(clang diagnostic error "-Wunused")")
+#define pragma_hello _Pragma(u8R"x(message R"y("Hello", world!)y")x")
+// CHECK: int n =
+// CHECK: #pragma GCC diagnostic push
+// CHECK: #pragma system_header
+// CHECK: #pragma GCC diagnostic pop
+// CHECK: #pragma comment(lib, "libfoo")
+// CHECK: #pragma clang diagnostic ignored "-Wunused"
+// CHECK: #pragma clang diagnostic error "-Wunused"
+// CHECK: #pragma message("\042Hello\042, world!")
+// CHECK: 0;
+int n = pragma_L pragma_u8 pragma_u pragma_U pragma_R pragma_UR pragma_hello 0;
diff --git a/test/Lexer/string_concat.cpp b/test/Lexer/string_concat.cpp
index 7e78a63e2f..a7eb396fe9 100644
--- a/test/Lexer/string_concat.cpp
+++ b/test/Lexer/string_concat.cpp
@@ -1,33 +1,48 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c11 -x c -fsyntax-only -verify %s
+
+#ifndef __cplusplus
+typedef __WCHAR_TYPE__ wchar_t;
+typedef __CHAR16_TYPE__ char16_t;
+typedef __CHAR32_TYPE__ char32_t;
+#endif
void f() {
const char* a = u8"abc" u"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char* b = u8"abc" U"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char* c = u8"abc" L"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#ifdef __cplusplus
const char* d = u8"abc" uR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char* e = u8"abc" UR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char* f = u8"abc" LR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#endif
const char16_t* g = u"abc" u8"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char16_t* h = u"abc" U"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char16_t* i = u"abc" L"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#ifdef __cplusplus
const char16_t* j = u"abc" u8R"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char16_t* k = u"abc" UR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char16_t* l = u"abc" LR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#endif
const char32_t* m = U"abc" u8"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char32_t* n = U"abc" u"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char32_t* o = U"abc" L"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#ifdef __cplusplus
const char32_t* p = U"abc" u8R"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char32_t* q = U"abc" uR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char32_t* r = U"abc" LR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#endif
const wchar_t* s = L"abc" u8"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const wchar_t* t = L"abc" u"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const wchar_t* u = L"abc" U"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#ifdef __cplusplus
const wchar_t* v = L"abc" u8R"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const wchar_t* w = L"abc" uR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const wchar_t* x = L"abc" UR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#endif
}
diff --git a/test/Lexer/unicode-strings.c b/test/Lexer/unicode-strings.c
new file mode 100644
index 0000000000..3ed1f76829
--- /dev/null
+++ b/test/Lexer/unicode-strings.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -x c -std=c11 -Werror %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -Werror %s
+// RUN: %clang_cc1 -x c -std=c11 -Wc99-compat -verify %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -Wc++98-compat -verify %s
+
+#ifndef __cplusplus
+typedef __CHAR16_TYPE__ char16_t;
+typedef __CHAR32_TYPE__ char32_t;
+#else
+// expected-warning@17 {{'char16_t' type specifier is incompatible with C++98}}
+// expected-warning@18 {{'char32_t' type specifier is incompatible with C++98}}
+// expected-warning@20 {{'char16_t' type specifier is incompatible with C++98}}
+// expected-warning@21 {{'char32_t' type specifier is incompatible with C++98}}
+#endif
+
+const char *a = u8"abcd"; // expected-warning {{unicode literals are incompatible with}}
+const char16_t *b = u"abcd"; // expected-warning {{unicode literals are incompatible with}}
+const char32_t *c = U"abcd"; // expected-warning {{unicode literals are incompatible with}}
+
+char16_t d = u'a'; // expected-warning {{unicode literals are incompatible with}}
+char32_t e = U'a'; // expected-warning {{unicode literals are incompatible with}}
diff --git a/test/Lexer/utf8-char-literal.cpp b/test/Lexer/utf8-char-literal.cpp
index 12b001e4b4..7a4d126097 100644
--- a/test/Lexer/utf8-char-literal.cpp
+++ b/test/Lexer/utf8-char-literal.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c11 -x c -fsyntax-only -verify %s
int array0[u'ñ' == u'\xf1'? 1 : -1];
int array1['\xF1' != u'\xf1'? 1 : -1];
diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
index 265e178fa7..931de8365b 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 (145):
+CHECK: Warnings without flags (144):
CHECK-NEXT: ext_delete_void_ptr_operand
CHECK-NEXT: ext_enum_friend
CHECK-NEXT: ext_expected_semi_decl_list
@@ -44,7 +44,6 @@ CHECK-NEXT: pp_out_of_date_dependency
CHECK-NEXT: pp_poisoning_existing_macro
CHECK-NEXT: pp_pragma_once_in_main_file
CHECK-NEXT: pp_pragma_sysheader_in_main_file
-CHECK-NEXT: pp_undef_builtin_macro
CHECK-NEXT: w_asm_qualifier_ignored
CHECK-NEXT: warn_accessor_property_type_mismatch
CHECK-NEXT: warn_anon_bitfield_width_exceeds_type_size
diff --git a/test/PCH/modified-header-error.c b/test/PCH/modified-header-error.c
index ef9249447a..4ad3fafff4 100644
--- a/test/PCH/modified-header-error.c
+++ b/test/PCH/modified-header-error.c
@@ -8,5 +8,5 @@
#include "header2.h"
-// CHECK: fatal error: file {{.*}} has been modified since the precompiled header was built
+// CHECK: fatal error: file {{.*}} has been modified since the precompiled header {{.*}} was built
// REQUIRES: shell
diff --git a/test/Parser/cxx-casting.cpp b/test/Parser/cxx-casting.cpp
index 01980d3341..69680e421b 100644
--- a/test/Parser/cxx-casting.cpp
+++ b/test/Parser/cxx-casting.cpp
@@ -58,9 +58,9 @@ void test2(char x, struct B * b) {
expected-error {{expected ']'}}
#define LC <:
#define C :
- test1::A LC:B> c; // expected-error {{class template test1::A requires template arguments}} expected-error 2{{}}
+ test1::A LC:B> c; // expected-error {{class template 'test1::A' requires template arguments}} expected-error 2{{}}
(void)static_cast LC:c>(&x); // expected-error {{expected '<' after 'static_cast'}} expected-error 2{{}} expected-note{{}}
- test1::A<:C B> d; // expected-error {{class template test1::A requires template arguments}} expected-error 2{{}}
+ test1::A<:C B> d; // expected-error {{class template 'test1::A' requires template arguments}} expected-error 2{{}}
(void)static_cast<:C c>(&x); // expected-error {{expected '<' after 'static_cast'}} expected-error 2{{}} expected-note{{}}
#define LCC <::
@@ -85,7 +85,7 @@ void test3() {
E< ::F>();
// Make sure that parser doesn't expand '[:' to '< ::'
- ::D[:F> A5; // expected-error {{class template ::D requires template arguments}} \
+ ::D[:F> A5; // expected-error {{class template '::D' requires template arguments}} \
// expected-error {{expected expression}} \
// expected-error {{expected unqualified-id}}
}
diff --git a/test/Parser/placeholder-recovery.m b/test/Parser/placeholder-recovery.m
index 1fc154955d..3fe1d62c30 100644
--- a/test/Parser/placeholder-recovery.m
+++ b/test/Parser/placeholder-recovery.m
@@ -5,7 +5,7 @@
// bogus 'archaic' warnings with bad location info.
@protocol <#protocol name#> <NSObject> // expected-error 2{{expected identifier}} \
// expected-error{{cannot find protocol declaration for 'NSObject'}} \
-// expected-warning{{protocol qualifiers without 'id'}}
+// expected-warning{{protocol has no object type specified; defaults to qualified 'id'}}
<#methods#> // expected-error{{expected identifier}}
diff --git a/test/Preprocessor/c90.c b/test/Preprocessor/c90.c
index 1d5010d75e..3b9105fe6e 100644
--- a/test/Preprocessor/c90.c
+++ b/test/Preprocessor/c90.c
@@ -1,4 +1,5 @@
/* RUN: %clang_cc1 %s -std=c89 -Eonly -verify -pedantic-errors
+ * RUN: %clang_cc1 %s -std=c89 -E | FileCheck %s
*/
/* PR3919 */
@@ -8,3 +9,7 @@
#define foo3$bar /* expected-error {{'$' in identifier}} */
+/* CHECK-NOT: this comment should be missing
+ * CHECK: {{^}}// this comment should be present{{$}}
+ */
+// this comment should be present
diff --git a/test/Preprocessor/traditional-cpp.c b/test/Preprocessor/traditional-cpp.c
index 5a94c00c96..4c4633e039 100644
--- a/test/Preprocessor/traditional-cpp.c
+++ b/test/Preprocessor/traditional-cpp.c
@@ -5,8 +5,14 @@
/*
RUN: %clang_cc1 -traditional-cpp %s -E -o %t
RUN: FileCheck -strict-whitespace < %t %s
+ RUN: %clang_cc1 -traditional-cpp %s -E -C | FileCheck -check-prefix=CHECK-COMMENTS %s
*/
+/* -traditional-cpp should eliminate all C89 comments. */
+/* CHECK-NOT: /*
+ * CHECK-COMMENTS: {{^}}/* -traditional-cpp should eliminate all C89 comments. *{{/$}}
+ */
+
/* CHECK: {{^}}foo // bar{{$}}
*/
foo // bar
@@ -78,3 +84,7 @@ a b c in skipped block
/* CHECK-NOT: {{^}}a b c in skipped block{{$}}
* CHECK-NOT: {{^}}/* Comments are whitespace too
*/
+
+Preserve URLs: http://clang.llvm.org
+/* CHECK: {{^}}Preserve URLs: http://clang.llvm.org{{$}}
+ */
diff --git a/test/Sema/warn-documentation.cpp b/test/Sema/warn-documentation.cpp
index e2e49e59bf..0132ef280c 100644
--- a/test/Sema/warn-documentation.cpp
+++ b/test/Sema/warn-documentation.cpp
@@ -303,6 +303,11 @@ typedef int (*test_param27)(int aaa);
/// \param aaa Meow.
typedef test_param27 test_param28;
+// rdar://13066276
+// expected-warning@+1 {{'@param' command used in a comment that is not attached to a function declaration}}
+/// @param aaa Meow.
+typedef unsigned int test_param29;
+
// expected-warning@+1 {{'\tparam' command used in a comment that is not attached to a template declaration}}
/// \tparam T Aaa
@@ -400,6 +405,12 @@ class test_tparam19 { };
// ----
+// expected-warning@+1 {{'@tparam' command used in a comment that is not attached to a template declaration}}
+/// @tparam T Aaa
+int test_tparam22;
+
+// ----
+
/// Aaa
/// \deprecated Bbb
@@ -438,6 +449,14 @@ template<typename T>
void test_deprecated_7(T aaa);
+// rdar://12397511
+// expected-note@+2 {{previous command '\headerfile' here}}
+// expected-warning@+2 {{duplicated command '\headerfile'}}
+/// \headerfile ""
+/// \headerfile foo.h
+int test__headerfile_1(int a);
+
+
/// \invariant aaa
void test_invariant_1(int a);
@@ -524,6 +543,23 @@ enum test_returns_wrong_decl_8 {
/// \returns Aaa
namespace test_returns_wrong_decl_10 { };
+// rdar://13066276
+// expected-warning@+1 {{'@returns' command used in a comment that is not attached to a function or method declaration}}
+/// @returns Aaa
+typedef unsigned int test_returns_wrong_decl_11;
+
+// rdar://13094352
+// expected-warning@+1 {{'@function' command should be used in a comment attached to a function declaration}}
+/*! @function test_function
+*/
+typedef unsigned int Base64Flags;
+unsigned test_function(Base64Flags inFlags);
+
+// expected-warning@+1 {{'@callback' command should be used in a comment attached to a pointer to function declaration}}
+/*! @callback test_callback
+*/
+typedef unsigned int BaseFlags;
+unsigned (*test_callback)(BaseFlags inFlags);
// expected-warning@+1 {{'\endverbatim' command does not terminate a verbatim text block}}
/// \endverbatim
@@ -862,36 +898,55 @@ int test_nocrash9;
// We used to crash on this. PR15068
-// expected-warning@+2 {{empty paragraph passed to '\param' command}}
-// expected-warning@+2 {{empty paragraph passed to '\param' command}}
+// expected-warning@+2 {{empty paragraph passed to '@param' command}}
+// expected-warning@+2 {{empty paragraph passed to '@param' command}}
///@param x
///@param y
int test_nocrash10(int x, int y);
-// expected-warning@+2 {{empty paragraph passed to '\param' command}} expected-warning@+2 {{parameter 'x' not found in the function declaration}}
-// expected-warning@+2 {{empty paragraph passed to '\param' command}} expected-warning@+2 {{parameter 'y' not found in the function declaration}}
+// expected-warning@+2 {{empty paragraph passed to '@param' command}} expected-warning@+2 {{parameter 'x' not found in the function declaration}}
+// expected-warning@+2 {{empty paragraph passed to '@param' command}} expected-warning@+2 {{parameter 'y' not found in the function declaration}}
///@param x
///@param y
int test_nocrash11();
-// expected-warning@+3 {{empty paragraph passed to '\param' command}} expected-warning@+3 {{parameter 'x' not found in the function declaration}}
-// expected-warning@+3 {{empty paragraph passed to '\param' command}} expected-warning@+3 {{parameter 'y' not found in the function declaration}}
+// expected-warning@+3 {{empty paragraph passed to '@param' command}} expected-warning@+3 {{parameter 'x' not found in the function declaration}}
+// expected-warning@+3 {{empty paragraph passed to '@param' command}} expected-warning@+3 {{parameter 'y' not found in the function declaration}}
/**
@param x
@param y
**/
int test_nocrash12();
-// expected-warning@+2 {{empty paragraph passed to '\param' command}}
-// expected-warning@+1 {{empty paragraph passed to '\param' command}}
+// expected-warning@+2 {{empty paragraph passed to '@param' command}}
+// expected-warning@+1 {{empty paragraph passed to '@param' command}}
///@param x@param y
int test_nocrash13(int x, int y);
-// rdar://12397511
+// rdar://12379114
+// expected-warning@+2 {{'@union' command should not be used in a comment attached to a non-union declaration}}
+/*!
+ @union U This is new
+*/
+struct U { int iS; };
-// expected-note@+2 {{previous command '\headerfile' here}}
-// expected-warning@+2 {{duplicated command '\headerfile'}}
-/// \headerfile ""
-/// \headerfile foo.h
-int test_duplicate_headerfile1(int);
+/*!
+ @union U1
+*/
+union U1 {int i; };
+// expected-warning@+2 {{'@struct' command should not be used in a comment attached to a non-struct declaration}}
+/*!
+ @struct S2
+*/
+union S2 {};
+
+/*!
+ @class C1
+*/
+class C1;
+
+/*!
+ @struct S3;
+*/
+class S3;
diff --git a/test/Sema/warn-documentation.m b/test/Sema/warn-documentation.m
index 8a894dca70..98c4993561 100644
--- a/test/Sema/warn-documentation.m
+++ b/test/Sema/warn-documentation.m
@@ -97,3 +97,63 @@ int b;
/// \returns aaa.
typedef int (^test_param1)(int aaa, int ccc);
+// rdar://13094352
+// expected-warning@+2 {{'@method' command should be used in a comment attached to an Objective-C method declaration}}
+@interface I
+/*! @method Base64EncodeEx
+*/
+typedef id ID;
+- (unsigned) Base64EncodeEx : (ID)Arg;
+@end
+
+// rdar://12379114
+// expected-warning@+5 {{'@interface' command should not be used in a comment attached to a non-interface declaration}}
+// expected-warning@+5 {{'@classdesign' command should not be used in a comment attached to a non-container declaration}}
+// expected-warning@+5 {{'@coclass' command should not be used in a comment attached to a non-container declaration}}
+@interface NSObject @end
+/*!
+@interface IOCommandGate
+@classdesign Multiple paragraphs go here.
+@coclass myCoClass
+*/
+
+typedef id OBJ;
+@interface IOCommandGate : NSObject {
+ OBJ iv;
+}
+@end
+
+// expected-warning@+2 {{'@protocol' command should not be used in a comment attached to a non-protocol declaration}}
+/*!
+@protocol PROTO
+*/
+struct S;
+
+/*!
+ @interface NSArray This is an array
+*/
+@class NSArray;
+@interface NSArray @end
+
+/*!
+@interface NSMutableArray
+@super NSArray
+*/
+@interface NSMutableArray : NSArray @end
+
+/*!
+ @protocol MyProto
+*/
+@protocol MyProto @end
+
+// expected-warning@+2 {{'@protocol' command should not be used in a comment attached to a non-protocol declaration}}
+/*!
+ @protocol MyProto
+*/
+@interface INTF <MyProto> @end
+
+// expected-warning@+2 {{'@struct' command should not be used in a comment attached to a non-struct declaration}}
+/*!
+ @struct S1 THIS IS IT
+*/
+@interface S1 @end
diff --git a/test/SemaCXX/blocks.cpp b/test/SemaCXX/blocks.cpp
index 3f81c274d0..a635e998d9 100644
--- a/test/SemaCXX/blocks.cpp
+++ b/test/SemaCXX/blocks.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -fblocks
// expected-no-diagnostics
void tovoid(void*);
@@ -69,3 +69,16 @@ namespace radar8382559 {
return hasProperty = 1;
}
}
+
+// Move __block variables to the heap when possible.
+class MoveOnly {
+public:
+ MoveOnly();
+ MoveOnly(const MoveOnly&) = delete;
+ MoveOnly(MoveOnly&&);
+};
+
+void move_block() {
+ __block MoveOnly mo;
+}
+
diff --git a/test/SemaCXX/function-redecl.cpp b/test/SemaCXX/function-redecl.cpp
index 4a5638f84e..7bf44b1c36 100644
--- a/test/SemaCXX/function-redecl.cpp
+++ b/test/SemaCXX/function-redecl.cpp
@@ -134,3 +134,14 @@ namespace test3 {
}
}
float test3_x; // expected-error {{redefinition of 'test3_x' with a different type: 'float' vs 'int'}}
+
+namespace test4 {
+ extern "C" {
+ void f() {
+ extern int b; // expected-note {{previous definition is here}}
+ }
+ }
+ extern "C" {
+ float b; // expected-error {{redefinition of 'b' with a different type: 'float' vs 'int'}}
+ }
+}
diff --git a/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
index 83f8395139..40bcf45bca 100644
--- a/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
+++ b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
@@ -70,7 +70,7 @@ namespace llvm {
struct S {};
void bar() {
GraphWriter<S> x; //expected-error{{no template named 'GraphWriter'; did you mean 'llvm::GraphWriter'?}}
- (void)new llvm::GraphWriter; // expected-error {{use of class template llvm::GraphWriter requires template arguments}}
+ (void)new llvm::GraphWriter; // expected-error {{use of class template 'llvm::GraphWriter' requires template arguments}}
(void)new llvm::Graphwriter<S>; // expected-error {{no template named 'Graphwriter' in namespace 'llvm'; did you mean 'GraphWriter'?}}
}
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index 8ecb54dde6..e5b3fab33c 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -415,3 +415,28 @@ namespace PR11784 {
void f(int);
void g() { A x; x = f; }
}
+
+namespace test10 {
+ struct A {
+ void operator[](float (*fn)(int)); // expected-note 2 {{not viable: no overload of 'bar' matching 'float (*)(int)'}}
+ };
+
+ float foo(int);
+ float foo(float);
+
+ template <class T> T bar(T);
+ template <class T, class U> T bar(U);
+
+ void test(A &a) {
+ a[&foo];
+ a[foo];
+
+ a[&bar<int>]; // expected-error {{no viable overloaded operator[]}}
+ a[bar<int>]; // expected-error {{no viable overloaded operator[]}}
+
+ // If these fail, it's because we're not letting the overload
+ // resolution for operator| resolve the overload of 'bar'.
+ a[&bar<float>];
+ a[bar<float>];
+ }
+}
diff --git a/test/SemaCXX/pragma-weak.cpp b/test/SemaCXX/pragma-weak.cpp
new file mode 100644
index 0000000000..057cf6b463
--- /dev/null
+++ b/test/SemaCXX/pragma-weak.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s
+
+#pragma weak foo
+static void foo();
+extern "C" {
+ void foo() {
+ };
+}
diff --git a/test/SemaObjC/arc-objc-lifetime.m b/test/SemaObjC/arc-objc-lifetime.m
index f2fb139322..5e252537fb 100644
--- a/test/SemaObjC/arc-objc-lifetime.m
+++ b/test/SemaObjC/arc-objc-lifetime.m
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -Wexplicit-ownership-type -verify -Wno-objc-root-class %s
-// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -Wexplicit-ownership-type -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -fobjc-runtime-has-weak -Wexplicit-ownership-type -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -fobjc-runtime-has-weak -Wexplicit-ownership-type -verify -Wno-objc-root-class %s
// rdar://10244607
typedef const struct __CFString * CFStringRef;
@@ -80,9 +80,48 @@ NSObject * __strong f4(void); // expected-warning{{ARC __strong lifetime qualifi
NSObject_ptr __strong f5(); // expected-warning{{ARC __strong lifetime qualifier on return type is ignored}}
typedef __strong id (*fptr)(int); // expected-warning{{ARC __strong lifetime qualifier on return type is ignored}}
-typedef __strong id (^block_ptr)(int); // expected-warning{{ARC __strong lifetime qualifier on return type is ignored}}
// Don't warn
strong_id f6();
strong_NSObject_ptr f7();
+typedef __strong id (^block_ptr)(int);
+
+// rdar://10127067
+void test8_a() {
+ __weak id *(^myBlock)(void);
+ __weak id *var = myBlock();
+ (void) (__strong id *) &myBlock;
+ (void) (__weak id *) &myBlock; // expected-error {{cast}}
+}
+void test8_b() {
+ __weak id (^myBlock)(void);
+ (void) (__weak id *) &myBlock;
+ (void) (__strong id *) &myBlock; // expected-error {{cast}}
+}
+void test8_c() {
+ __weak id (^*(^myBlock)(void))(void);
+ (void) (__weak id*) myBlock();
+ (void) (__strong id*) myBlock(); // expected-error {{cast}}
+ (void) (__weak id*) &myBlock; // expected-error {{cast}}
+ (void) (__strong id*) &myBlock;
+}
+@class Test9;
+void test9_a() {
+ __weak Test9 **(^myBlock)(void);
+ __weak Test9 **var = myBlock();
+ (void) (__strong Test9 **) &myBlock;
+ (void) (__weak Test9 **) &myBlock; // expected-error {{cast}}
+}
+void test9_b() {
+ __weak Test9 *(^myBlock)(void);
+ (void) (__weak Test9**) &myBlock;
+ (void) (__strong Test9**) &myBlock; // expected-error {{cast}}
+}
+void test9_c() {
+ __weak Test9 *(^*(^myBlock)(void))(void);
+ (void) (__weak Test9 **) myBlock();
+ (void) (__strong Test9 **) myBlock(); // expected-error {{cast}}
+ (void) (__weak Test9 **) &myBlock; // expected-error {{cast}}
+ (void) (__strong Test9 **) &myBlock;
+}
diff --git a/test/SemaObjC/bad-receiver-1.m b/test/SemaObjC/bad-receiver-1.m
index fe3eecff2b..fe7f7f5b44 100644
--- a/test/SemaObjC/bad-receiver-1.m
+++ b/test/SemaObjC/bad-receiver-1.m
@@ -7,8 +7,7 @@
int objc_lookUpClass(const char*);
void __raiseExc1() {
- [objc_lookUpClass("NSString") retain]; // expected-warning {{receiver type 'int' is not 'id'}} \
- expected-warning {{method '-retain' not found}}
+ [objc_lookUpClass("NSString") retain]; // expected-warning {{receiver type 'int' is not 'id'}}
}
typedef const struct __CFString * CFStringRef;
diff --git a/test/SemaObjC/blocks.m b/test/SemaObjC/blocks.m
index 9926b0835f..dd659addef 100644
--- a/test/SemaObjC/blocks.m
+++ b/test/SemaObjC/blocks.m
@@ -75,10 +75,11 @@ void foo10() {
// In C, enum constants have the type of the underlying integer type, not the
-// enumeration they are part of. We pretend the constants have enum type when
-// they are mixed with other expressions of enum type.
+// enumeration they are part of. We pretend the constants have enum type if
+// all the returns seem to be playing along.
enum CStyleEnum {
- CSE_Value = 1
+ CSE_Value = 1,
+ CSE_Value2 = 2
};
enum CStyleEnum getCSE();
typedef enum CStyleEnum (^cse_block_t)();
@@ -92,7 +93,9 @@ void testCStyleEnumInference(bool arg) {
a = ^{ // expected-error {{incompatible block pointer types assigning to 'cse_block_t' (aka 'enum CStyleEnum (^)()') from 'int (^)(void)'}}
return 1;
};
- a = ^{ // expected-error {{incompatible block pointer types assigning to 'cse_block_t' (aka 'enum CStyleEnum (^)()') from 'int (^)(void)'}}
+
+ // No warning here.
+ a = ^{
return CSE_Value;
};
@@ -114,6 +117,15 @@ void testCStyleEnumInference(bool arg) {
else
return 1;
};
+
+ // rdar://13200889
+ extern void check_enum(void);
+ a = ^{
+ return (arg ? (CSE_Value) : (check_enum(), (!arg ? CSE_Value2 : getCSE())));
+ };
+ a = ^{
+ return (arg ? (CSE_Value) : ({check_enum(); CSE_Value2; }));
+ };
}
diff --git a/test/SemaObjC/boxing-illegal-types.m b/test/SemaObjC/boxing-illegal.m
index ad45b11f2d..59b5c8b710 100644
--- a/test/SemaObjC/boxing-illegal-types.m
+++ b/test/SemaObjC/boxing-illegal.m
@@ -56,3 +56,20 @@ void testEnum(void *p) {
box = @(ME_foo);
box = @(*(enum ForwE*)p); // expected-error {{incomplete type 'enum ForwE' used in a boxed expression}}
}
+
+// rdar://13333205
+@class NSMutableDictionary;
+
+@interface NSMutableArray
++ (NSMutableArray*) array;
+@end
+
+NSMutableDictionary* mBars;
+
+__attribute((objc_root_class)) @interface rdar13333205 @end
+
+@implementation rdar13333205
+- (void) insertBar:(id)preset ofKind:(id) kind atIndex:(int)index {
+ NSMutableArray* presetArray = mBars[kind] ?: [NSMutableArray array]; // expected-error {{expected method to read dictionary element not found on object of type 'NSMutableDictionary *'}}
+}
+@end
diff --git a/test/SemaObjC/debugger-cast-result-to-id.m b/test/SemaObjC/debugger-cast-result-to-id.m
index 00a02be2c3..ecf3e74ba7 100644
--- a/test/SemaObjC/debugger-cast-result-to-id.m
+++ b/test/SemaObjC/debugger-cast-result-to-id.m
@@ -6,6 +6,8 @@ extern __unknown_anytype test1();
void test_unknown_anytype_receiver() {
(void)(int)[[test0 unknownMethod] otherUnknownMethod];;
(void)(id)[[test1() unknownMethod] otherUnknownMethod];
+ id x = test0;
+ id y = test1();
}
// rdar://10988847
diff --git a/test/SemaObjC/message.m b/test/SemaObjC/message.m
index 4015690bd0..f43bdf9885 100644
--- a/test/SemaObjC/message.m
+++ b/test/SemaObjC/message.m
@@ -95,7 +95,7 @@ int test5(int X) {
void foo4() {
struct objc_object X[10];
- [X rect]; // expected-warning {{receiver type 'struct objc_object *' is not 'id' or interface pointer, consider casting it to 'id'}} expected-warning {{method '-rect' not found (return type defaults to 'id')}}
+ [X rect]; // expected-warning {{receiver type 'struct objc_object *' is not 'id' or interface pointer, consider casting it to 'id'}}
}
// rdar://13207886
diff --git a/test/SemaObjC/protocol-archane.m b/test/SemaObjC/protocol-archane.m
index 49c9851122..788edf276d 100644
--- a/test/SemaObjC/protocol-archane.m
+++ b/test/SemaObjC/protocol-archane.m
@@ -8,9 +8,9 @@
void bar();
void foo(id x) {
bar((short<SomeProtocol>)x); // expected-error {{expected ')'}} expected-note {{to match this '('}}
- bar((<SomeProtocol>)x); // expected-warning {{protocol qualifiers without 'id' is archaic}}
+ bar((<SomeProtocol>)x); // expected-warning {{protocol has no object type specified; defaults to qualified 'id'}}
- [(<SomeProtocol>)x bar]; // expected-warning {{protocol qualifiers without 'id' is archaic}}
+ [(<SomeProtocol>)x bar]; // expected-warning {{protocol has no object type specified; defaults to qualified 'id'}}
}
@protocol MyProtocol
@@ -37,6 +37,6 @@ Class <SomeProtocol> UnfortunateGCCExtension;
@protocol Broken @end
@interface Crash @end
@implementation Crash
-- (void)crashWith:(<Broken>)a { // expected-warning {{protocol qualifiers without 'id' is archaic}}
+- (void)crashWith:(<Broken>)a { // expected-warning {{protocol has no object type specified; defaults to qualified 'id'}}
}
@end
diff --git a/test/SemaObjC/super-property-notation.m b/test/SemaObjC/super-property-notation.m
index 0c17bb9392..4741d1b5a8 100644
--- a/test/SemaObjC/super-property-notation.m
+++ b/test/SemaObjC/super-property-notation.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
@interface B
+(int) classGetter;
@@ -29,3 +28,25 @@ void f0() {
int l2 = [A classGetter2];
}
+// rdar://13349296
+__attribute__((objc_root_class)) @interface ClassBase
+@property (nonatomic, retain) ClassBase * foo;
+@end
+
+@implementation ClassBase
+- (void) Meth:(ClassBase*)foo {
+ super.foo = foo; // expected-error {{'ClassBase' cannot use 'super' because it is a root class}}
+ [super setFoo:foo]; // expected-error {{'ClassBase' cannot use 'super' because it is a root class}}
+}
+@end
+
+@interface ClassDerived : ClassBase
+@property (nonatomic, retain) ClassDerived * foo;
+@end
+
+@implementation ClassDerived
+- (void) Meth:(ClassBase*)foo {
+ super.foo = foo; // must work with no warning
+ [super setFoo:foo]; // works with no warning
+}
+@end
diff --git a/test/SemaObjC/super.m b/test/SemaObjC/super.m
index cf48c196db..fd069af7b0 100644
--- a/test/SemaObjC/super.m
+++ b/test/SemaObjC/super.m
@@ -51,8 +51,7 @@ void f(id super) {
[super m];
}
void f0(int super) {
- [super m]; // expected-warning{{receiver type 'int' is not 'id'}} \
- expected-warning {{method '-m' not found (return type defaults to 'id')}}
+ [super m]; // expected-warning{{receiver type 'int' is not 'id'}}
}
void f1(id puper) { // expected-note {{'puper' declared here}}
[super m]; // expected-error{{use of undeclared identifier 'super'}}
diff --git a/test/SemaObjC/warn-isa-ref.m b/test/SemaObjC/warn-isa-ref.m
index c20474d5b0..39a5e45496 100644
--- a/test/SemaObjC/warn-isa-ref.m
+++ b/test/SemaObjC/warn-isa-ref.m
@@ -26,13 +26,11 @@ static void func() {
// GCC allows this, with the following warning:
// instance variable 'isa' is @protected; this will be a hard error in the future
//
- // FIXME: see if we can avoid the 2 warnings that follow the error.
+ // FIXME: see if we can avoid the warning that follows the error.
[(*y).isa self]; // expected-error {{instance variable 'isa' is protected}} \
- expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}} \
- expected-warning{{method '-self' not found (return type defaults to 'id')}}
+ expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}}
[y->isa self]; // expected-error {{instance variable 'isa' is protected}} \
- expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}} \
- expected-warning{{method '-self' not found (return type defaults to 'id')}}
+ expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}}
}
// rdar://11702488
diff --git a/test/SemaObjCXX/arc-nsconsumed-errors.mm b/test/SemaObjCXX/arc-nsconsumed-errors.mm
index 93f5d99967..10ae10d049 100644
--- a/test/SemaObjCXX/arc-nsconsumed-errors.mm
+++ b/test/SemaObjCXX/arc-nsconsumed-errors.mm
@@ -18,3 +18,35 @@ blk1 b2 = ^void (id, __attribute((ns_consumed)) id){}; // expected-error {{canno
blk1 c3 = ^void (__attribute((ns_consumed)) id, __attribute((ns_consumed)) id){};
blk1 d4 = ^void (id, id) {}; // expected-error {{cannot initialize a variable of type '__strong blk1'}}
+
+
+typedef void (*releaser_t)(__attribute__((ns_consumed)) id);
+
+void normalFunction(id);
+releaser_t r1 = normalFunction; // expected-error {{cannot initialize a variable of type 'releaser_t'}}
+
+void releaser(__attribute__((ns_consumed)) id);
+releaser_t r2 = releaser; // no-warning
+
+template <typename T>
+void templateFunction(T) {} // expected-note {{candidate function}}
+releaser_t r3 = templateFunction<id>; // expected-error {{address of overloaded function 'templateFunction' does not match required type 'void (id)'}}
+
+template <typename T>
+void templateReleaser(__attribute__((ns_consumed)) T) {}
+releaser_t r4 = templateReleaser<id>; // no-warning
+
+
+@class AntiRelease, ExplicitAntiRelease, ProRelease;
+
+template<>
+void templateFunction(__attribute__((ns_consumed)) AntiRelease *); // expected-error {{no function template matches function template specialization 'templateFunction'}}
+
+template<>
+void templateReleaser(AntiRelease *); // expected-error {{no function template matches function template specialization 'templateReleaser'}}
+
+template<>
+void templateReleaser(ExplicitAntiRelease *) {} // expected-error {{no function template matches function template specialization 'templateReleaser'}}
+
+template<>
+void templateReleaser(__attribute__((ns_consumed)) ProRelease *); // no-warning
diff --git a/test/SemaObjCXX/debugger-cast-result-to-id.mm b/test/SemaObjCXX/debugger-cast-result-to-id.mm
index cd7aa7b6ac..815ae3833d 100644
--- a/test/SemaObjCXX/debugger-cast-result-to-id.mm
+++ b/test/SemaObjCXX/debugger-cast-result-to-id.mm
@@ -1,7 +1,21 @@
-// RUN: %clang_cc1 -fdebugger-support -fdebugger-cast-result-to-id -funknown-anytype -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fdebugger-support -fdebugger-cast-result-to-id -funknown-anytype -fsyntax-only -verify %s
+
+extern __unknown_anytype test0a;
+extern __unknown_anytype test1a();
+extern __unknown_anytype test0b;
+extern __unknown_anytype test1b();
+extern __unknown_anytype test0c;
+extern __unknown_anytype test1c();
+extern __unknown_anytype test0d;
+extern __unknown_anytype test1d();
+extern __unknown_anytype test0d;
+extern __unknown_anytype test1d();
+
+@interface A
+@end
// rdar://problem/9416370
-namespace test0 {
+namespace rdar9416370 {
void test(id x) {
if ([x foo]) {} // expected-error {{no known method '-foo'; cast the message send to the method's return type}}
[x foo];
@@ -10,8 +24,20 @@ namespace test0 {
// rdar://10988847
@class NSString; // expected-note {{forward declaration of class here}}
-namespace test1 {
- void rdar10988847() {
+namespace rdar10988847 {
+ void test() {
id s = [NSString stringWithUTF8String:"foo"]; // expected-warning {{receiver 'NSString' is a forward class and corresponding @interface may not exist}}
}
}
+
+// rdar://13338107
+namespace rdar13338107 {
+ void test() {
+ id x1 = test0a;
+ id x2 = test1a();
+ A *x3 = test0b;
+ A *x4 = test1b();
+ auto x5 = test0c;
+ auto x6 = test1c();
+ }
+}
diff --git a/test/SemaObjCXX/properties.mm b/test/SemaObjCXX/properties.mm
index 804d6829b1..abd4db998b 100644
--- a/test/SemaObjCXX/properties.mm
+++ b/test/SemaObjCXX/properties.mm
@@ -129,3 +129,38 @@ extern void* VoidType;
extern decltype(TestNonTrivialObj.p1 = NonTrivial1())* VoidType;
extern decltype(TestNonTrivialObj.p2 = NonTrivial2())* VoidType;
+// rdar://13332183
+namespace test9 {
+ struct CString {
+ const char *_data;
+ char operator[](int i) const { return _data[i]; }
+ };
+}
+@interface Test9
+@property test9::CString name;
+@end
+namespace test9 {
+ char test(Test9 *t) {
+ return t.name[0];
+ }
+}
+
+namespace test10 {
+ struct A { operator const char*(); };
+ struct B { operator const char*(); };
+}
+@interface Test10
+@property test10::A a;
+@property test10::B b;
+@property int index;
+@end
+namespace test10 {
+ void test(Test10 *t) {
+ (void) t.a[6];
+ (void) 6[t.b];
+ (void) "help"[t.index];
+ (void) t.index["help"];
+ (void) t.a[t.index];
+ (void) t.index[t.b];
+ }
+}
diff --git a/test/SemaOpenCL/invalid-kernel-attrs.cl b/test/SemaOpenCL/invalid-kernel-attrs.cl
new file mode 100644
index 0000000000..d242eaf692
--- /dev/null
+++ b/test/SemaOpenCL/invalid-kernel-attrs.cl
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -verify %s
+
+kernel __attribute__((vec_type_hint)) void kernel1() {} //expected-error{{attribute takes one argument}}
+
+kernel __attribute__((vec_type_hint(not_type))) void kernel2() {} //expected-error{{unknown type name 'not_type'}}
+
+kernel __attribute__((vec_type_hint(void))) void kernel3() {} //expected-error{{invalid attribute argument 'void' - expecting a vector or vectorizable scalar type}}
+
+kernel __attribute__((vec_type_hint(bool))) void kernel4() {} //expected-error{{invalid attribute argument 'bool' - expecting a vector or vectorizable scalar type}}
+
+kernel __attribute__((vec_type_hint(int))) __attribute__((vec_type_hint(float))) void kernel5() {} //expected-warning{{attribute 'vec_type_hint' is already applied with different parameters}}
+
+kernel __attribute__((work_group_size_hint(8,16,32,4))) void kernel6() {} //expected-error{{attribute requires exactly 3 arguments}}
+
+kernel __attribute__((work_group_size_hint(1,2,3))) __attribute__((work_group_size_hint(3,2,1))) void kernel7() {} //expected-warning{{attribute 'work_group_size_hint' is already applied with different parameters}}
+
diff --git a/test/SemaTemplate/class-template-id.cpp b/test/SemaTemplate/class-template-id.cpp
index b674537ea7..5bbc70c955 100644
--- a/test/SemaTemplate/class-template-id.cpp
+++ b/test/SemaTemplate/class-template-id.cpp
@@ -40,7 +40,7 @@ typedef N::C<float> c2;
// PR5655
template<typename T> struct Foo { }; // expected-note{{template is declared here}}
-void f(void) { Foo bar; } // expected-error{{use of class template Foo requires template arguments}}
+void f(void) { Foo bar; } // expected-error{{use of class template 'Foo' requires template arguments}}
// rdar://problem/8254267
template <typename T> class Party;
diff --git a/test/SemaTemplate/destructor-template.cpp b/test/SemaTemplate/destructor-template.cpp
index 07beda40aa..6806c24a84 100644
--- a/test/SemaTemplate/destructor-template.cpp
+++ b/test/SemaTemplate/destructor-template.cpp
@@ -57,3 +57,22 @@ namespace PR7904 {
};
Foo f;
}
+
+namespace rdar13140795 {
+ template <class T> class shared_ptr {};
+
+ template <typename T> struct Marshal {
+ static int gc();
+ };
+
+
+ template <typename T> int Marshal<T>::gc() {
+ shared_ptr<T> *x;
+ x->template shared_ptr<T>::~shared_ptr();
+ return 0;
+ }
+
+ void test() {
+ Marshal<int>::gc();
+ }
+}
diff --git a/test/SemaTemplate/instantiate-type.cpp b/test/SemaTemplate/instantiate-type.cpp
index f5d02707cb..2440a38f3e 100644
--- a/test/SemaTemplate/instantiate-type.cpp
+++ b/test/SemaTemplate/instantiate-type.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
int* f(int);
float *f(...);
@@ -15,3 +15,14 @@ X<int>::typeof_type &iptr1 = iptr0;
X<int>::typeof_expr &iptr2 = iptr0;
X<float*>::typeof_expr &fptr1 = fptr0;
+
+namespace rdar13094134 {
+ template <class>
+ class X {
+ typedef struct {
+ Y *y; // expected-error{{unknown type name 'Y'}}
+ } Y;
+ };
+
+ X<int> xi;
+}
diff --git a/test/SemaTemplate/temp_arg.cpp b/test/SemaTemplate/temp_arg.cpp
index 5a4c8fc16f..052c19ef63 100644
--- a/test/SemaTemplate/temp_arg.cpp
+++ b/test/SemaTemplate/temp_arg.cpp
@@ -10,7 +10,7 @@ A<int, 0, X> * a1;
A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}}
A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}}
-A a3; // expected-error{{use of class template A requires template arguments}}
+A a3; // expected-error{{use of class template 'A' requires template arguments}}
namespace test0 {
template <class t> class foo {};
diff --git a/test/SemaTemplate/temp_arg_type.cpp b/test/SemaTemplate/temp_arg_type.cpp
index 397094218a..637b5637ba 100644
--- a/test/SemaTemplate/temp_arg_type.cpp
+++ b/test/SemaTemplate/temp_arg_type.cpp
@@ -4,7 +4,7 @@ template<typename T> class A; // expected-note 2 {{template parameter is declare
// [temp.arg.type]p1
A<0> *a1; // expected-error{{template argument for template type parameter must be a type}}
-A<A> *a2; // expected-error{{use of class template A requires template arguments}}
+A<A> *a2; // expected-error{{use of class template 'A' requires template arguments}}
A<int> *a3;
A<int()> *a4;
@@ -19,7 +19,7 @@ A<function_tpl> a7; // expected-error{{template argument for template type para
namespace ns {
template<typename T> class B {}; // expected-note{{template is declared here}}
}
-A<ns::B> a8; // expected-error{{use of class template ns::B requires template arguments}}
+A<ns::B> a8; // expected-error{{use of class template 'ns::B' requires template arguments}}
// [temp.arg.type]p2
void f() {
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 178cbcae8e..46d61e995c 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -1231,7 +1231,7 @@ int perform_test_load_tu(const char *file, const char *filter,
int result;
Idx = clang_createIndex(/* excludeDeclsFromPCH */
!strcmp(filter, "local") ? 1 : 0,
- /* displayDiagnosics=*/1);
+ /* displayDiagnostics=*/1);
if (!CreateTranslationUnit(Idx, file, &TU)) {
clang_disposeIndex(Idx);
@@ -1256,7 +1256,7 @@ int perform_test_load_source(int argc, const char **argv,
Idx = clang_createIndex(/* excludeDeclsFromPCH */
(!strcmp(filter, "local") ||
!strcmp(filter, "local-display"))? 1 : 0,
- /* displayDiagnosics=*/0);
+ /* displayDiagnostics=*/0);
if ((CommentSchemaFile = parse_comments_schema(argc, argv))) {
argc--;
@@ -1301,7 +1301,7 @@ int perform_test_reparse_source(int argc, const char **argv, int trials,
Idx = clang_createIndex(/* excludeDeclsFromPCH */
!strcmp(filter, "local") ? 1 : 0,
- /* displayDiagnosics=*/0);
+ /* displayDiagnostics=*/0);
if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
clang_disposeIndex(Idx);
@@ -1380,7 +1380,7 @@ static int perform_file_scan(const char *ast_file, const char *source_file,
unsigned start_line = 1, start_col = 1;
if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
- /* displayDiagnosics=*/1))) {
+ /* displayDiagnostics=*/1))) {
fprintf(stderr, "Could not create Index\n");
return 1;
}
@@ -2135,6 +2135,99 @@ static int find_file_refs_at(int argc, const char **argv) {
return 0;
}
+static enum CXVisitorResult findFileIncludesVisit(void *context,
+ CXCursor cursor, CXSourceRange range) {
+ PrintCursor(cursor, NULL);
+ PrintRange(range, "");
+ printf("\n");
+ return CXVisit_Continue;
+}
+
+static int find_file_includes_in(int argc, const char **argv) {
+ CXIndex CIdx;
+ struct CXUnsavedFile *unsaved_files = 0;
+ int num_unsaved_files = 0;
+ CXTranslationUnit TU;
+ const char **Filenames = 0;
+ unsigned NumFilenames = 0;
+ unsigned Repeats = 1;
+ unsigned I, FI;
+
+ /* Count the number of locations. */
+ while (strstr(argv[NumFilenames+1], "-file-includes-in=") == argv[NumFilenames+1])
+ ++NumFilenames;
+
+ /* Parse the locations. */
+ assert(NumFilenames > 0 && "Unable to count filenames?");
+ Filenames = (const char **)malloc(NumFilenames * sizeof(const char *));
+ for (I = 0; I < NumFilenames; ++I) {
+ const char *input = argv[I + 1] + strlen("-file-includes-in=");
+ /* Copy the file name. */
+ Filenames[I] = input;
+ }
+
+ if (parse_remapped_files(argc, argv, NumFilenames + 1, &unsaved_files,
+ &num_unsaved_files))
+ return -1;
+
+ if (getenv("CINDEXTEST_EDITING"))
+ Repeats = 2;
+
+ /* Parse the translation unit. When we're testing clang_getCursor() after
+ reparsing, don't remap unsaved files until the second parse. */
+ CIdx = clang_createIndex(1, 1);
+ TU = clang_parseTranslationUnit(CIdx, argv[argc - 1],
+ argv + num_unsaved_files + 1 + NumFilenames,
+ argc - num_unsaved_files - 2 - NumFilenames,
+ unsaved_files,
+ Repeats > 1? 0 : num_unsaved_files,
+ getDefaultParsingOptions());
+
+ if (!TU) {
+ fprintf(stderr, "unable to parse input\n");
+ return -1;
+ }
+
+ if (checkForErrors(TU) != 0)
+ return -1;
+
+ for (I = 0; I != Repeats; ++I) {
+ if (Repeats > 1 &&
+ clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
+ clang_defaultReparseOptions(TU))) {
+ clang_disposeTranslationUnit(TU);
+ return 1;
+ }
+
+ if (checkForErrors(TU) != 0)
+ return -1;
+
+ for (FI = 0; FI < NumFilenames; ++FI) {
+ CXFile file = clang_getFile(TU, Filenames[FI]);
+ if (!file)
+ continue;
+
+ if (checkForErrors(TU) != 0)
+ return -1;
+
+ if (I + 1 == Repeats) {
+ CXCursorAndRangeVisitor visitor = { 0, findFileIncludesVisit };
+ clang_findIncludesInFile(TU, file, visitor);
+
+ if (checkForErrors(TU) != 0)
+ return -1;
+ }
+ }
+ }
+
+ PrintDiagnostics(TU);
+ clang_disposeTranslationUnit(TU);
+ clang_disposeIndex(CIdx);
+ free((void *)Filenames);
+ free_remapped_files(unsaved_files, num_unsaved_files);
+ return 0;
+}
+
#define MAX_IMPORTED_ASTFILES 200
typedef struct {
@@ -2702,7 +2795,7 @@ static int index_file(int argc, const char **argv, int full) {
}
if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
- /* displayDiagnosics=*/1))) {
+ /* displayDiagnostics=*/1))) {
fprintf(stderr, "Could not create Index\n");
return 1;
}
@@ -2746,7 +2839,7 @@ static int index_tu(int argc, const char **argv) {
}
if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
- /* displayDiagnosics=*/1))) {
+ /* displayDiagnostics=*/1))) {
fprintf(stderr, "Could not create Index\n");
return 1;
}
@@ -2781,7 +2874,7 @@ static int index_compile_db(int argc, const char **argv) {
}
if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
- /* displayDiagnosics=*/1))) {
+ /* displayDiagnostics=*/1))) {
fprintf(stderr, "Could not create Index\n");
return 1;
}
@@ -3289,7 +3382,7 @@ int write_pch_file(const char *filename, int argc, const char *argv[]) {
int num_unsaved_files = 0;
int result = 0;
- Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnosics=*/1);
+ Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnostics=*/1);
if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
clang_disposeIndex(Idx);
@@ -3520,7 +3613,8 @@ static void print_usage(void) {
"usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
" c-index-test -code-completion-timing=<site> <compiler arguments>\n"
" c-index-test -cursor-at=<site> <compiler arguments>\n"
- " c-index-test -file-refs-at=<site> <compiler arguments>\n");
+ " c-index-test -file-refs-at=<site> <compiler arguments>\n"
+ " c-index-test -file-includes-in=<filename> <compiler arguments>\n");
fprintf(stderr,
" c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
" c-index-test -index-file-full [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
@@ -3582,6 +3676,8 @@ int cindextest_main(int argc, const char **argv) {
return inspect_cursor_at(argc, argv);
if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
return find_file_refs_at(argc, argv);
+ if (argc > 2 && strstr(argv[1], "-file-includes-in=") == argv[1])
+ return find_file_includes_in(argc, argv);
if (argc > 2 && strcmp(argv[1], "-index-file") == 0)
return index_file(argc - 2, argv + 2, /*full=*/0);
if (argc > 2 && strcmp(argv[1], "-index-file-full") == 0)
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index de627fb58b..c8790177b3 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -417,7 +417,7 @@ int main(int argc_, const char **argv_) {
// DiagnosticOptions instance.
TextDiagnosticPrinter *DiagClient
= new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
- DiagClient->setPrefix(llvm::sys::path::stem(Path.str()));
+ DiagClient->setPrefix(llvm::sys::path::filename(Path.str()));
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 36224a8cff..a2449bdc3f 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -223,9 +223,9 @@ static bool visitPreprocessedEntitiesInRange(SourceRange R,
PPRec, FID);
}
-void CursorVisitor::visitFileRegion() {
+bool CursorVisitor::visitFileRegion() {
if (RegionOfInterest.isInvalid())
- return;
+ return false;
ASTUnit *Unit = cxtu::getASTUnit(TU);
SourceManager &SM = Unit->getSourceManager();
@@ -243,7 +243,7 @@ void CursorVisitor::visitFileRegion() {
assert(Begin.first == End.first);
if (Begin.second > End.second)
- return;
+ return false;
FileID File = Begin.first;
unsigned Offset = Begin.second;
@@ -251,12 +251,15 @@ void CursorVisitor::visitFileRegion() {
if (!VisitDeclsOnly && !VisitPreprocessorLast)
if (visitPreprocessedEntitiesInRegion())
- return; // visitation break.
+ return true; // visitation break.
- visitDeclsFromFileRegion(File, Offset, Length);
+ if (visitDeclsFromFileRegion(File, Offset, Length))
+ return true; // visitation break.
if (!VisitDeclsOnly && VisitPreprocessorLast)
- visitPreprocessedEntitiesInRegion();
+ return visitPreprocessedEntitiesInRegion();
+
+ return false;
}
static bool isInLexicalContext(Decl *D, DeclContext *DC) {
@@ -271,7 +274,7 @@ static bool isInLexicalContext(Decl *D, DeclContext *DC) {
return false;
}
-void CursorVisitor::visitDeclsFromFileRegion(FileID File,
+bool CursorVisitor::visitDeclsFromFileRegion(FileID File,
unsigned Offset, unsigned Length) {
ASTUnit *Unit = cxtu::getASTUnit(TU);
SourceManager &SM = Unit->getSourceManager();
@@ -286,7 +289,7 @@ void CursorVisitor::visitDeclsFromFileRegion(FileID File,
bool Invalid = false;
const SrcMgr::SLocEntry &SLEntry = SM.getSLocEntry(File, &Invalid);
if (Invalid)
- return;
+ return false;
SourceLocation Outer;
if (SLEntry.isFile())
@@ -294,7 +297,7 @@ void CursorVisitor::visitDeclsFromFileRegion(FileID File,
else
Outer = SLEntry.getExpansion().getExpansionLocStart();
if (Outer.isInvalid())
- return;
+ return false;
llvm::tie(File, Offset) = SM.getDecomposedExpansionLoc(Outer);
Length = 0;
@@ -337,11 +340,11 @@ void CursorVisitor::visitDeclsFromFileRegion(FileID File,
}
if (Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true))
- break;
+ return true; // visitation break.
}
if (VisitedAtLeastOnce)
- return;
+ return false;
// No Decls overlapped with the range. Move up the lexical context until there
// is a context that contains the range or we reach the translation unit
@@ -356,12 +359,14 @@ void CursorVisitor::visitDeclsFromFileRegion(FileID File,
break;
if (RangeCompare(SM, CurDeclRange, Range) == RangeOverlap) {
- Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true);
- break;
+ if (Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true))
+ return true; // visitation break.
}
DC = D->getLexicalDeclContext();
}
+
+ return false;
}
bool CursorVisitor::visitPreprocessedEntitiesInRegion() {
@@ -6387,6 +6392,8 @@ Logger &cxindex::Logger::operator<<(CXTranslationUnit TU) {
if (TU) {
if (ASTUnit *Unit = cxtu::getASTUnit(TU)) {
LogOS << '<' << Unit->getMainFileName() << '>';
+ if (Unit->isMainFileAST())
+ LogOS << " (" << Unit->getASTFileName() << ')';
return *this;
}
}
@@ -6395,6 +6402,18 @@ Logger &cxindex::Logger::operator<<(CXTranslationUnit TU) {
return *this;
}
+Logger &cxindex::Logger::operator<<(const FileEntry *FE) {
+ *this << FE->getName();
+ return *this;
+}
+
+Logger &cxindex::Logger::operator<<(CXCursor cursor) {
+ CXString cursorName = clang_getCursorDisplayName(cursor);
+ *this << cursorName << "@" << clang_getCursorLocation(cursor);
+ clang_disposeString(cursorName);
+ return *this;
+}
+
Logger &cxindex::Logger::operator<<(CXSourceLocation Loc) {
CXFile File;
unsigned Line, Column;
diff --git a/tools/libclang/CIndexHigh.cpp b/tools/libclang/CIndexHigh.cpp
index 77e71c3393..2a55af57fc 100644
--- a/tools/libclang/CIndexHigh.cpp
+++ b/tools/libclang/CIndexHigh.cpp
@@ -205,31 +205,31 @@ static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
return CXChildVisit_Recurse;
}
- data->visitor.visit(data->visitor.context, cursor,
- cxloc::translateSourceRange(Ctx, Loc));
+ if (data->visitor.visit(data->visitor.context, cursor,
+ cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break)
+ return CXChildVisit_Break;
}
return CXChildVisit_Recurse;
}
-static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
- const FileEntry *File,
- CXCursorAndRangeVisitor Visitor) {
+static bool findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
+ const FileEntry *File,
+ CXCursorAndRangeVisitor Visitor) {
assert(clang_isDeclaration(declCursor.kind));
SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager();
FileID FID = SM.translateFile(File);
const Decl *Dcl = cxcursor::getCursorDecl(declCursor);
if (!Dcl)
- return;
+ return false;
FindFileIdRefVisitData data(TU, FID, Dcl,
cxcursor::getSelectorIdentifierIndex(declCursor),
Visitor);
if (const DeclContext *DC = Dcl->getParentFunctionOrMethod()) {
- clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU),
- findFileIdRefVisit, &data);
- return;
+ return clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU),
+ findFileIdRefVisit, &data);
}
SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
@@ -239,7 +239,7 @@ static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
/*VisitIncludedEntities=*/false,
Range,
/*VisitDeclsOnly=*/true);
- FindIdRefsVisitor.visitFileRegion();
+ return FindIdRefsVisitor.visitFileRegion();
}
namespace {
@@ -300,17 +300,18 @@ static enum CXChildVisitResult findFileMacroRefVisit(CXCursor cursor,
return CXChildVisit_Continue;
}
- data->visitor.visit(data->visitor.context, cursor,
- cxloc::translateSourceRange(Ctx, Loc));
+ if (data->visitor.visit(data->visitor.context, cursor,
+ cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break)
+ return CXChildVisit_Break;
return CXChildVisit_Continue;
}
-static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
+static bool findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
const FileEntry *File,
CXCursorAndRangeVisitor Visitor) {
if (Cursor.kind != CXCursor_MacroDefinition &&
Cursor.kind != CXCursor_MacroExpansion)
- return;
+ return false;
ASTUnit *Unit = cxtu::getASTUnit(TU);
SourceManager &SM = Unit->getSourceManager();
@@ -322,7 +323,7 @@ static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
else
Macro = getCursorMacroExpansion(Cursor).getName();
if (!Macro)
- return;
+ return false;
FindFileMacroRefVisitData data(*Unit, File, Macro, Visitor);
@@ -332,7 +333,73 @@ static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
/*VisitPreprocessorLast=*/false,
/*VisitIncludedEntities=*/false,
Range);
- FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion();
+ return FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion();
+}
+
+namespace {
+
+struct FindFileIncludesVisitor {
+ ASTUnit &Unit;
+ const FileEntry *File;
+ CXCursorAndRangeVisitor visitor;
+
+ FindFileIncludesVisitor(ASTUnit &Unit, const FileEntry *File,
+ CXCursorAndRangeVisitor visitor)
+ : Unit(Unit), File(File), visitor(visitor) { }
+
+ ASTContext &getASTContext() const {
+ return Unit.getASTContext();
+ }
+
+ enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent) {
+ if (cursor.kind != CXCursor_InclusionDirective)
+ return CXChildVisit_Continue;
+
+ SourceLocation
+ Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
+
+ ASTContext &Ctx = getASTContext();
+ SourceManager &SM = Ctx.getSourceManager();
+
+ // We are looking for includes in a specific file.
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ if (SM.getFileEntryForID(LocInfo.first) != File)
+ return CXChildVisit_Continue;
+
+ if (visitor.visit(visitor.context, cursor,
+ cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break)
+ return CXChildVisit_Break;
+ return CXChildVisit_Continue;
+ }
+
+ static enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent,
+ CXClientData client_data) {
+ return static_cast<FindFileIncludesVisitor*>(client_data)->
+ visit(cursor, parent);
+ }
+};
+
+} // anonymous namespace
+
+static bool findIncludesInFile(CXTranslationUnit TU, const FileEntry *File,
+ CXCursorAndRangeVisitor Visitor) {
+ assert(TU && File && Visitor.visit);
+
+ ASTUnit *Unit = cxtu::getASTUnit(TU);
+ SourceManager &SM = Unit->getSourceManager();
+
+ FileID FID = SM.translateFile(File);
+
+ FindFileIncludesVisitor IncludesVisitor(*Unit, File, Visitor);
+
+ SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
+ CursorVisitor InclusionCursorsVisitor(TU,
+ FindFileIncludesVisitor::visit,
+ &IncludesVisitor,
+ /*VisitPreprocessorLast=*/false,
+ /*VisitIncludedEntities=*/false,
+ Range);
+ return InclusionCursorsVisitor.visitPreprocessedEntitiesInRegion();
}
@@ -342,44 +409,48 @@ static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
extern "C" {
-void clang_findReferencesInFile(CXCursor cursor, CXFile file,
- CXCursorAndRangeVisitor visitor) {
+CXResult clang_findReferencesInFile(CXCursor cursor, CXFile file,
+ CXCursorAndRangeVisitor visitor) {
LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
if (clang_Cursor_isNull(cursor)) {
if (Log)
*Log << "Null cursor";
- return;
+ return CXResult_Invalid;
}
if (cursor.kind == CXCursor_NoDeclFound) {
if (Log)
*Log << "Got CXCursor_NoDeclFound";
- return;
+ return CXResult_Invalid;
}
if (!file) {
if (Log)
*Log << "Null file";
- return;
+ return CXResult_Invalid;
}
if (!visitor.visit) {
if (Log)
*Log << "Null visitor";
- return;
+ return CXResult_Invalid;
}
+ if (Log)
+ *Log << cursor << " @" << static_cast<const FileEntry *>(file);
+
ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor);
if (!CXXUnit)
- return;
+ return CXResult_Invalid;
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
if (cursor.kind == CXCursor_MacroDefinition ||
cursor.kind == CXCursor_MacroExpansion) {
- findMacroRefsInFile(cxcursor::getCursorTU(cursor),
- cursor,
- static_cast<const FileEntry *>(file),
- visitor);
- return;
+ if (findMacroRefsInFile(cxcursor::getCursorTU(cursor),
+ cursor,
+ static_cast<const FileEntry *>(file),
+ visitor))
+ return CXResult_VisitBreak;
+ return CXResult_Success;
}
// We are interested in semantics of identifiers so for C++ constructor exprs
@@ -396,13 +467,49 @@ void clang_findReferencesInFile(CXCursor cursor, CXFile file,
if (!clang_isDeclaration(refCursor.kind)) {
if (Log)
*Log << "cursor is not referencing a declaration";
- return;
+ return CXResult_Invalid;
+ }
+
+ if (findIdRefsInFile(cxcursor::getCursorTU(cursor),
+ refCursor,
+ static_cast<const FileEntry *>(file),
+ visitor))
+ return CXResult_VisitBreak;
+ return CXResult_Success;
+}
+
+CXResult clang_findIncludesInFile(CXTranslationUnit TU, CXFile file,
+ CXCursorAndRangeVisitor visitor) {
+ LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
+
+ if (!TU) {
+ if (Log)
+ *Log << "Null CXTranslationUnit";
+ return CXResult_Invalid;
+ }
+ if (!file) {
+ if (Log)
+ *Log << "Null file";
+ return CXResult_Invalid;
+ }
+ if (!visitor.visit) {
+ if (Log)
+ *Log << "Null visitor";
+ return CXResult_Invalid;
}
- findIdRefsInFile(cxcursor::getCursorTU(cursor),
- refCursor,
- static_cast<const FileEntry *>(file),
- visitor);
+ if (Log)
+ *Log << TU << " @" << static_cast<const FileEntry *>(file);
+
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
+ if (!CXXUnit)
+ return CXResult_Invalid;
+
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ if (findIncludesInFile(TU, static_cast<const FileEntry *>(file), visitor))
+ return CXResult_VisitBreak;
+ return CXResult_Success;
}
static enum CXVisitorResult _visitCursorAndRange(void *context,
@@ -412,13 +519,21 @@ static enum CXVisitorResult _visitCursorAndRange(void *context,
return INVOKE_BLOCK2(block, cursor, range);
}
-void clang_findReferencesInFileWithBlock(CXCursor cursor,
- CXFile file,
- CXCursorAndRangeVisitorBlock block) {
+CXResult clang_findReferencesInFileWithBlock(CXCursor cursor,
+ CXFile file,
+ CXCursorAndRangeVisitorBlock block) {
CXCursorAndRangeVisitor visitor = { block,
block ? _visitCursorAndRange : 0 };
return clang_findReferencesInFile(cursor, file, visitor);
}
+CXResult clang_findIncludesInFileWithBlock(CXTranslationUnit TU,
+ CXFile file,
+ CXCursorAndRangeVisitorBlock block) {
+ CXCursorAndRangeVisitor visitor = { block,
+ block ? _visitCursorAndRange : 0 };
+ return clang_findIncludesInFile(TU, file, visitor);
+}
+
} // end: extern "C"
diff --git a/tools/libclang/CLog.h b/tools/libclang/CLog.h
index 3ac40d56e7..57e01aeb68 100644
--- a/tools/libclang/CLog.h
+++ b/tools/libclang/CLog.h
@@ -23,6 +23,7 @@ class format_object_base;
}
namespace clang {
+ class FileEntry;
namespace cxindex {
@@ -64,6 +65,8 @@ public:
~Logger();
Logger &operator<<(CXTranslationUnit);
+ Logger &operator<<(const FileEntry *FE);
+ Logger &operator<<(CXCursor cursor);
Logger &operator<<(CXSourceLocation);
Logger &operator<<(CXSourceRange);
Logger &operator<<(CXString);
diff --git a/tools/libclang/CXLoadedDiagnostic.cpp b/tools/libclang/CXLoadedDiagnostic.cpp
index 766ea3480a..b02fdd6ff1 100644
--- a/tools/libclang/CXLoadedDiagnostic.cpp
+++ b/tools/libclang/CXLoadedDiagnostic.cpp
@@ -423,7 +423,7 @@ LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) {
return Failure;
}
if (Record[0] > MaxSupportedVersion) {
- reportInvalidFile("diagnosics file is a newer version than the one "
+ reportInvalidFile("diagnostics file is a newer version than the one "
"supported");
return Failure;
}
diff --git a/tools/libclang/CursorVisitor.h b/tools/libclang/CursorVisitor.h
index 38b7f334ad..53d864d942 100644
--- a/tools/libclang/CursorVisitor.h
+++ b/tools/libclang/CursorVisitor.h
@@ -116,7 +116,7 @@ private:
/// \param R a half-open source range retrieved from the abstract syntax tree.
RangeComparisonResult CompareRegionOfInterest(SourceRange R);
- void visitDeclsFromFileRegion(FileID File, unsigned Offset, unsigned Length);
+ bool visitDeclsFromFileRegion(FileID File, unsigned Offset, unsigned Length);
class SetParentRAII {
CXCursor &Parent;
@@ -179,7 +179,7 @@ public:
/// \brief Visit declarations and preprocessed entities for the file region
/// designated by \see RegionOfInterest.
- void visitFileRegion();
+ bool visitFileRegion();
bool visitPreprocessedEntitiesInRegion();
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index e0c4db07f4..d99f24ef03 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -98,6 +98,8 @@ clang_equalLocations
clang_equalRanges
clang_equalTypes
clang_executeOnThread
+clang_findIncludesInFile
+clang_findIncludesInFileWithBlock
clang_findReferencesInFile
clang_findReferencesInFileWithBlock
clang_formatDiagnostic
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
index 013c1f692f..4965dbdc7a 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/scan-build
@@ -505,6 +505,7 @@ sub Postprocess {
Diag("Removing directory '$Dir' because it contains no reports.\n");
system ("rm", "-fR", $Dir);
}
+ Diag("No bugs found.\n");
return 0;
}
diff --git a/unittests/AST/CommentLexer.cpp b/unittests/AST/CommentLexer.cpp
index 7c8456b2dd..507daf8391 100644
--- a/unittests/AST/CommentLexer.cpp
+++ b/unittests/AST/CommentLexer.cpp
@@ -301,8 +301,10 @@ TEST_F(CommentLexerTest, DoxygenCommand3) {
// Doxygen escape sequences.
TEST_F(CommentLexerTest, DoxygenCommand4) {
- const char *Source =
- "/// \\\\ \\@ \\& \\$ \\# \\< \\> \\% \\\" \\. \\::";
+ const char *Sources[] = {
+ "/// \\\\ \\@ \\& \\$ \\# \\< \\> \\% \\\" \\. \\::",
+ "/// @\\ @@ @& @$ @# @< @> @% @\" @. @::"
+ };
const char *Text[] = {
" ",
"\\", " ", "@", " ", "&", " ", "$", " ", "#", " ",
@@ -310,16 +312,18 @@ TEST_F(CommentLexerTest, DoxygenCommand4) {
"::", ""
};
- std::vector<Token> Toks;
+ for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
+ std::vector<Token> Toks;
- lexString(Source, Toks);
+ lexString(Sources[i], Toks);
- ASSERT_EQ(array_lengthof(Text), Toks.size());
+ ASSERT_EQ(array_lengthof(Text), Toks.size());
- for (size_t i = 0, e = Toks.size(); i != e; i++) {
- if(Toks[i].is(tok::text))
- ASSERT_EQ(StringRef(Text[i]), Toks[i].getText())
- << "index " << i;
+ for (size_t j = 0, e = Toks.size(); j != e; j++) {
+ if(Toks[j].is(tok::text))
+ ASSERT_EQ(StringRef(Text[j]), Toks[j].getText())
+ << "index " << i;
+ }
}
}
@@ -362,7 +366,7 @@ TEST_F(CommentLexerTest, DoxygenCommand6) {
ASSERT_EQ(tok::text, Toks[0].getKind());
ASSERT_EQ(StringRef(" "), Toks[0].getText());
- ASSERT_EQ(tok::command, Toks[1].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[1].getKind());
ASSERT_EQ(StringRef("brief"), getCommandName(Toks[1]));
ASSERT_EQ(tok::text, Toks[2].getKind());
@@ -382,28 +386,60 @@ TEST_F(CommentLexerTest, DoxygenCommand7) {
ASSERT_EQ(tok::text, Toks[0].getKind());
ASSERT_EQ(StringRef(" "), Toks[0].getText());
- ASSERT_EQ(tok::command, Toks[1].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[1].getKind());
ASSERT_EQ(StringRef("em"), getCommandName(Toks[1]));
- ASSERT_EQ(tok::command, Toks[2].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[2].getKind());
ASSERT_EQ(StringRef("em"), getCommandName(Toks[2]));
ASSERT_EQ(tok::text, Toks[3].getKind());
ASSERT_EQ(StringRef(" "), Toks[3].getText());
- ASSERT_EQ(tok::command, Toks[4].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[4].getKind());
ASSERT_EQ(StringRef("em"), getCommandName(Toks[4]));
ASSERT_EQ(tok::text, Toks[5].getKind());
ASSERT_EQ(StringRef("\t"), Toks[5].getText());
- ASSERT_EQ(tok::command, Toks[6].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[6].getKind());
ASSERT_EQ(StringRef("em"), getCommandName(Toks[6]));
ASSERT_EQ(tok::newline, Toks[7].getKind());
}
TEST_F(CommentLexerTest, DoxygenCommand8) {
+ const char *Source = "/// @em@em @em\t@em\n";
+ std::vector<Token> Toks;
+
+ lexString(Source, Toks);
+
+ ASSERT_EQ(8U, Toks.size());
+
+ ASSERT_EQ(tok::text, Toks[0].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[0].getText());
+
+ ASSERT_EQ(tok::at_command, Toks[1].getKind());
+ ASSERT_EQ(StringRef("em"), getCommandName(Toks[1]));
+
+ ASSERT_EQ(tok::at_command, Toks[2].getKind());
+ ASSERT_EQ(StringRef("em"), getCommandName(Toks[2]));
+
+ ASSERT_EQ(tok::text, Toks[3].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[3].getText());
+
+ ASSERT_EQ(tok::at_command, Toks[4].getKind());
+ ASSERT_EQ(StringRef("em"), getCommandName(Toks[4]));
+
+ ASSERT_EQ(tok::text, Toks[5].getKind());
+ ASSERT_EQ(StringRef("\t"), Toks[5].getText());
+
+ ASSERT_EQ(tok::at_command, Toks[6].getKind());
+ ASSERT_EQ(StringRef("em"), getCommandName(Toks[6]));
+
+ ASSERT_EQ(tok::newline, Toks[7].getKind());
+}
+
+TEST_F(CommentLexerTest, DoxygenCommand9) {
const char *Source = "/// \\aaa\\bbb \\ccc\t\\ddd\n";
std::vector<Token> Toks;
@@ -435,7 +471,7 @@ TEST_F(CommentLexerTest, DoxygenCommand8) {
ASSERT_EQ(tok::newline, Toks[7].getKind());
}
-TEST_F(CommentLexerTest, DoxygenCommand9) {
+TEST_F(CommentLexerTest, DoxygenCommand10) {
const char *Source = "// \\c\n";
std::vector<Token> Toks;
@@ -446,14 +482,16 @@ TEST_F(CommentLexerTest, DoxygenCommand9) {
ASSERT_EQ(tok::text, Toks[0].getKind());
ASSERT_EQ(StringRef(" "), Toks[0].getText());
- ASSERT_EQ(tok::command, Toks[1].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[1].getKind());
ASSERT_EQ(StringRef("c"), getCommandName(Toks[1]));
ASSERT_EQ(tok::newline, Toks[2].getKind());
}
TEST_F(CommentLexerTest, RegisterCustomBlockCommand) {
- const char *Source = "/// \\NewBlockCommand Aaa.\n";
+ const char *Source =
+ "/// \\NewBlockCommand Aaa.\n"
+ "/// @NewBlockCommand Aaa.\n";
Traits.registerBlockCommand(StringRef("NewBlockCommand"));
@@ -461,18 +499,29 @@ TEST_F(CommentLexerTest, RegisterCustomBlockCommand) {
lexString(Source, Toks);
- ASSERT_EQ(4U, Toks.size());
+ ASSERT_EQ(8U, Toks.size());
- ASSERT_EQ(tok::text, Toks[0].getKind());
- ASSERT_EQ(StringRef(" "), Toks[0].getText());
+ ASSERT_EQ(tok::text, Toks[0].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[0].getText());
- ASSERT_EQ(tok::command, Toks[1].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[1].getKind());
ASSERT_EQ(StringRef("NewBlockCommand"), getCommandName(Toks[1]));
ASSERT_EQ(tok::text, Toks[2].getKind());
ASSERT_EQ(StringRef(" Aaa."), Toks[2].getText());
- ASSERT_EQ(tok::newline, Toks[3].getKind());
+ ASSERT_EQ(tok::newline, Toks[3].getKind());
+
+ ASSERT_EQ(tok::text, Toks[4].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[4].getText());
+
+ ASSERT_EQ(tok::at_command, Toks[5].getKind());
+ ASSERT_EQ(StringRef("NewBlockCommand"), getCommandName(Toks[5]));
+
+ ASSERT_EQ(tok::text, Toks[6].getKind());
+ ASSERT_EQ(StringRef(" Aaa."), Toks[6].getText());
+
+ ASSERT_EQ(tok::newline, Toks[7].getKind());
}
TEST_F(CommentLexerTest, RegisterMultipleBlockCommands) {
@@ -494,7 +543,7 @@ TEST_F(CommentLexerTest, RegisterMultipleBlockCommands) {
ASSERT_EQ(tok::text, Toks[0].getKind());
ASSERT_EQ(StringRef(" "), Toks[0].getText());
- ASSERT_EQ(tok::command, Toks[1].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[1].getKind());
ASSERT_EQ(StringRef("Foo"), getCommandName(Toks[1]));
ASSERT_EQ(tok::newline, Toks[2].getKind());
@@ -502,7 +551,7 @@ TEST_F(CommentLexerTest, RegisterMultipleBlockCommands) {
ASSERT_EQ(tok::text, Toks[3].getKind());
ASSERT_EQ(StringRef(" "), Toks[3].getText());
- ASSERT_EQ(tok::command, Toks[4].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[4].getKind());
ASSERT_EQ(StringRef("Bar"), getCommandName(Toks[4]));
ASSERT_EQ(tok::text, Toks[5].getKind());
@@ -513,7 +562,7 @@ TEST_F(CommentLexerTest, RegisterMultipleBlockCommands) {
ASSERT_EQ(tok::text, Toks[7].getKind());
ASSERT_EQ(StringRef(" "), Toks[7].getText());
- ASSERT_EQ(tok::command, Toks[8].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[8].getKind());
ASSERT_EQ(StringRef("Blech"), getCommandName(Toks[8]));
ASSERT_EQ(tok::text, Toks[9].getKind());
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index 53620a0294..32f846d925 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -313,6 +313,13 @@ TEST(DeclarationMatcher, ClassIsDerived) {
recordDecl(isDerivedFrom(recordDecl(hasName("X")).bind("test")))));
}
+TEST(DeclarationMatcher, hasMethod) {
+ EXPECT_TRUE(matches("class A { void func(); };",
+ recordDecl(hasMethod(hasName("func")))));
+ EXPECT_TRUE(notMatches("class A { void func(); };",
+ recordDecl(hasMethod(isPublic()))));
+}
+
TEST(DeclarationMatcher, ClassDerivedFromDependentTemplateSpecialization) {
EXPECT_TRUE(matches(
"template <typename T> struct A {"
@@ -1022,6 +1029,12 @@ TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) {
"bool operator&&(Y x, Y y) { return true; }; "
"Y a; Y b; bool c = a && b;",
OpCallLessLess));
+ DeclarationMatcher ClassWithOpStar =
+ recordDecl(hasMethod(hasOverloadedOperatorName("*")));
+ EXPECT_TRUE(matches("class Y { int operator*(); };",
+ ClassWithOpStar));
+ EXPECT_TRUE(notMatches("class Y { void myOperator(); };",
+ ClassWithOpStar)) ;
}
TEST(Matcher, NestedOverloadedOperatorCalls) {
@@ -1329,6 +1342,18 @@ TEST(Matcher, References) {
notMatches("class X {}; void y(X *y) { X *&x = y; }", ReferenceClassX));
}
+TEST(QualType, hasCanonicalType) {
+ EXPECT_TRUE(notMatches("typedef int &int_ref;"
+ "int a;"
+ "int_ref b = a;",
+ varDecl(hasType(qualType(referenceType())))));
+ EXPECT_TRUE(
+ matches("typedef int &int_ref;"
+ "int a;"
+ "int_ref b = a;",
+ varDecl(hasType(qualType(hasCanonicalType(referenceType()))))));
+}
+
TEST(HasParameter, CallsInnerMatcher) {
EXPECT_TRUE(matches("class X { void x(int) {} };",
methodDecl(hasParameter(0, varDecl()))));
@@ -3373,6 +3398,10 @@ TEST(TypeMatching, PointerTypes) {
hasType(pointerType()))));
EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
hasType(referenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(lValueReferenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(rValueReferenceType()))));
Fragment = "int *ptr;";
EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
@@ -3393,6 +3422,54 @@ TEST(TypeMatching, PointerTypes) {
hasType(pointerType()))));
EXPECT_TRUE(matches(Fragment, varDecl(hasName("ref"),
hasType(referenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("ref"),
+ hasType(lValueReferenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(rValueReferenceType()))));
+
+ Fragment = "int &&ref = 2;";
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(blockPointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(memberPointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(pointerType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("ref"),
+ hasType(referenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(lValueReferenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("ref"),
+ hasType(rValueReferenceType()))));
+}
+
+TEST(TypeMatching, AutoRefTypes) {
+ std::string Fragment = "auto a = 1;"
+ "auto b = a;"
+ "auto &c = a;"
+ "auto &&d = c;"
+ "auto &&e = 2;";
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("a"),
+ hasType(referenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("b"),
+ hasType(referenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("c"),
+ hasType(referenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("c"),
+ hasType(lValueReferenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("c"),
+ hasType(rValueReferenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("d"),
+ hasType(referenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("d"),
+ hasType(lValueReferenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("d"),
+ hasType(rValueReferenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("e"),
+ hasType(referenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("e"),
+ hasType(lValueReferenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("e"),
+ hasType(rValueReferenceType()))));
}
TEST(TypeMatching, PointeeTypes) {
@@ -3469,6 +3546,10 @@ TEST(ElaboratedTypeNarrowing, hasQualifier) {
"}"
"M::D d;",
elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N")))))));
+ EXPECT_TRUE(notMatches(
+ "struct D {"
+ "} d;",
+ elaboratedType(hasQualifier(nestedNameSpecifier()))));
}
TEST(ElaboratedTypeNarrowing, namesType) {
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 02c749337e..5cab6f96f3 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -166,6 +166,39 @@ TEST_F(FormatTest, OnlyGeneratesNecessaryReplacements) {
TEST_F(FormatTest, RemovesTrailingWhitespaceOfFormattedLine) {
EXPECT_EQ("int a;\nint b;", format("int a; \nint b;", 0, 0, getLLVMStyle()));
+ EXPECT_EQ("int a;", format("int a; "));
+ EXPECT_EQ("int a;\n", format("int a; \n \n \n "));
+ EXPECT_EQ("int a;\nint b; ",
+ format("int a; \nint b; ", 0, 0, getLLVMStyle()));
+}
+
+TEST_F(FormatTest, FormatsCorrectRegionForLeadingWhitespace) {
+ EXPECT_EQ("int b;\nint a;",
+ format("int b;\n int a;", 7, 0, getLLVMStyle()));
+ EXPECT_EQ("int b;\n int a;",
+ format("int b;\n int a;", 6, 0, getLLVMStyle()));
+
+ EXPECT_EQ("#define A \\\n"
+ " int a; \\\n"
+ " int b;",
+ format("#define A \\\n"
+ " int a; \\\n"
+ " int b;",
+ 26, 0, getLLVMStyleWithColumns(12)));
+ EXPECT_EQ("#define A \\\n"
+ " int a; \\\n"
+ " int b;",
+ format("#define A \\\n"
+ " int a; \\\n"
+ " int b;",
+ 25, 0, getLLVMStyleWithColumns(12)));
+}
+
+TEST_F(FormatTest, RemovesWhitespaceWhenTriggeredOnEmptyLine) {
+ EXPECT_EQ("int a;\n\n int b;",
+ format("int a;\n \n\n int b;", 7, 0, getLLVMStyle()));
+ EXPECT_EQ("int a;\n\n int b;",
+ format("int a;\n \n\n int b;", 9, 0, getLLVMStyle()));
}
TEST_F(FormatTest, ReformatsMovedLines) {
@@ -390,6 +423,10 @@ TEST_F(FormatTest, FormatsSwitchStatement) {
"}");
verifyFormat("switch (test)\n"
" ;");
+ verifyFormat("switch (x) {\n"
+ "default: {\n"
+ " // Do nothing.\n"
+ "}");
verifyGoogleFormat("switch (x) {\n"
" case 1:\n"
@@ -537,6 +574,13 @@ TEST_F(FormatTest, UnderstandsSingleLineComments) {
" aaaaaaaaaaaaaaaaaaaaaa); // 81 cols with this comment");
}
+TEST_F(FormatTest, RemovesTrailingWhitespaceOfComments) {
+ EXPECT_EQ("// comment", format("// comment "));
+ EXPECT_EQ("int aaaaaaa, bbbbbbb; // comment",
+ format("int aaaaaaa, bbbbbbb; // comment ",
+ getLLVMStyleWithColumns(33)));
+}
+
TEST_F(FormatTest, UnderstandsMultiLineComments) {
verifyFormat("f(/*test=*/ true);");
EXPECT_EQ(
@@ -612,6 +656,11 @@ TEST_F(FormatTest, CommentsInStaticInitializers) {
"\n"
" b\n"
"};"));
+ verifyFormat("const uint8_t aaaaaaaaaaaaaaaaaaaaaa[0] = {\n"
+ " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // comment\n"
+ " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // comment\n"
+ " 0x00, 0x00, 0x00, 0x00 // comment\n"
+ "};");
}
//===----------------------------------------------------------------------===//
@@ -1189,9 +1238,11 @@ TEST_F(FormatTest, ConstructorInitializers) {
TEST_F(FormatTest, BreaksAsHighAsPossible) {
verifyFormat(
- "if ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaaaaaaaaaaaaa) ||\n"
- " (bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb && bbbbbbbbbbbbbbbbbbbbbbbbbb))\n"
- " f();");
+ "void f() {\n"
+ " if ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaaaaaaaaaaaaa) ||\n"
+ " (bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb && bbbbbbbbbbbbbbbbbbbbbbbbbb))\n"
+ " f();\n"
+ "}");
verifyFormat("if (Intervals[i].getRange().getFirst() <\n"
" Intervals[i - 1].getRange().getLast()) {\n}");
}
@@ -1222,8 +1273,10 @@ TEST_F(FormatTest, BreaksDesireably) {
" (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
verifyFormat(
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ "void f() {\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);\n"
+ "}");
verifyFormat(
"aaaaaa(new Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaaaaaaaaaaa));");
@@ -1319,7 +1372,7 @@ TEST_F(FormatTest, FormatsBuilderPattern) {
" ->aaaaaaaa(aaaaaaaaaaaaaaa);");
verifyFormat(
"aaaaaaaaaaaaaaaaaaa()->aaaaaa(bbbbb)->aaaaaaaaaaaaaaaaaaa( // break\n"
- " aaaaaaaaaaaaaa);");
+ " aaaaaaaaaaaaaa);");
verifyFormat(
"aaaaaaaaaaaaaaaaaaaaaaa *aaaaaaaaa = aaaaaa->aaaaaaaaaaaa()\n"
" ->aaaaaaaaaaaaaaaa(\n"
@@ -1334,6 +1387,10 @@ TEST_F(FormatTest, DoesNotBreakTrailingAnnotation) {
" GUARDED_BY(aaaaaaaaaaaaa);");
verifyFormat("void aaaaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) const\n"
" GUARDED_BY(aaaaaaaaaaaaa) {}");
+ verifyFormat(
+ "void aaaaaaaaaaaaaaaaaa()\n"
+ " __attribute__((aaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaa));");
}
TEST_F(FormatTest, BreaksAccordingToOperatorPrecedence) {
@@ -1796,7 +1853,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyFormat("int main(int argc, char **argv) {}");
verifyFormat("Test::Test(int b) : a(b * b) {}");
verifyIndependentOfContext("f(a, *a);");
- verifyIndependentOfContext("f(*a);");
+ verifyFormat("void g() { f(*a); }");
verifyIndependentOfContext("int a = b * 10;");
verifyIndependentOfContext("int a = 10 * b;");
verifyIndependentOfContext("int a = b * c;");
@@ -1829,6 +1886,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyIndependentOfContext("return sizeof(int **);");
verifyIndependentOfContext("return sizeof(int ******);");
verifyIndependentOfContext("return (int **&)a;");
+ verifyFormat("void f(Type (*parameter)[10]) {}");
verifyGoogleFormat("return sizeof(int**);");
verifyIndependentOfContext("Type **A = static_cast<Type **>(P);");
verifyGoogleFormat("Type** A = static_cast<Type**>(P);");
@@ -1868,7 +1926,7 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyIndependentOfContext("a = &(x + y);");
verifyIndependentOfContext("*(x + y).call();");
verifyIndependentOfContext("&(x + y)->call();");
- verifyIndependentOfContext("&(*I).first");
+ verifyFormat("void f() { &(*I).first; }");
verifyIndependentOfContext("f(b * /* confusing comment */ ++c);");
verifyFormat(
@@ -1893,7 +1951,9 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
verifyIndependentOfContext("A = new SomeType *[Length]();");
verifyGoogleFormat("A = new SomeType* [Length]();");
+}
+TEST_F(FormatTest, AdaptivelyFormatsPointersAndReferences) {
EXPECT_EQ("int *a;\n"
"int *a;\n"
"int *a;",
@@ -1917,6 +1977,21 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
getGoogleStyle()));
}
+TEST_F(FormatTest, UnderstandsRvalueReferences) {
+ verifyFormat("int f(int &&a) {}");
+ verifyFormat("int f(int a, char &&b) {}");
+ verifyFormat("void f() { int &&a = b; }");
+ verifyGoogleFormat("int f(int a, char&& b) {}");
+ verifyGoogleFormat("void f() { int&& a = b; }");
+
+ // FIXME: These require somewhat deeper changes in template arguments
+ // formatting.
+ // verifyIndependentOfContext("A<int &&> a;");
+ // verifyIndependentOfContext("A<int &&, int &&> a;");
+ // verifyGoogleFormat("A<int&&> a;");
+ // verifyGoogleFormat("A<int&&, int&&> a;");
+}
+
TEST_F(FormatTest, FormatsBinaryOperatorsPrecedingEquals) {
verifyFormat("void f() {\n"
" x[aaaaaaaaa -\n"
@@ -1961,12 +2036,13 @@ TEST_F(FormatTest, FormatsCasts) {
}
TEST_F(FormatTest, FormatsFunctionTypes) {
- // FIXME: Determine the cases that need a space after the return type and fix.
verifyFormat("A<bool()> a;");
verifyFormat("A<SomeType()> a;");
verifyFormat("A<void(*)(int, std::string)> a;");
- verifyFormat("int(*func)(void *);");
+ // FIXME: Inconsistent.
+ verifyFormat("int (*func)(void *);");
+ verifyFormat("void f() { int(*func)(void *); }");
}
TEST_F(FormatTest, BreaksLongDeclarations) {
@@ -2994,8 +3070,17 @@ TEST_F(FormatTest, BreakStringLiterals) {
EXPECT_EQ("\"some \"\n"
"\"text\"",
format("\"some text\"", getLLVMStyleWithColumns(7)));
- EXPECT_EQ("\"some text\"",
+ EXPECT_EQ("\"some\"\n"
+ "\" text\"",
format("\"some text\"", getLLVMStyleWithColumns(6)));
+ EXPECT_EQ("\"some\"\n"
+ "\" tex\"\n"
+ "\" and\"",
+ format("\"some tex and\"", getLLVMStyleWithColumns(6)));
+ EXPECT_EQ("\"some\"\n"
+ "\"/tex\"\n"
+ "\"/and\"",
+ format("\"some/tex/and\"", getLLVMStyleWithColumns(6)));
EXPECT_EQ("variable =\n"
" \"long string \"\n"
@@ -3032,6 +3117,57 @@ TEST_F(FormatTest, BreakStringLiterals) {
"aaaaaaaaaaaaaaaaaaaa(\n"
" aaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaa(\"aaa aaaaa aaa aaa aaaaa aaa aaaaa aaa aaa aaaaaa\"));");
+
+ EXPECT_EQ(
+ "\"splitmea\"\n"
+ "\"trandomp\"\n"
+ "\"oint\"",
+ format("\"splitmeatrandompoint\"", getLLVMStyleWithColumns(10)));
+
+ EXPECT_EQ(
+ "\"split/\"\n"
+ "\"pathat/\"\n"
+ "\"slashes\"",
+ format("\"split/pathat/slashes\"", getLLVMStyleWithColumns(10)));
+}
+
+TEST_F(FormatTest, DoNotBreakStringLiteralsInEscapeSequence) {
+ EXPECT_EQ("\"\\a\"",
+ format("\"\\a\"", getLLVMStyleWithColumns(3)));
+ EXPECT_EQ("\"\\\"",
+ format("\"\\\"", getLLVMStyleWithColumns(2)));
+ EXPECT_EQ("\"test\"\n"
+ "\"\\n\"",
+ format("\"test\\n\"", getLLVMStyleWithColumns(7)));
+ EXPECT_EQ("\"tes\\\\\"\n"
+ "\"n\"",
+ format("\"tes\\\\n\"", getLLVMStyleWithColumns(7)));
+ EXPECT_EQ("\"\\\\\\\\\"\n"
+ "\"\\n\"",
+ format("\"\\\\\\\\\\n\"", getLLVMStyleWithColumns(7)));
+ EXPECT_EQ("\"\\uff01\"",
+ format("\"\\uff01\"", getLLVMStyleWithColumns(7)));
+ EXPECT_EQ("\"\\uff01\"\n"
+ "\"test\"",
+ format("\"\\uff01test\"", getLLVMStyleWithColumns(8)));
+ EXPECT_EQ("\"\\Uff01ff02\"",
+ format("\"\\Uff01ff02\"", getLLVMStyleWithColumns(11)));
+ EXPECT_EQ("\"\\x000000000001\"\n"
+ "\"next\"",
+ format("\"\\x000000000001next\"", getLLVMStyleWithColumns(16)));
+ EXPECT_EQ("\"\\x000000000001next\"",
+ format("\"\\x000000000001next\"", getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("\"\\x000000000001\"",
+ format("\"\\x000000000001\"", getLLVMStyleWithColumns(7)));
+ EXPECT_EQ("\"test\"\n"
+ "\"\\000000\"\n"
+ "\"000001\"",
+ format("\"test\\000000000001\"", getLLVMStyleWithColumns(9)));
+ EXPECT_EQ("\"test\\000\"\n"
+ "\"000000001\"",
+ format("\"test\\000000000001\"", getLLVMStyleWithColumns(10)));
+ EXPECT_EQ("R\"(\\x\\x00)\"\n",
+ format("R\"(\\x\\x00)\"\n", getLLVMStyleWithColumns(7)));
}
} // end namespace tooling
diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp
index 5a35875c3e..c453b056d2 100644
--- a/unittests/Tooling/CompilationDatabaseTest.cpp
+++ b/unittests/Tooling/CompilationDatabaseTest.cpp
@@ -391,6 +391,12 @@ TEST(unescapeJsonCommandLine, ParsesQuotedStringWithoutClosingQuote) {
EXPECT_EQ("", Empty[0]);
}
+TEST(unescapeJsonCommandLine, ParsesSingleQuotedString) {
+ std::vector<std::string> Args = unescapeJsonCommandLine("a'\\\\b \\\"c\\\"'");
+ ASSERT_EQ(1ul, Args.size());
+ EXPECT_EQ("a\\b \"c\"", Args[0]);
+}
+
TEST(FixedCompilationDatabase, ReturnsFixedCommandLine) {
std::vector<std::string> CommandLine;
CommandLine.push_back("one");
diff --git a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
index 4dafc2eec9..ebb0427d7c 100644
--- a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
+++ b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
@@ -47,6 +47,9 @@ void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) {
<< Tag.getValueAsBit("IsVerbatimBlockEndCommand") << ", "
<< Tag.getValueAsBit("IsVerbatimLineCommand") << ", "
<< Tag.getValueAsBit("IsDeclarationCommand") << ", "
+ << Tag.getValueAsBit("IsFunctionDeclarationCommand") << ", "
+ << Tag.getValueAsBit("IsRecordLikeDetailCommand") << ", "
+ << Tag.getValueAsBit("IsRecordLikeDeclarationCommand") << ", "
<< /* IsUnknownCommand = */ "0"
<< " }";
if (i + 1 != e)
diff --git a/www/analyzer/faq.html b/www/analyzer/faq.html
index 5c132b57f2..129bfb63bb 100644
--- a/www/analyzer/faq.html
+++ b/www/analyzer/faq.html
@@ -68,13 +68,15 @@ int foo(int *b) {
<img src="images/example_use_assert.png" alt="example use assert">
-<p>You can teach the analyzer facts about your code as well as document it by
-using assertions. In the contrived example above, the analyzer reports an error
-on the path which assumes that the loop is never entered. However, the owner of
-the code might know that the loop is always entered because the input parameter
-<tt>length</tt> is always greater than <tt>0</tt>. The false positive can be
-suppressed by asserting this knowledge, adding <tt>assert(length > 0)</tt> in
-the beginning of the function.</p>
+<p> In the contrived example above, the analyzer has detected that the body of
+the loop is never entered for the case where <tt>length <= 0</tt>. In this
+particular example, you may know that the loop will always be entered because
+the input parameter <tt>length</tt> will be greater than zero in all calls to this
+function. You can teach the analyzer facts about your code as well as document
+it by using assertions. By adding <tt>assert(length > 0)</tt> in the beginning
+of the function, you tell the analyzer that your code is never expecting a zero
+or a negative value, so it won't need to test the correctness of those paths.
+</p>
<pre class="code_example">
int foo(int length) {
diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl
index c1df06053a..1355297e7c 100644
--- a/www/analyzer/latest_checker.html.incl
+++ b/www/analyzer/latest_checker.html.incl
@@ -1 +1 @@
-<b><a href="http://bit.ly/1299Xt3">checker-271.tar.bz2</a></b> (built February 8, 2013)
+<b><a href="https://attache.apple.com/AttacheWeb/dl?id=ATCbb91eedf8edf4c7388549be8f91e810d">checker-272.tar.bz2</a></b> (built March 1, 2013)
diff --git a/www/analyzer/release_notes.html b/www/analyzer/release_notes.html
index c259edd0d5..190695ef85 100644
--- a/www/analyzer/release_notes.html
+++ b/www/analyzer/release_notes.html
@@ -15,6 +15,22 @@
<h1>Release notes for <tt>checker-XXX</tt> builds</h1>
+<h4 id="checker_272">checker-272</h4>
+<p><b>built:</b> March 1, 2013</br>
+ <b>download:</b> <a href="https://attache.apple.com/AttacheWeb/dl?id=ATCbb91eedf8edf4c7388549be8f91e810d">checker-272.tar.bz2</a></p>
+ <p><b>highlights:</b></p>
+ <ul>
+ <li>Better modeling of C++ constructors:
+ <ul>
+ <li>Interprocedural analysis support for constructors of types with trivial destructors</li>
+ <li>Efficient model of trivial copy and move constructors</li>
+ </ul>
+ </li>
+ <li>Better diagnostics for loops that execute 0 times</li>
+ <li>Fixes a linking issue that prevented the checker from running on OS X v10.6 and earlier</li>
+ <li>Fixes for misc. crashes and false positives</li>
+ </ul>
+
<h4 id="checker_271">checker-271</h4>
<p><b>built:</b> February 8, 2013</br>
<b>download:</b> <a href="http://bit.ly/1299Xt3">checker-271.tar.bz2</a></p>
diff --git a/www/comparison.html b/www/comparison.html
index 01b8aea069..e8b14923b6 100644
--- a/www/comparison.html
+++ b/www/comparison.html
@@ -52,7 +52,6 @@
FORTRAN, etc.</li>
<li>GCC supports more targets than LLVM.</li>
<li>GCC is popular and widely adopted.</li>
- <li>GCC does not require a C++ compiler to build it.</li>
</ul>
<p>Pro's of clang vs GCC:</p>
diff --git a/www/compatibility.html b/www/compatibility.html
index de864eda4f..8bfaff191c 100644
--- a/www/compatibility.html
+++ b/www/compatibility.html
@@ -19,10 +19,10 @@
<h1>Language Compatibility</h1>
<!-- ======================================================================= -->
-<p>Clang strives to both conform to current language standards (C99,
- C++98) and also to implement many widely-used extensions available
+<p>Clang strives to both conform to current language standards (up to C11
+ and C++11) and also to implement many widely-used extensions available
in other compilers, so that most correct code will "just work" when
- compiler with Clang. However, Clang is more strict than other
+ compiled with Clang. However, Clang is more strict than other
popular compilers, and may reject incorrect code that other
compilers allow. This page documents common compatibility and
portability issues with Clang to help you understand and fix the
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 1c23ff356a..f063ca9a25 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -38,9 +38,11 @@
<p>Clang provides support for a number of features included in the new <a href="http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=50372">ISO C++ Standard, ISO/IEC 14882:2011</a>. The following table describes which C++11 features have been implemented in Clang and in which Clang versions they became available.</p>
-<p>You can use Clang in C++11 mode either
-with <a href="http://libcxx.llvm.org/">libc++</a> or with gcc's libstdc++.
-Patches are needed to make <a href="libstdc++4.4-clang0x.patch">libstdc++-4.4</a>
+<p>By default, Clang builds C++ code according to the C++98 standard, with many
+C++11 features accepted as extensions. You can use Clang in C++11 mode with the
+<code>-std=c++11</code> option. Clang's C++11 mode can be used
+with <a href="http://libcxx.llvm.org/">libc++</a> or with gcc's libstdc++, but
+patches are needed to make <a href="libstdc++4.4-clang0x.patch">libstdc++-4.4</a>
work with Clang in C++11 mode. Patches are also needed to make
<a href="libstdc++4.6-clang11.patch">libstdc++-4.6</a>,
and <a href="libstdc++4.7-clang11.patch">libstdc++-4.7</a> work with Clang