aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-01-13 20:00:46 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-01-13 20:00:46 +0000
commit0414e226b73ef7952be3ef346c1c802e7f036f54 (patch)
treeff0114c0524108a01707e4101f3224db0d7fd01f
parent97b17066aaac3f1590a809d79abe98fde03821ec (diff)
Vendor import of clang trunk r257626:vendor/clang/clang-trunk-r257626
Notes
Notes: svn path=/vendor/clang/dist/; revision=293840 svn path=/vendor/clang/clang-trunk-r257626/; revision=293841; tag=vendor/clang/clang-trunk-r257626
-rw-r--r--include/clang/AST/ASTContext.h12
-rw-r--r--include/clang/AST/ASTMutationListener.h4
-rw-r--r--include/clang/AST/BuiltinTypes.def2
-rw-r--r--include/clang/AST/Decl.h5
-rw-r--r--include/clang/AST/DeclBase.h9
-rw-r--r--include/clang/AST/Expr.h1
-rw-r--r--include/clang/AST/ExprCXX.h35
-rw-r--r--include/clang/AST/OperationKinds.h6
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h4
-rw-r--r--include/clang/AST/Stmt.h2
-rw-r--r--include/clang/AST/Type.h42
-rw-r--r--include/clang/AST/TypeLoc.h19
-rw-r--r--include/clang/AST/TypeNodes.def1
-rw-r--r--include/clang/ASTMatchers/ASTMatchersInternal.h8
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td1
-rw-r--r--include/clang/Basic/DiagnosticGroups.td1
-rw-r--r--include/clang/Basic/DiagnosticIDs.h2
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td2
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--include/clang/Basic/Specifiers.h5
-rw-r--r--include/clang/Basic/TokenKinds.def7
-rw-r--r--include/clang/Basic/VirtualFileSystem.h5
-rw-r--r--include/clang/CodeGen/BackendUtil.h10
-rw-r--r--include/clang/Driver/Action.h67
-rw-r--r--include/clang/Driver/Compilation.h16
-rw-r--r--include/clang/Driver/Driver.h26
-rw-r--r--include/clang/Driver/Options.td8
-rw-r--r--include/clang/Driver/ToolChain.h2
-rw-r--r--include/clang/Lex/LiteralSupport.h1
-rw-r--r--include/clang/Parse/Parser.h30
-rw-r--r--include/clang/Sema/DeclSpec.h32
-rw-r--r--include/clang/Sema/Lookup.h1
-rw-r--r--include/clang/Sema/Overload.h9
-rw-r--r--include/clang/Sema/Sema.h12
-rw-r--r--include/clang/Serialization/ASTBitCodes.h4
-rw-r--r--include/clang/Serialization/ASTWriter.h1
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h117
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h6
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h28
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h84
-rw-r--r--lib/AST/ASTContext.cpp53
-rw-r--r--lib/AST/ASTDumper.cpp4
-rw-r--r--lib/AST/ASTImporter.cpp8
-rw-r--r--lib/AST/Decl.cpp16
-rw-r--r--lib/AST/DeclBase.cpp7
-rw-r--r--lib/AST/Expr.cpp3
-rw-r--r--lib/AST/ExprCXX.cpp8
-rw-r--r--lib/AST/ExprConstant.cpp7
-rw-r--r--lib/AST/ItaniumMangle.cpp8
-rw-r--r--lib/AST/MicrosoftMangle.cpp9
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp10
-rw-r--r--lib/AST/StmtPrinter.cpp1
-rw-r--r--lib/AST/Type.cpp7
-rw-r--r--lib/AST/TypePrinter.cpp10
-rw-r--r--lib/Basic/Targets.cpp23
-rw-r--r--lib/Basic/VirtualFileSystem.cpp17
-rw-r--r--lib/CodeGen/BackendUtil.cpp49
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp8
-rw-r--r--lib/CodeGen/CGDebugInfo.h1
-rw-r--r--lib/CodeGen/CGExpr.cpp1
-rw-r--r--lib/CodeGen/CGExprAgg.cpp1
-rw-r--r--lib/CodeGen/CGExprComplex.cpp1
-rw-r--r--lib/CodeGen/CGExprConstant.cpp1
-rw-r--r--lib/CodeGen/CGExprScalar.cpp25
-rw-r--r--lib/CodeGen/CGOpenCLRuntime.cpp11
-rw-r--r--lib/CodeGen/CGOpenCLRuntime.h5
-rw-r--r--lib/CodeGen/CGOpenMPRuntime.cpp2
-rw-r--r--lib/CodeGen/CGOpenMPRuntime.h4
-rw-r--r--lib/CodeGen/CodeGenAction.cpp36
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp31
-rw-r--r--lib/CodeGen/CodeGenModule.cpp15
-rw-r--r--lib/CodeGen/CodeGenPGO.cpp2
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp4
-rw-r--r--lib/CodeGen/CoverageMappingGen.cpp20
-rw-r--r--lib/CodeGen/CoverageMappingGen.h4
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp6
-rw-r--r--lib/CodeGen/ObjectFilePCHContainerOperations.cpp19
-rw-r--r--lib/Driver/Action.cpp117
-rw-r--r--lib/Driver/Compilation.cpp8
-rw-r--r--lib/Driver/Driver.cpp214
-rw-r--r--lib/Driver/InputInfo.h33
-rw-r--r--lib/Driver/MSVCToolChain.cpp171
-rw-r--r--lib/Driver/MinGWToolChain.cpp16
-rw-r--r--lib/Driver/ToolChains.cpp11
-rw-r--r--lib/Driver/ToolChains.h3
-rw-r--r--lib/Driver/Tools.cpp57
-rw-r--r--lib/Driver/Tools.h4
-rw-r--r--lib/Edit/RewriteObjCFoundationAPI.cpp3
-rw-r--r--lib/Format/ContinuationIndenter.cpp28
-rw-r--r--lib/Format/Format.cpp8
-rw-r--r--lib/Format/TokenAnnotator.cpp29
-rw-r--r--lib/Format/UnwrappedLineParser.cpp135
-rw-r--r--lib/Format/UnwrappedLineParser.h1
-rw-r--r--lib/Format/WhitespaceManager.cpp58
-rw-r--r--lib/Format/WhitespaceManager.h7
-rw-r--r--lib/Frontend/CompilerInvocation.cpp9
-rw-r--r--lib/Frontend/FrontendActions.cpp20
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp6
-rw-r--r--lib/Headers/altivec.h38
-rw-r--r--lib/Lex/HeaderSearch.cpp3
-rw-r--r--lib/Lex/LiteralSupport.cpp1
-rw-r--r--lib/Lex/Pragma.cpp19
-rw-r--r--lib/Parse/ParseDecl.cpp36
-rw-r--r--lib/Parse/ParseDeclCXX.cpp3
-rw-r--r--lib/Parse/ParseOpenMP.cpp12
-rw-r--r--lib/Parse/ParsePragma.cpp8
-rw-r--r--lib/Parse/ParseStmt.cpp52
-rw-r--r--lib/Parse/Parser.cpp3
-rw-r--r--lib/Sema/DeclSpec.cpp17
-rw-r--r--lib/Sema/SemaCast.cpp2
-rw-r--r--lib/Sema/SemaChecking.cpp19
-rw-r--r--lib/Sema/SemaDecl.cpp81
-rw-r--r--lib/Sema/SemaDeclAttr.cpp48
-rw-r--r--lib/Sema/SemaDeclCXX.cpp5
-rw-r--r--lib/Sema/SemaExpr.cpp88
-rw-r--r--lib/Sema/SemaExprCXX.cpp17
-rw-r--r--lib/Sema/SemaExprObjC.cpp2
-rw-r--r--lib/Sema/SemaLookup.cpp19
-rw-r--r--lib/Sema/SemaOverload.cpp27
-rw-r--r--lib/Sema/SemaTemplate.cpp6
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp2
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp1
-rw-r--r--lib/Sema/SemaType.cpp58
-rw-r--r--lib/Sema/TreeTransform.h39
-rw-r--r--lib/Serialization/ASTCommon.h1
-rw-r--r--lib/Serialization/ASTReader.cpp14
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp15
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp16
-rw-r--r--lib/Serialization/ASTWriter.cpp23
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp2
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp13
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp60
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp18
-rw-r--r--lib/StaticAnalyzer/Core/RangeConstraintManager.cpp4
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp45
-rw-r--r--lib/StaticAnalyzer/Core/SVals.cpp8
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp8
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp8
-rw-r--r--lib/StaticAnalyzer/Core/SymbolManager.cpp36
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp9
-rw-r--r--test/Analysis/inlining/analysis-order.c15
-rw-r--r--test/Analysis/range_casts.c156
-rw-r--r--test/CXX/class/class.mem/p13.cpp4
-rw-r--r--test/CXX/class/class.union/class.union.anon/p1.cpp24
-rw-r--r--test/CXX/class/class.union/class.union.anon/p4.cpp (renamed from test/CXX/class/class.union/p8.cpp)0
-rw-r--r--test/CXX/temp/temp.res/temp.local/p6.cpp67
-rw-r--r--test/CodeGen/builtins-ppc-vsx.c47
-rw-r--r--test/CodeGen/target-data.c4
-rw-r--r--test/CodeGenCXX/builtins-systemz-zvector.cpp50
-rw-r--r--test/CodeGenCXX/mangle-ms.cpp25
-rw-r--r--test/CodeGenCXX/pass-object-size.cpp18
-rw-r--r--test/CodeGenCXX/vector-splat-conversion.cpp54
-rw-r--r--test/CodeGenOpenCL/bool_cast.cl6
-rw-r--r--test/CodeGenOpenCL/pipe_types.cl27
-rw-r--r--test/Driver/amdgpu-toolchain.c2
-rw-r--r--test/Driver/appletvos-version-min.c1
-rw-r--r--test/Driver/arm-xscale.c3
-rw-r--r--test/Driver/cl-options.c9
-rw-r--r--test/Driver/cuda-bad-arch.cu22
-rw-r--r--test/Driver/cuda-options.cu289
-rw-r--r--test/Driver/cuda-unused-arg-warning.cu23
-rw-r--r--test/Driver/debug-options.c2
-rw-r--r--test/Driver/fortran.f956
-rw-r--r--test/Driver/gcc_forward.c13
-rw-r--r--test/Driver/pic.c2
-rw-r--r--test/Driver/wasm-toolchain.c47
-rw-r--r--test/Driver/wasm32-unknown-unknown.cpp20
-rw-r--r--test/Driver/wasm64-unknown-unknown.cpp20
-rw-r--r--test/Index/print-type-declaration.cpp12
-rw-r--r--test/Misc/ast-dump-lookups.cpp21
-rw-r--r--test/Misc/ast-print-char-literal.cpp24
-rw-r--r--test/Modules/Inputs/DebugCXX.h10
-rw-r--r--test/Modules/Inputs/dummy.h4
-rw-r--r--test/Modules/Inputs/using-decl-redecl/a.h3
-rw-r--r--test/Modules/Inputs/using-decl-redecl/d.h1
-rw-r--r--test/Modules/Inputs/using-decl-redecl/module.modulemap5
-rw-r--r--test/Modules/ModuleDebugInfo.cpp18
-rw-r--r--test/Modules/modular_maps.cpp2
-rw-r--r--test/Modules/separate_map_tree.cpp2
-rw-r--r--test/Modules/tag-injection.c18
-rw-r--r--test/Modules/tag-injection.cpp7
-rw-r--r--test/Modules/using-decl-redecl.cpp12
-rw-r--r--test/OpenMP/barrier_ast_print.cpp36
-rw-r--r--test/OpenMP/barrier_messages.cpp8
-rw-r--r--test/OpenMP/cancel_messages.cpp4
-rw-r--r--test/OpenMP/cancellation_point_messages.cpp4
-rw-r--r--test/OpenMP/flush_messages.cpp8
-rw-r--r--test/OpenMP/target_codegen_registration.cpp48
-rw-r--r--test/OpenMP/target_codegen_registration_naming.cpp8
-rw-r--r--test/OpenMP/taskwait_messages.cpp8
-rw-r--r--test/OpenMP/taskyield_messages.cpp8
-rw-r--r--test/OpenMP/threadprivate_messages.cpp3
-rw-r--r--test/PCH/chain-default-argument-instantiation.cpp50
-rw-r--r--test/PCH/cxx-char-literal.cpp19
-rw-r--r--test/PCH/ocl_types.cl18
-rw-r--r--test/PCH/ocl_types.h11
-rw-r--r--test/Sema/bitfield-layout.c186
-rw-r--r--test/Sema/darwin-tls.c17
-rw-r--r--test/Sema/decl-in-prototype.c3
-rw-r--r--test/Sema/integer-overflow.c8
-rw-r--r--test/Sema/pass-object-size.c6
-rw-r--r--test/SemaCUDA/Inputs/cuda.h4
-rw-r--r--test/SemaCUDA/attributes-on-non-cuda.cu (renamed from test/SemaCUDA/attributes.cu)3
-rw-r--r--test/SemaCUDA/bad-attributes.cu49
-rw-r--r--test/SemaCXX/anonymous-union.cpp4
-rw-r--r--test/SemaCXX/conversion.cpp127
-rw-r--r--test/SemaCXX/linkage-invalid-decl.cpp9
-rw-r--r--test/SemaCXX/pass-object-size.cpp14
-rw-r--r--test/SemaOpenCL/invalid-pipes-cl2.0.cl8
-rw-r--r--test/SemaOpenCL/pipes-1.2-negative.cl3
-rw-r--r--test/SemaTemplate/default-arguments-cxx0x.cpp19
-rw-r--r--test/SemaTemplate/temp_arg_template.cpp12
-rw-r--r--tools/CMakeLists.txt4
-rw-r--r--tools/c-index-test/c-index-test.c20
-rw-r--r--tools/libclang/CIndex.cpp4
-rw-r--r--tools/libclang/CXType.cpp6
-rw-r--r--tools/scan-build-py/README.md120
-rw-r--r--tools/scan-build-py/bin/analyze-build17
-rw-r--r--tools/scan-build-py/bin/analyze-c++14
-rw-r--r--tools/scan-build-py/bin/analyze-cc14
-rw-r--r--tools/scan-build-py/bin/intercept-build17
-rw-r--r--tools/scan-build-py/bin/intercept-c++14
-rw-r--r--tools/scan-build-py/bin/intercept-cc14
-rw-r--r--tools/scan-build-py/bin/scan-build17
-rw-r--r--tools/scan-build-py/libear/__init__.py260
-rw-r--r--tools/scan-build-py/libear/config.h.in23
-rw-r--r--tools/scan-build-py/libear/ear.c605
-rw-r--r--tools/scan-build-py/libscanbuild/__init__.py82
-rw-r--r--tools/scan-build-py/libscanbuild/analyze.py502
-rw-r--r--tools/scan-build-py/libscanbuild/clang.py156
-rw-r--r--tools/scan-build-py/libscanbuild/command.py133
-rw-r--r--tools/scan-build-py/libscanbuild/intercept.py359
-rw-r--r--tools/scan-build-py/libscanbuild/report.py530
-rw-r--r--tools/scan-build-py/libscanbuild/resources/scanview.css62
-rw-r--r--tools/scan-build-py/libscanbuild/resources/selectable.js47
-rw-r--r--tools/scan-build-py/libscanbuild/resources/sorttable.js492
-rw-r--r--tools/scan-build-py/libscanbuild/runner.py256
-rw-r--r--tools/scan-build-py/libscanbuild/shell.py66
-rw-r--r--tools/scan-build-py/tests/__init__.py18
-rw-r--r--tools/scan-build-py/tests/functional/__init__.py0
-rw-r--r--tools/scan-build-py/tests/functional/cases/__init__.py71
-rw-r--r--tools/scan-build-py/tests/functional/cases/test_create_cdb.py191
-rw-r--r--tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py50
-rw-r--r--tools/scan-build-py/tests/functional/cases/test_from_cdb.py183
-rw-r--r--tools/scan-build-py/tests/functional/cases/test_from_cmd.py118
-rw-r--r--tools/scan-build-py/tests/functional/exec/CMakeLists.txt32
-rw-r--r--tools/scan-build-py/tests/functional/exec/config.h.in20
-rw-r--r--tools/scan-build-py/tests/functional/exec/main.c307
-rw-r--r--tools/scan-build-py/tests/functional/src/broken-one.c6
-rw-r--r--tools/scan-build-py/tests/functional/src/broken-two.c1
-rw-r--r--tools/scan-build-py/tests/functional/src/build/Makefile42
-rw-r--r--tools/scan-build-py/tests/functional/src/clean-one.c13
-rw-r--r--tools/scan-build-py/tests/functional/src/clean-two.c11
-rw-r--r--tools/scan-build-py/tests/functional/src/compilation_database/build_broken.json.in43
-rw-r--r--tools/scan-build-py/tests/functional/src/compilation_database/build_clean.json.in19
-rw-r--r--tools/scan-build-py/tests/functional/src/compilation_database/build_regular.json.in31
-rw-r--r--tools/scan-build-py/tests/functional/src/emit-one.c23
-rw-r--r--tools/scan-build-py/tests/functional/src/emit-two.c13
-rw-r--r--tools/scan-build-py/tests/functional/src/include/clean-one.h6
-rw-r--r--tools/scan-build-py/tests/functional/src/main.c4
-rw-r--r--tools/scan-build-py/tests/unit/__init__.py24
-rw-r--r--tools/scan-build-py/tests/unit/fixtures.py40
-rw-r--r--tools/scan-build-py/tests/unit/test_analyze.py8
-rw-r--r--tools/scan-build-py/tests/unit/test_clang.py41
-rw-r--r--tools/scan-build-py/tests/unit/test_command.py193
-rw-r--r--tools/scan-build-py/tests/unit/test_intercept.py123
-rw-r--r--tools/scan-build-py/tests/unit/test_report.py146
-rw-r--r--tools/scan-build-py/tests/unit/test_runner.py213
-rw-r--r--tools/scan-build-py/tests/unit/test_shell.py42
-rw-r--r--unittests/AST/SourceLocationTest.cpp38
-rw-r--r--unittests/Basic/VirtualFileSystemTest.cpp75
-rw-r--r--unittests/Format/FormatTest.cpp51
-rw-r--r--unittests/Format/FormatTestJS.cpp61
-rw-r--r--unittests/Format/FormatTestSelective.cpp7
277 files changed, 9481 insertions, 1329 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index b66009e909a1..abf92948bb42 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -131,6 +131,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<AutoType> AutoTypes;
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
llvm::FoldingSet<AttributedType> AttributedTypes;
+ mutable llvm::FoldingSet<PipeType> PipeTypes;
mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
@@ -1079,6 +1080,9 @@ public:
/// blocks.
QualType getBlockDescriptorType() const;
+ /// \brief Return pipe type for the specified type.
+ QualType getPipeType(QualType T) const;
+
/// Gets the struct used to keep track of the extended descriptor for
/// pointer to blocks.
QualType getBlockDescriptorExtendedType() const;
@@ -2279,9 +2283,13 @@ public:
/// \brief Make an APSInt of the appropriate width and signedness for the
/// given \p Value and integer \p Type.
llvm::APSInt MakeIntValue(uint64_t Value, QualType Type) const {
- llvm::APSInt Res(getIntWidth(Type),
- !Type->isSignedIntegerOrEnumerationType());
+ // If Type is a signed integer type larger than 64 bits, we need to be sure
+ // to sign extend Res appropriately.
+ llvm::APSInt Res(64, !Type->isSignedIntegerOrEnumerationType());
Res = Value;
+ unsigned Width = getIntWidth(Type);
+ if (Width != Res.getBitWidth())
+ return Res.extOrTrunc(Width);
return Res;
}
diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h
index 3ff392de11a7..cf3b55d7b2c7 100644
--- a/include/clang/AST/ASTMutationListener.h
+++ b/include/clang/AST/ASTMutationListener.h
@@ -29,6 +29,7 @@ namespace clang {
class ObjCContainerDecl;
class ObjCInterfaceDecl;
class ObjCPropertyDecl;
+ class ParmVarDecl;
class QualType;
class RecordDecl;
class TagDecl;
@@ -88,6 +89,9 @@ public:
/// \brief A function template's definition was instantiated.
virtual void FunctionDefinitionInstantiated(const FunctionDecl *D) {}
+ /// \brief A default argument was instantiated.
+ virtual void DefaultArgumentInstantiated(const ParmVarDecl *D) {}
+
/// \brief A new objc category class was added for an interface.
virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD) {}
diff --git a/include/clang/AST/BuiltinTypes.def b/include/clang/AST/BuiltinTypes.def
index 85e237a2bf04..a08a6839024b 100644
--- a/include/clang/AST/BuiltinTypes.def
+++ b/include/clang/AST/BuiltinTypes.def
@@ -1,4 +1,4 @@
-//===-- BuiltinTypeNodes.def - Metadata about BuiltinTypes ------*- C++ -*-===//
+//===-- BuiltinTypes.def - Metadata about BuiltinTypes ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 046ce70a343b..029c1182f26e 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -2440,10 +2440,9 @@ class IndirectFieldDecl : public ValueDecl,
NamedDecl **Chaining;
unsigned ChainingSize;
- IndirectFieldDecl(DeclContext *DC, SourceLocation L,
+ IndirectFieldDecl(ASTContext &C, DeclContext *DC, SourceLocation L,
DeclarationName N, QualType T,
- NamedDecl **CH, unsigned CHS)
- : ValueDecl(IndirectField, DC, L, N, T), Chaining(CH), ChainingSize(CHS) {}
+ NamedDecl **CH, unsigned CHS);
public:
static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC,
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 05b2a1280fab..2d6e84a68aa5 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -113,6 +113,9 @@ public:
/// Tags, declared with 'struct foo;' and referenced with
/// 'struct foo'. All tags are also types. This is what
/// elaborated-type-specifiers look for in C.
+ /// This also contains names that conflict with tags in the
+ /// same scope but that are otherwise ordinary names (non-type
+ /// template parameters and indirect field declarations).
IDNS_Tag = 0x0002,
/// Types, declared with 'struct foo', typedefs, etc.
@@ -131,7 +134,7 @@ public:
IDNS_Namespace = 0x0010,
/// Ordinary names. In C, everything that's not a label, tag,
- /// or member ends up here.
+ /// member, or function-local extern ends up here.
IDNS_Ordinary = 0x0020,
/// Objective C \@protocol.
@@ -160,7 +163,9 @@ public:
/// This declaration is a function-local extern declaration of a
/// variable or function. This may also be IDNS_Ordinary if it
- /// has been declared outside any function.
+ /// has been declared outside any function. These act mostly like
+ /// invisible friend declarations, but are also visible to unqualified
+ /// lookup within the scope of the declaring function.
IDNS_LocalExtern = 0x0800
};
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 095dd6a1ef34..38733eee82c3 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -1292,6 +1292,7 @@ public:
enum CharacterKind {
Ascii,
Wide,
+ UTF8,
UTF16,
UTF32
};
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 0608abac1fe9..682127498647 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -951,15 +951,9 @@ public:
/// This wraps up a function call argument that was created from the
/// corresponding parameter's default argument, when the call did not
/// explicitly supply arguments for all of the parameters.
-class CXXDefaultArgExpr final
- : public Expr,
- private llvm::TrailingObjects<CXXDefaultArgExpr, Expr *> {
+class CXXDefaultArgExpr final : public Expr {
/// \brief The parameter whose default is being used.
- ///
- /// When the bit is set, the subexpression is stored after the
- /// CXXDefaultArgExpr itself. When the bit is clear, the parameter's
- /// actual default expression is the subexpression.
- llvm::PointerIntPair<ParmVarDecl *, 1, bool> Param;
+ ParmVarDecl *Param;
/// \brief The location where the default argument expression was used.
SourceLocation Loc;
@@ -971,16 +965,7 @@ class CXXDefaultArgExpr final
: param->getDefaultArg()->getType(),
param->getDefaultArg()->getValueKind(),
param->getDefaultArg()->getObjectKind(), false, false, false, false),
- Param(param, false), Loc(Loc) { }
-
- CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *param,
- Expr *SubExpr)
- : Expr(SC, SubExpr->getType(),
- SubExpr->getValueKind(), SubExpr->getObjectKind(),
- false, false, false, false),
- Param(param, true), Loc(Loc) {
- *getTrailingObjects<Expr *>() = SubExpr;
- }
+ Param(param), Loc(Loc) { }
public:
CXXDefaultArgExpr(EmptyShell Empty) : Expr(CXXDefaultArgExprClass, Empty) {}
@@ -992,24 +977,15 @@ public:
return new (C) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param);
}
- // \p Param is the parameter whose default argument is used by this
- // expression, and \p SubExpr is the expression that will actually be used.
- static CXXDefaultArgExpr *Create(const ASTContext &C, SourceLocation Loc,
- ParmVarDecl *Param, Expr *SubExpr);
-
// Retrieve the parameter that the argument was created from.
- const ParmVarDecl *getParam() const { return Param.getPointer(); }
- ParmVarDecl *getParam() { return Param.getPointer(); }
+ const ParmVarDecl *getParam() const { return Param; }
+ ParmVarDecl *getParam() { return Param; }
// Retrieve the actual argument to the function call.
const Expr *getExpr() const {
- if (Param.getInt())
- return *getTrailingObjects<Expr *>();
return getParam()->getDefaultArg();
}
Expr *getExpr() {
- if (Param.getInt())
- return *getTrailingObjects<Expr *>();
return getParam()->getDefaultArg();
}
@@ -1033,7 +1009,6 @@ public:
return child_range(child_iterator(), child_iterator());
}
- friend TrailingObjects;
friend class ASTStmtReader;
friend class ASTStmtWriter;
};
diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h
index 2235c1012fb7..102bbc21edb3 100644
--- a/include/clang/AST/OperationKinds.h
+++ b/include/clang/AST/OperationKinds.h
@@ -185,7 +185,11 @@ enum CastKind {
/// CK_FloatingToBoolean - Floating point to boolean.
/// (bool) f
CK_FloatingToBoolean,
-
+
+ // CK_BooleanToSignedIntegral - Convert a boolean to -1 or 0 for true and
+ // false, respectively.
+ CK_BooleanToSignedIntegral,
+
/// CK_FloatingCast - Casting between floating types of different size.
/// (double) f
/// (float) ld
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index e6f758364a85..0c25a45c1cec 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -978,6 +978,8 @@ DEF_TRAVERSE_TYPE(ObjCObjectPointerType,
DEF_TRAVERSE_TYPE(AtomicType, { TRY_TO(TraverseType(T->getValueType())); })
+DEF_TRAVERSE_TYPE(PipeType, { TRY_TO(TraverseType(T->getElementType())); })
+
#undef DEF_TRAVERSE_TYPE
// ----------------- TypeLoc traversal -----------------
@@ -1206,6 +1208,8 @@ DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType,
DEF_TRAVERSE_TYPELOC(AtomicType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); })
+DEF_TRAVERSE_TYPELOC(PipeType, { TRY_TO(TraverseTypeLoc(TL.getValueLoc())); })
+
#undef DEF_TRAVERSE_TYPELOC
// ----------------- Decl traversal -----------------
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index e48b7dcc28f5..d3950e92cf0d 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -130,7 +130,7 @@ protected:
friend class CharacterLiteral;
unsigned : NumExprBits;
- unsigned Kind : 2;
+ unsigned Kind : 3;
};
enum APFloatSemantics {
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 0c08130da621..d63b2c43d553 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -1721,6 +1721,7 @@ public:
bool isNDRangeT() const; // OpenCL ndrange_t
bool isReserveIDT() const; // OpenCL reserve_id_t
+ bool isPipeType() const; // OpenCL pipe type
bool isOpenCLSpecificType() const; // Any OpenCL specific type
/// Determines if this type, which must satisfy
@@ -5015,6 +5016,41 @@ class AtomicType : public Type, public llvm::FoldingSetNode {
}
};
+/// PipeType - OpenCL20.
+class PipeType : public Type, public llvm::FoldingSetNode {
+ QualType ElementType;
+
+ PipeType(QualType elemType, QualType CanonicalPtr) :
+ Type(Pipe, CanonicalPtr, elemType->isDependentType(),
+ elemType->isInstantiationDependentType(),
+ elemType->isVariablyModifiedType(),
+ elemType->containsUnexpandedParameterPack()),
+ ElementType(elemType) {}
+ friend class ASTContext; // ASTContext creates these.
+
+public:
+
+ QualType getElementType() const { return ElementType; }
+
+ bool isSugared() const { return false; }
+
+ QualType desugar() const { return QualType(this, 0); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getElementType());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, QualType T) {
+ ID.AddPointer(T.getAsOpaquePtr());
+ }
+
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == Pipe;
+ }
+
+};
+
/// A qualifier set is used to build a set of qualifiers.
class QualifierCollector : public Qualifiers {
public:
@@ -5461,9 +5497,13 @@ inline bool Type::isImageType() const {
isImage1dBufferT();
}
+inline bool Type::isPipeType() const {
+ return isa<PipeType>(CanonicalType);
+}
+
inline bool Type::isOpenCLSpecificType() const {
return isSamplerT() || isEventT() || isImageType() || isClkEventT() ||
- isQueueT() || isNDRangeT() || isReserveIDT();
+ isQueueT() || isNDRangeT() || isReserveIDT() || isPipeType();
}
inline bool Type::isTemplateTypeParmType() const {
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 26feda5d7668..29035a41776e 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -2033,7 +2033,26 @@ public:
}
};
+struct PipeTypeLocInfo {
+ SourceLocation KWLoc;
+};
+
+class PipeTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, PipeTypeLoc, PipeType,
+ PipeTypeLocInfo> {
+public:
+ TypeLoc getValueLoc() const { return this->getInnerTypeLoc(); }
+
+ SourceRange getLocalSourceRange() const { return SourceRange(getKWLoc()); }
+
+ SourceLocation getKWLoc() const { return this->getLocalData()->KWLoc; }
+ void setKWLoc(SourceLocation Loc) { this->getLocalData()->KWLoc = Loc; }
+ void initializeLocal(ASTContext &Context, SourceLocation Loc) {
+ setKWLoc(Loc);
+ }
+
+ QualType getInnerType() const { return this->getTypePtr()->getElementType(); }
+};
}
#endif
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index 2549f0bf50c5..8caf1024142d 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -104,6 +104,7 @@ NON_CANONICAL_UNLESS_DEPENDENT_TYPE(PackExpansion, Type)
TYPE(ObjCObject, Type)
TYPE(ObjCInterface, ObjCObjectType)
TYPE(ObjCObjectPointer, Type)
+TYPE(Pipe, Type)
TYPE(Atomic, Type)
#ifdef LAST_TYPE
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index d49909183fd4..1d1d7952c166 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -560,10 +560,10 @@ bool matchesFirstInPointerRange(const MatcherT &Matcher, IteratorT Start,
// Metafunction to determine if type T has a member called
// getDecl.
-#if defined(_MSC_VER) && (_MSC_VER < 1900) && !defined(__clang__)
-// For old versions of MSVC, we use a weird nonstandard __if_exists
-// statement, since before MSVC2015, it was not standards-conformant
-// enough to compile the usual code below.
+#if defined(_MSC_VER) && !defined(__clang__)
+// For MSVC, we use a weird nonstandard __if_exists statement, as it
+// is not standards-conformant enough to properly compile the standard
+// code below. (At least up through MSVC 2015 require this workaround)
template <typename T> struct has_getDecl {
__if_exists(T::getDecl) {
enum { value = 1 };
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index ce270bfffc69..b04498f3188c 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -22,6 +22,7 @@ def err_drv_unknown_stdin_type_clang_cl : Error<
def err_drv_unknown_language : Error<"language not recognized: '%0'">;
def err_drv_invalid_arch_name : Error<
"invalid arch name '%0'">;
+def err_drv_cuda_bad_gpu_arch : Error<"Unsupported CUDA gpu architecture: %0">;
def err_drv_invalid_thread_model_for_target : Error<
"invalid thread model '%0' in '%1' for this target">;
def err_drv_invalid_linker_name : Error<
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 8e5f57d6d890..2e4e57b63b8e 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -616,6 +616,7 @@ def Most : DiagGroup<"most", [
CharSubscript,
Comment,
DeleteNonVirtualDtor,
+ ForLoopAnalysis,
Format,
Implicit,
InfiniteRecursion,
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index a675dfabe46d..312b71f4064d 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -29,7 +29,7 @@ namespace clang {
enum {
DIAG_START_COMMON = 0,
DIAG_START_DRIVER = DIAG_START_COMMON + 300,
- DIAG_START_FRONTEND = DIAG_START_DRIVER + 100,
+ DIAG_START_FRONTEND = DIAG_START_DRIVER + 200,
DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + 100,
DIAG_START_LEX = DIAG_START_SERIALIZATION + 120,
DIAG_START_PARSE = DIAG_START_LEX + 300,
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index ed6ff20f5c42..2fc9664f49e5 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -490,6 +490,8 @@ def warn_pragma_diagnostic_unknown_warning :
// - #pragma __debug
def warn_pragma_debug_unexpected_command : Warning<
"unexpected debug command '%0'">, InGroup<IgnoredPragmas>;
+def warn_pragma_debug_missing_argument : Warning<
+ "missing argument to debug command '%0'">, InGroup<IgnoredPragmas>;
def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">;
def err_paste_at_start : Error<
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 59f5095d6467..6ba482c78e4a 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1,4 +1,3 @@
-
//==--- DiagnosticSemaKinds.td - libsema diagnostics ----------------------===//
//
// The LLVM Compiler Infrastructure
@@ -7643,6 +7642,10 @@ def err_wrong_sampler_addressspace: Error<
"sampler type cannot be used with the __local and __global address space qualifiers">;
def err_opencl_global_invalid_addr_space : Error<
"program scope variable must reside in %0 address space">;
+def err_missing_actual_pipe_type : Error<
+ "missing actual type specifier for pipe">;
+def err_reference_pipe_type : Error <
+ "pipes packet types cannot be of reference type">;
def err_opencl_no_main : Error<"%select{function|kernel}0 cannot be called 'main'">;
def err_opencl_kernel_attr :
Error<"attribute %0 can only be applied to a kernel function">;
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index 1d59d64d6bc7..e284171f7773 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -36,6 +36,11 @@ namespace clang {
TSS_unsigned
};
+ enum TypeSpecifiersPipe {
+ TSP_unspecified,
+ TSP_pipe
+ };
+
/// \brief Specifies the kind of type.
enum TypeSpecifierType {
TST_unspecified,
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 9252d9947a94..026945141d24 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -519,6 +519,8 @@ KEYWORD(vec_step , KEYOPENCL|KEYALTIVEC|KEYZVECTOR)
// OpenMP Type Traits
KEYWORD(__builtin_omp_required_simd_align, KEYALL)
+KEYWORD(pipe , KEYOPENCL)
+
// Borland Extensions.
KEYWORD(__pascal , KEYALL)
@@ -697,6 +699,11 @@ ANNOTATION(pragma_parser_crash)
// handles them.
ANNOTATION(pragma_captured)
+// Annotation for #pragma clang __debug dump...
+// The lexer produces these so that the parser and semantic analysis can
+// look up and dump the operand.
+ANNOTATION(pragma_dump)
+
// Annotation for #pragma ms_struct...
// The lexer produces these so that they only take effect when the parser
// handles them.
diff --git a/include/clang/Basic/VirtualFileSystem.h b/include/clang/Basic/VirtualFileSystem.h
index 1df4947dd7e8..bab88c90b0a8 100644
--- a/include/clang/Basic/VirtualFileSystem.h
+++ b/include/clang/Basic/VirtualFileSystem.h
@@ -299,10 +299,7 @@ public:
llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
return WorkingDirectory;
}
- std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
- WorkingDirectory = Path.str();
- return std::error_code();
- }
+ std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
};
/// \brief Get a globally unique ID for a virtual file or directory.
diff --git a/include/clang/CodeGen/BackendUtil.h b/include/clang/CodeGen/BackendUtil.h
index ba5dc3939ced..d375a7881313 100644
--- a/include/clang/CodeGen/BackendUtil.h
+++ b/include/clang/CodeGen/BackendUtil.h
@@ -33,12 +33,10 @@ namespace clang {
Backend_EmitObj ///< Emit native object files
};
- void
- EmitBackendOutput(DiagnosticsEngine &Diags, const CodeGenOptions &CGOpts,
- const TargetOptions &TOpts, const LangOptions &LOpts,
- StringRef TDesc, llvm::Module *M, BackendAction Action,
- raw_pwrite_stream *OS,
- std::unique_ptr<llvm::FunctionInfoIndex> Index = nullptr);
+ void EmitBackendOutput(DiagnosticsEngine &Diags, const CodeGenOptions &CGOpts,
+ const TargetOptions &TOpts, const LangOptions &LOpts,
+ StringRef TDesc, llvm::Module *M, BackendAction Action,
+ raw_pwrite_stream *OS);
}
#endif
diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h
index fc31d4b0dec2..c5b0f4755092 100644
--- a/include/clang/Driver/Action.h
+++ b/include/clang/Driver/Action.h
@@ -15,6 +15,9 @@
#include "llvm/ADT/SmallVector.h"
namespace llvm {
+
+class StringRef;
+
namespace opt {
class Arg;
}
@@ -32,6 +35,9 @@ namespace driver {
/// single primary output, at least in terms of controlling the
/// compilation. Actions can produce auxiliary files, but can only
/// produce a single output to feed into subsequent actions.
+///
+/// Actions are usually owned by a Compilation, which creates new
+/// actions via MakeAction().
class Action {
public:
typedef ActionList::size_type size_type;
@@ -70,27 +76,20 @@ private:
ActionList Inputs;
- unsigned OwnsInputs : 1;
-
protected:
- Action(ActionClass Kind, types::ID Type)
- : Kind(Kind), Type(Type), OwnsInputs(true) {}
- Action(ActionClass Kind, std::unique_ptr<Action> Input, types::ID Type)
- : Kind(Kind), Type(Type), Inputs(1, Input.release()), OwnsInputs(true) {
- }
- Action(ActionClass Kind, std::unique_ptr<Action> Input)
- : Kind(Kind), Type(Input->getType()), Inputs(1, Input.release()),
- OwnsInputs(true) {}
+ Action(ActionClass Kind, types::ID Type) : Action(Kind, ActionList(), Type) {}
+ Action(ActionClass Kind, Action *Input, types::ID Type)
+ : Action(Kind, ActionList({Input}), Type) {}
+ Action(ActionClass Kind, Action *Input)
+ : Action(Kind, ActionList({Input}), Input->getType()) {}
Action(ActionClass Kind, const ActionList &Inputs, types::ID Type)
- : Kind(Kind), Type(Type), Inputs(Inputs), OwnsInputs(true) {}
+ : Kind(Kind), Type(Type), Inputs(Inputs) {}
+
public:
virtual ~Action();
const char *getClassName() const { return Action::getClassName(getKind()); }
- bool getOwnsInputs() { return OwnsInputs; }
- void setOwnsInputs(bool Value) { OwnsInputs = Value; }
-
ActionClass getKind() const { return Kind; }
types::ID getType() const { return Type; }
@@ -126,7 +125,7 @@ class BindArchAction : public Action {
const char *ArchName;
public:
- BindArchAction(std::unique_ptr<Action> Input, const char *ArchName);
+ BindArchAction(Action *Input, const char *ArchName);
const char *getArchName() const { return ArchName; }
@@ -137,19 +136,24 @@ public:
class CudaDeviceAction : public Action {
virtual void anchor();
- /// GPU architecture to bind -- e.g 'sm_35'.
+ /// GPU architecture to bind. Always of the form /sm_\d+/.
const char *GpuArchName;
/// True when action results are not consumed by the host action (e.g when
/// -fsyntax-only or --cuda-device-only options are used).
bool AtTopLevel;
public:
- CudaDeviceAction(std::unique_ptr<Action> Input, const char *ArchName,
- bool AtTopLevel);
+ CudaDeviceAction(Action *Input, const char *ArchName, bool AtTopLevel);
const char *getGpuArchName() const { return GpuArchName; }
+
+ /// Gets the compute_XX that corresponds to getGpuArchName().
+ const char *getComputeArchName() const;
+
bool isAtTopLevel() const { return AtTopLevel; }
+ static bool IsValidGpuArchName(llvm::StringRef ArchName);
+
static bool classof(const Action *A) {
return A->getKind() == CudaDeviceClass;
}
@@ -160,9 +164,7 @@ class CudaHostAction : public Action {
ActionList DeviceActions;
public:
- CudaHostAction(std::unique_ptr<Action> Input,
- const ActionList &DeviceActions);
- ~CudaHostAction() override;
+ CudaHostAction(Action *Input, const ActionList &DeviceActions);
const ActionList &getDeviceActions() const { return DeviceActions; }
@@ -172,7 +174,7 @@ public:
class JobAction : public Action {
virtual void anchor();
protected:
- JobAction(ActionClass Kind, std::unique_ptr<Action> Input, types::ID Type);
+ JobAction(ActionClass Kind, Action *Input, types::ID Type);
JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type);
public:
@@ -185,7 +187,7 @@ public:
class PreprocessJobAction : public JobAction {
void anchor() override;
public:
- PreprocessJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
+ PreprocessJobAction(Action *Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == PreprocessJobClass;
@@ -195,7 +197,7 @@ public:
class PrecompileJobAction : public JobAction {
void anchor() override;
public:
- PrecompileJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
+ PrecompileJobAction(Action *Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == PrecompileJobClass;
@@ -205,7 +207,7 @@ public:
class AnalyzeJobAction : public JobAction {
void anchor() override;
public:
- AnalyzeJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
+ AnalyzeJobAction(Action *Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == AnalyzeJobClass;
@@ -215,7 +217,7 @@ public:
class MigrateJobAction : public JobAction {
void anchor() override;
public:
- MigrateJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
+ MigrateJobAction(Action *Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == MigrateJobClass;
@@ -225,7 +227,7 @@ public:
class CompileJobAction : public JobAction {
void anchor() override;
public:
- CompileJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
+ CompileJobAction(Action *Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == CompileJobClass;
@@ -235,7 +237,7 @@ public:
class BackendJobAction : public JobAction {
void anchor() override;
public:
- BackendJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
+ BackendJobAction(Action *Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == BackendJobClass;
@@ -245,7 +247,7 @@ public:
class AssembleJobAction : public JobAction {
void anchor() override;
public:
- AssembleJobAction(std::unique_ptr<Action> Input, types::ID OutputType);
+ AssembleJobAction(Action *Input, types::ID OutputType);
static bool classof(const Action *A) {
return A->getKind() == AssembleJobClass;
@@ -285,8 +287,7 @@ public:
class VerifyJobAction : public JobAction {
void anchor() override;
public:
- VerifyJobAction(ActionClass Kind, std::unique_ptr<Action> Input,
- types::ID Type);
+ VerifyJobAction(ActionClass Kind, Action *Input, types::ID Type);
static bool classof(const Action *A) {
return A->getKind() == VerifyDebugInfoJobClass ||
A->getKind() == VerifyPCHJobClass;
@@ -296,7 +297,7 @@ public:
class VerifyDebugInfoJobAction : public VerifyJobAction {
void anchor() override;
public:
- VerifyDebugInfoJobAction(std::unique_ptr<Action> Input, types::ID Type);
+ VerifyDebugInfoJobAction(Action *Input, types::ID Type);
static bool classof(const Action *A) {
return A->getKind() == VerifyDebugInfoJobClass;
}
@@ -305,7 +306,7 @@ public:
class VerifyPCHJobAction : public VerifyJobAction {
void anchor() override;
public:
- VerifyPCHJobAction(std::unique_ptr<Action> Input, types::ID Type);
+ VerifyPCHJobAction(Action *Input, types::ID Type);
static bool classof(const Action *A) {
return A->getKind() == VerifyPCHJobClass;
}
diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h
index 12ff068d133c..3ed19135043a 100644
--- a/include/clang/Driver/Compilation.h
+++ b/include/clang/Driver/Compilation.h
@@ -48,7 +48,12 @@ class Compilation {
/// own argument translation.
llvm::opt::DerivedArgList *TranslatedArgs;
- /// The list of actions.
+ /// The list of actions we've created via MakeAction. This is not accessible
+ /// to consumers; it's here just to manage ownership.
+ std::vector<std::unique_ptr<Action>> AllActions;
+
+ /// The list of actions. This is maintained and modified by consumers, via
+ /// getActions().
ActionList Actions;
/// The root list of jobs.
@@ -105,6 +110,15 @@ public:
ActionList &getActions() { return Actions; }
const ActionList &getActions() const { return Actions; }
+ /// Creates a new Action owned by this Compilation.
+ ///
+ /// The new Action is *not* added to the list returned by getActions().
+ template <typename T, typename... Args> T *MakeAction(Args &&... Arg) {
+ T *RawPtr = new T(std::forward<Args>(Arg)...);
+ AllActions.push_back(std::unique_ptr<Action>(RawPtr));
+ return RawPtr;
+ }
+
JobList &getJobs() { return Jobs; }
const JobList &getJobs() const { return Jobs; }
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index c9940ba5501f..a229779e1aa1 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -18,10 +18,10 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
-#include "llvm/Support/Path.h" // FIXME: Kill when CompilationInfo
-#include <memory>
- // lands.
+#include "llvm/Support/Path.h" // FIXME: Kill when CompilationInfo lands.
+
#include <list>
+#include <memory>
#include <set>
#include <string>
@@ -375,20 +375,16 @@ public:
/// ConstructAction - Construct the appropriate action to do for
/// \p Phase on the \p Input, taking in to account arguments
/// like -fsyntax-only or --analyze.
- std::unique_ptr<Action>
- ConstructPhaseAction(const ToolChain &TC, const llvm::opt::ArgList &Args,
- phases::ID Phase, std::unique_ptr<Action> Input) const;
+ Action *ConstructPhaseAction(Compilation &C, const ToolChain &TC,
+ const llvm::opt::ArgList &Args, phases::ID Phase,
+ Action *Input) const;
/// BuildJobsForAction - Construct the jobs to perform for the
- /// action \p A.
- void BuildJobsForAction(Compilation &C,
- const Action *A,
- const ToolChain *TC,
- const char *BoundArch,
- bool AtTopLevel,
- bool MultipleArchs,
- const char *LinkingOutput,
- InputInfo &Result) const;
+ /// action \p A and return an InputInfo for the result of running \p A.
+ InputInfo BuildJobsForAction(Compilation &C, const Action *A,
+ const ToolChain *TC, const char *BoundArch,
+ bool AtTopLevel, bool MultipleArchs,
+ const char *LinkingOutput) const;
/// Returns the default name for linked images (e.g., "a.out").
const char *getDefaultImageName() const;
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index e219a9b76b79..e4279e80d847 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -1906,13 +1906,13 @@ def _ : Joined<["--"], "">, Flags<[Unsupported]>;
def mieee_rnd_near : Flag<["-"], "mieee-rnd-near">, Group<m_hexagon_Features_Group>;
def mv4 : Flag<["-"], "mv4">, Group<m_hexagon_Features_Group>,
- Alias<mcpu_EQ>, AliasArgs<["v4"]>;
+ Alias<mcpu_EQ>, AliasArgs<["hexagonv4"]>;
def mv5 : Flag<["-"], "mv5">, Group<m_hexagon_Features_Group>, Alias<mcpu_EQ>,
- AliasArgs<["v5"]>;
+ AliasArgs<["hexagonv5"]>;
def mv55 : Flag<["-"], "mv55">, Group<m_hexagon_Features_Group>,
- Alias<mcpu_EQ>, AliasArgs<["v55"]>;
+ Alias<mcpu_EQ>, AliasArgs<["hexagonv55"]>;
def mv60 : Flag<["-"], "mv60">, Group<m_hexagon_Features_Group>,
- Alias<mcpu_EQ>, AliasArgs<["v60"]>;
+ Alias<mcpu_EQ>, AliasArgs<["hexagonv60"]>;
def mhexagon_hvx : Flag<["-"], "mhvx">, Group<m_hexagon_Features_Group>,
Flags<[CC1Option]>, HelpText<"Enable Hexagon Vector eXtensions">;
def mno_hexagon_hvx : Flag<["-"], "mno-hvx">, Group<m_hexagon_Features_Group>,
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index ed73107940ce..7e68d0a59a09 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -134,7 +134,7 @@ public:
StringRef getOS() const { return Triple.getOSName(); }
/// \brief Provide the default architecture name (as expected by -arch) for
- /// this toolchain. Note t
+ /// this toolchain.
StringRef getDefaultUniversalArchName() const;
std::string getTripleString() const {
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index 5210e3f2e1c5..d568614e2ae4 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -166,6 +166,7 @@ public:
bool hadError() const { return HadError; }
bool isAscii() const { return Kind == tok::char_constant; }
bool isWide() const { return Kind == tok::wide_char_constant; }
+ bool isUTF8() const { return Kind == tok::utf8_char_constant; }
bool isUTF16() const { return Kind == tok::utf16_char_constant; }
bool isUTF32() const { return Kind == tok::utf32_char_constant; }
bool isMultiChar() const { return IsMultiChar; }
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 82b779879c20..00885a5c7103 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -502,6 +502,10 @@ private:
void HandlePragmaAlign();
/// \brief Handle the annotation token produced for
+ /// #pragma clang __debug dump...
+ void HandlePragmaDump();
+
+ /// \brief Handle the annotation token produced for
/// #pragma weak id...
void HandlePragmaWeak();
@@ -1640,13 +1644,22 @@ private:
/// A SmallVector of types.
typedef SmallVector<ParsedType, 12> TypeVector;
- StmtResult ParseStatement(SourceLocation *TrailingElseLoc = nullptr);
+ StmtResult ParseStatement(SourceLocation *TrailingElseLoc = nullptr,
+ bool AllowOpenMPStandalone = false);
+ enum AllowedContsructsKind {
+ /// \brief Allow any declarations, statements, OpenMP directives.
+ ACK_Any,
+ /// \brief Allow only statements and non-standalone OpenMP directives.
+ ACK_StatementsOpenMPNonStandalone,
+ /// \brief Allow statements and all executable OpenMP directives
+ ACK_StatementsOpenMPAnyExecutable
+ };
StmtResult
- ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement,
+ ParseStatementOrDeclaration(StmtVector &Stmts, AllowedContsructsKind Allowed,
SourceLocation *TrailingElseLoc = nullptr);
StmtResult ParseStatementOrDeclarationAfterAttributes(
StmtVector &Stmts,
- bool OnlyStatement,
+ AllowedContsructsKind Allowed,
SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs);
StmtResult ParseExprStatement();
@@ -1674,7 +1687,8 @@ private:
StmtResult ParseReturnStatement();
StmtResult ParseAsmStatement(bool &msAsm);
StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc);
- StmtResult ParsePragmaLoopHint(StmtVector &Stmts, bool OnlyStatement,
+ StmtResult ParsePragmaLoopHint(StmtVector &Stmts,
+ AllowedContsructsKind Allowed,
SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs);
@@ -2439,11 +2453,13 @@ private:
bool AllowScopeSpecifier);
/// \brief Parses declarative or executable directive.
///
- /// \param StandAloneAllowed true if allowed stand-alone directives,
- /// false - otherwise
+ /// \param Allowed ACK_Any, if any directives are allowed,
+ /// ACK_StatementsOpenMPAnyExecutable - if any executable directives are
+ /// allowed, ACK_StatementsOpenMPNonStandalone - if only non-standalone
+ /// executable directives are allowed.
///
StmtResult
- ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed);
+ ParseOpenMPDeclarativeOrExecutableDirective(AllowedContsructsKind Allowed);
/// \brief Parses clause of kind \a CKind for directive of a kind \a Kind.
///
/// \param DKind Kind of current directive.
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index e9fdb707f277..064d37b2a02b 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -337,6 +337,7 @@ private:
unsigned TypeAltiVecPixel : 1;
unsigned TypeAltiVecBool : 1;
unsigned TypeSpecOwned : 1;
+ unsigned TypeSpecPipe : 1;
// type-qualifiers
unsigned TypeQualifiers : 4; // Bitwise OR of TQ.
@@ -385,6 +386,7 @@ private:
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc;
SourceLocation FS_forceinlineLoc;
SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc, ConceptLoc;
+ SourceLocation TQ_pipeLoc;
WrittenBuiltinSpecs writtenBS;
void SaveWrittenBuiltinSpecs();
@@ -420,6 +422,7 @@ public:
TypeAltiVecPixel(false),
TypeAltiVecBool(false),
TypeSpecOwned(false),
+ TypeSpecPipe(false),
TypeQualifiers(TQ_unspecified),
FS_inline_specified(false),
FS_forceinline_specified(false),
@@ -473,6 +476,7 @@ public:
bool isTypeAltiVecBool() const { return TypeAltiVecBool; }
bool isTypeSpecOwned() const { return TypeSpecOwned; }
bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); }
+ bool isTypeSpecPipe() const { return TypeSpecPipe; }
ParsedType getRepAsType() const {
assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type");
@@ -532,6 +536,7 @@ public:
SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; }
SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; }
SourceLocation getAtomicSpecLoc() const { return TQ_atomicLoc; }
+ SourceLocation getPipeLoc() const { return TQ_pipeLoc; }
/// \brief Clear out all of the type qualifiers.
void ClearTypeQualifiers() {
@@ -540,6 +545,7 @@ public:
TQ_restrictLoc = SourceLocation();
TQ_volatileLoc = SourceLocation();
TQ_atomicLoc = SourceLocation();
+ TQ_pipeLoc = SourceLocation();
}
// function-specifier
@@ -643,6 +649,9 @@ public:
bool SetTypeAltiVecBool(bool isAltiVecBool, SourceLocation Loc,
const char *&PrevSpec, unsigned &DiagID,
const PrintingPolicy &Policy);
+ bool SetTypePipe(bool isPipe, SourceLocation Loc,
+ const char *&PrevSpec, unsigned &DiagID,
+ const PrintingPolicy &Policy);
bool SetTypeSpecError();
void UpdateDeclRep(Decl *Rep) {
assert(isDeclRep((TST) TypeSpecType));
@@ -1081,7 +1090,7 @@ typedef SmallVector<Token, 4> CachedTokens;
/// This is intended to be a small value object.
struct DeclaratorChunk {
enum {
- Pointer, Reference, Array, Function, BlockPointer, MemberPointer, Paren
+ Pointer, Reference, Array, Function, BlockPointer, MemberPointer, Paren, Pipe
} Kind;
/// Loc - The place where this type was defined.
@@ -1409,6 +1418,13 @@ struct DeclaratorChunk {
}
};
+ struct PipeTypeInfo : TypeInfoCommon {
+ /// The access writes.
+ unsigned AccessWrites : 3;
+
+ void destroy() {}
+ };
+
union {
TypeInfoCommon Common;
PointerTypeInfo Ptr;
@@ -1417,6 +1433,7 @@ struct DeclaratorChunk {
FunctionTypeInfo Fun;
BlockPointerTypeInfo Cls;
MemberPointerTypeInfo Mem;
+ PipeTypeInfo PipeInfo;
};
void destroy() {
@@ -1428,6 +1445,7 @@ struct DeclaratorChunk {
case DeclaratorChunk::Array: return Arr.destroy();
case DeclaratorChunk::MemberPointer: return Mem.destroy();
case DeclaratorChunk::Paren: return;
+ case DeclaratorChunk::Pipe: return PipeInfo.destroy();
}
}
@@ -1526,6 +1544,17 @@ struct DeclaratorChunk {
return I;
}
+ /// \brief Return a DeclaratorChunk for a block.
+ static DeclaratorChunk getPipe(unsigned TypeQuals,
+ SourceLocation Loc) {
+ DeclaratorChunk I;
+ I.Kind = Pipe;
+ I.Loc = Loc;
+ I.Cls.TypeQuals = TypeQuals;
+ I.Cls.AttrList = 0;
+ return I;
+ }
+
static DeclaratorChunk getMemberPointer(const CXXScopeSpec &SS,
unsigned TypeQuals,
SourceLocation Loc) {
@@ -2026,6 +2055,7 @@ public:
case DeclaratorChunk::Array:
case DeclaratorChunk::BlockPointer:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
return false;
}
llvm_unreachable("Invalid type chunk");
diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h
index 87c40f0cf206..7efb19f57419 100644
--- a/include/clang/Sema/Lookup.h
+++ b/include/clang/Sema/Lookup.h
@@ -515,6 +515,7 @@ public:
configure();
}
+ void dump();
void print(raw_ostream &);
/// Suppress the diagnostics that would normally fire because of this
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index 20958b057a4f..62437953b35b 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -570,8 +570,8 @@ namespace clang {
/// This conversion candidate is not viable because its result
/// type is not implicitly convertible to the desired type.
ovl_fail_bad_final_conversion,
-
- /// This conversion function template specialization candidate is not
+
+ /// This conversion function template specialization candidate is not
/// viable because the final conversion was not an exact match.
ovl_fail_final_conversion_not_exact,
@@ -582,7 +582,10 @@ namespace clang {
/// This candidate function was not viable because an enable_if
/// attribute disabled it.
- ovl_fail_enable_if
+ ovl_fail_enable_if,
+
+ /// This candidate was not viable because its address could not be taken.
+ ovl_fail_addr_not_available
};
/// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 77d06f2affb7..ffe1ff3b950b 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1269,6 +1269,8 @@ public:
SourceLocation Loc, DeclarationName Entity);
QualType BuildParenType(QualType T);
QualType BuildAtomicType(QualType T, SourceLocation Loc);
+ QualType BuildPipeType(QualType T,
+ SourceLocation Loc);
TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S);
TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy);
@@ -2548,7 +2550,8 @@ public:
MultiExprArg Args,
SourceLocation RParenLoc,
Expr *ExecConfig,
- bool AllowTypoCorrection=true);
+ bool AllowTypoCorrection=true,
+ bool CalleesAddressIsTaken=false);
bool buildOverloadedCallSet(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
MultiExprArg Args, SourceLocation RParenLoc,
@@ -7626,6 +7629,9 @@ public:
void ActOnPragmaMSInitSeg(SourceLocation PragmaLocation,
StringLiteral *SegmentName);
+ /// \brief Called on #pragma clang __debug dump II
+ void ActOnPragmaDump(Scope *S, SourceLocation Loc, IdentifierInfo *II);
+
/// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch
void ActOnPragmaDetectMismatch(StringRef Name, StringRef Value);
@@ -8583,6 +8589,10 @@ public:
bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty,
CastKind &Kind);
+ /// \brief Prepare `SplattedExpr` for a vector splat operation, adding
+ /// implicit casts if necessary.
+ ExprResult prepareVectorSplat(QualType VectorTy, Expr *SplattedExpr);
+
// CheckExtVectorCast - check type constraints for extended vectors.
// Since vectors are an extension, there are no C standard reference for this.
// We allow casting between vectors and integer datatypes of the same size,
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 16bda6ea03c1..0dfb8cf37146 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -907,7 +907,9 @@ namespace clang {
/// \brief A DecayedType record.
TYPE_DECAYED = 41,
/// \brief An AdjustedType record.
- TYPE_ADJUSTED = 42
+ TYPE_ADJUSTED = 42,
+ /// \brief A PipeType record.
+ TYPE_PIPE = 43
};
/// \brief The type IDs for special types constructed by semantic
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index ed345472fc7d..ef8c65341388 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -871,6 +871,7 @@ public:
const FunctionDecl *Delete) override;
void CompletedImplicitDefinition(const FunctionDecl *D) override;
void StaticDataMemberInstantiated(const VarDecl *D) override;
+ void DefaultArgumentInstantiated(const ParmVarDecl *D) override;
void FunctionDefinitionInstantiated(const FunctionDecl *D) override;
void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD) override;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index bb835c4c565e..43f6e5cda0dc 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -80,7 +80,7 @@ class MemRegion : public llvm::FoldingSetNode {
public:
enum Kind {
// Memory spaces.
- GenericMemSpaceRegionKind,
+ CodeSpaceRegionKind,
StackLocalsSpaceRegionKind,
StackArgumentsSpaceRegionKind,
HeapSpaceRegionKind,
@@ -89,29 +89,29 @@ public:
GlobalInternalSpaceRegionKind,
GlobalSystemSpaceRegionKind,
GlobalImmutableSpaceRegionKind,
- BEG_NON_STATIC_GLOBAL_MEMSPACES = GlobalInternalSpaceRegionKind,
+ BEGIN_NON_STATIC_GLOBAL_MEMSPACES = GlobalInternalSpaceRegionKind,
END_NON_STATIC_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind,
- BEG_GLOBAL_MEMSPACES = StaticGlobalSpaceRegionKind,
+ BEGIN_GLOBAL_MEMSPACES = StaticGlobalSpaceRegionKind,
END_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind,
- BEG_MEMSPACES = GenericMemSpaceRegionKind,
+ BEGIN_MEMSPACES = CodeSpaceRegionKind,
END_MEMSPACES = GlobalImmutableSpaceRegionKind,
// Untyped regions.
SymbolicRegionKind,
AllocaRegionKind,
// Typed regions.
- BEG_TYPED_REGIONS,
- FunctionTextRegionKind = BEG_TYPED_REGIONS,
- BlockTextRegionKind,
+ BEGIN_TYPED_REGIONS,
+ FunctionCodeRegionKind = BEGIN_TYPED_REGIONS,
+ BlockCodeRegionKind,
BlockDataRegionKind,
- BEG_TYPED_VALUE_REGIONS,
- CompoundLiteralRegionKind = BEG_TYPED_VALUE_REGIONS,
+ BEGIN_TYPED_VALUE_REGIONS,
+ CompoundLiteralRegionKind = BEGIN_TYPED_VALUE_REGIONS,
CXXThisRegionKind,
StringRegionKind,
ObjCStringRegionKind,
ElementRegionKind,
// Decl Regions.
- BEG_DECL_REGIONS,
- VarRegionKind = BEG_DECL_REGIONS,
+ BEGIN_DECL_REGIONS,
+ VarRegionKind = BEGIN_DECL_REGIONS,
FieldRegionKind,
ObjCIvarRegionKind,
END_DECL_REGIONS = ObjCIvarRegionKind,
@@ -193,12 +193,9 @@ public:
/// for example, the set of global variables, the stack frame, etc.
class MemSpaceRegion : public MemRegion {
protected:
- friend class MemRegionManager;
-
MemRegionManager *Mgr;
- MemSpaceRegion(MemRegionManager *mgr, Kind k = GenericMemSpaceRegionKind)
- : MemRegion(k), Mgr(mgr) {
+ MemSpaceRegion(MemRegionManager *mgr, Kind k) : MemRegion(k), Mgr(mgr) {
assert(classof(this));
}
@@ -211,10 +208,26 @@ public:
static bool classof(const MemRegion *R) {
Kind k = R->getKind();
- return k >= BEG_MEMSPACES && k <= END_MEMSPACES;
+ return k >= BEGIN_MEMSPACES && k <= END_MEMSPACES;
}
};
-
+
+/// CodeSpaceRegion - The memory space that holds the executable code of
+/// functions and blocks.
+class CodeSpaceRegion : public MemSpaceRegion {
+ friend class MemRegionManager;
+
+ CodeSpaceRegion(MemRegionManager *mgr)
+ : MemSpaceRegion(mgr, CodeSpaceRegionKind) {}
+
+public:
+ void dumpToStream(raw_ostream &os) const override;
+
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == CodeSpaceRegionKind;
+ }
+};
+
class GlobalsSpaceRegion : public MemSpaceRegion {
virtual void anchor();
protected:
@@ -223,7 +236,7 @@ protected:
public:
static bool classof(const MemRegion *R) {
Kind k = R->getKind();
- return k >= BEG_GLOBAL_MEMSPACES && k <= END_GLOBAL_MEMSPACES;
+ return k >= BEGIN_GLOBAL_MEMSPACES && k <= END_GLOBAL_MEMSPACES;
}
};
@@ -259,17 +272,15 @@ public:
/// RegionStoreManager::invalidateRegions (instead of finding all the dependent
/// globals, we invalidate the whole parent region).
class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion {
- friend class MemRegionManager;
-
protected:
NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k)
: GlobalsSpaceRegion(mgr, k) {}
-
+
public:
static bool classof(const MemRegion *R) {
Kind k = R->getKind();
- return k >= BEG_NON_STATIC_GLOBAL_MEMSPACES &&
+ return k >= BEGIN_NON_STATIC_GLOBAL_MEMSPACES &&
k <= END_NON_STATIC_GLOBAL_MEMSPACES;
}
};
@@ -357,7 +368,7 @@ public:
return R->getKind() == UnknownSpaceRegionKind;
}
};
-
+
class StackSpaceRegion : public MemSpaceRegion {
private:
const StackFrameContext *SFC;
@@ -368,18 +379,18 @@ protected:
assert(classof(this));
}
-public:
+public:
const StackFrameContext *getStackFrame() const { return SFC; }
-
+
void Profile(llvm::FoldingSetNodeID &ID) const override;
static bool classof(const MemRegion *R) {
Kind k = R->getKind();
return k >= StackLocalsSpaceRegionKind &&
k <= StackArgumentsSpaceRegionKind;
- }
+ }
};
-
+
class StackLocalsSpaceRegion : public StackSpaceRegion {
virtual void anchor();
friend class MemRegionManager;
@@ -491,7 +502,7 @@ public:
static bool classof(const MemRegion* R) {
unsigned k = R->getKind();
- return k >= BEG_TYPED_REGIONS && k <= END_TYPED_REGIONS;
+ return k >= BEGIN_TYPED_REGIONS && k <= END_TYPED_REGIONS;
}
};
@@ -523,7 +534,7 @@ public:
static bool classof(const MemRegion* R) {
unsigned k = R->getKind();
- return k >= BEG_TYPED_VALUE_REGIONS && k <= END_TYPED_VALUE_REGIONS;
+ return k >= BEGIN_TYPED_VALUE_REGIONS && k <= END_TYPED_VALUE_REGIONS;
}
};
@@ -538,16 +549,16 @@ public:
static bool classof(const MemRegion* R) {
Kind k = R->getKind();
- return k >= FunctionTextRegionKind && k <= BlockTextRegionKind;
+ return k >= FunctionCodeRegionKind && k <= BlockCodeRegionKind;
}
};
-/// FunctionTextRegion - A region that represents code texts of function.
-class FunctionTextRegion : public CodeTextRegion {
+/// FunctionCodeRegion - A region that represents code texts of function.
+class FunctionCodeRegion : public CodeTextRegion {
const NamedDecl *FD;
public:
- FunctionTextRegion(const NamedDecl *fd, const MemRegion* sreg)
- : CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {
+ FunctionCodeRegion(const NamedDecl *fd, const MemRegion* sreg)
+ : CodeTextRegion(sreg, FunctionCodeRegionKind), FD(fd) {
assert(isa<ObjCMethodDecl>(fd) || isa<FunctionDecl>(fd));
}
@@ -577,27 +588,27 @@ public:
const MemRegion*);
static bool classof(const MemRegion* R) {
- return R->getKind() == FunctionTextRegionKind;
+ return R->getKind() == FunctionCodeRegionKind;
}
};
-/// BlockTextRegion - A region that represents code texts of blocks (closures).
-/// Blocks are represented with two kinds of regions. BlockTextRegions
+/// BlockCodeRegion - A region that represents code texts of blocks (closures).
+/// Blocks are represented with two kinds of regions. BlockCodeRegions
/// represent the "code", while BlockDataRegions represent instances of blocks,
/// which correspond to "code+data". The distinction is important, because
/// like a closure a block captures the values of externally referenced
/// variables.
-class BlockTextRegion : public CodeTextRegion {
+class BlockCodeRegion : public CodeTextRegion {
friend class MemRegionManager;
const BlockDecl *BD;
AnalysisDeclContext *AC;
CanQualType locTy;
- BlockTextRegion(const BlockDecl *bd, CanQualType lTy,
+ BlockCodeRegion(const BlockDecl *bd, CanQualType lTy,
AnalysisDeclContext *ac, const MemRegion* sreg)
- : CodeTextRegion(sreg, BlockTextRegionKind), BD(bd), AC(ac), locTy(lTy) {}
+ : CodeTextRegion(sreg, BlockCodeRegionKind), BD(bd), AC(ac), locTy(lTy) {}
public:
QualType getLocationType() const override {
@@ -619,32 +630,32 @@ public:
const MemRegion*);
static bool classof(const MemRegion* R) {
- return R->getKind() == BlockTextRegionKind;
+ return R->getKind() == BlockCodeRegionKind;
}
};
/// BlockDataRegion - A region that represents a block instance.
-/// Blocks are represented with two kinds of regions. BlockTextRegions
+/// Blocks are represented with two kinds of regions. BlockCodeRegions
/// represent the "code", while BlockDataRegions represent instances of blocks,
/// which correspond to "code+data". The distinction is important, because
/// like a closure a block captures the values of externally referenced
/// variables.
class BlockDataRegion : public TypedRegion {
friend class MemRegionManager;
- const BlockTextRegion *BC;
+ const BlockCodeRegion *BC;
const LocationContext *LC; // Can be null */
unsigned BlockCount;
void *ReferencedVars;
void *OriginalVars;
- BlockDataRegion(const BlockTextRegion *bc, const LocationContext *lc,
+ BlockDataRegion(const BlockCodeRegion *bc, const LocationContext *lc,
unsigned count, const MemRegion *sreg)
: TypedRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc),
BlockCount(count),
ReferencedVars(nullptr), OriginalVars(nullptr) {}
public:
- const BlockTextRegion *getCodeRegion() const { return BC; }
+ const BlockCodeRegion *getCodeRegion() const { return BC; }
const BlockDecl *getDecl() const { return BC->getDecl(); }
@@ -691,7 +702,7 @@ public:
void Profile(llvm::FoldingSetNodeID& ID) const override;
- static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockTextRegion *,
+ static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockCodeRegion *,
const LocationContext *, unsigned,
const MemRegion *);
@@ -856,7 +867,7 @@ public:
static bool classof(const MemRegion* R) {
unsigned k = R->getKind();
- return k >= BEG_DECL_REGIONS && k <= END_DECL_REGIONS;
+ return k >= BEGIN_DECL_REGIONS && k <= END_DECL_REGIONS;
}
};
@@ -1138,7 +1149,7 @@ class MemRegionManager {
HeapSpaceRegion *heap;
UnknownSpaceRegion *unknown;
- MemSpaceRegion *code;
+ CodeSpaceRegion *code;
public:
MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator &a)
@@ -1174,9 +1185,9 @@ public:
/// getUnknownRegion - Retrieve the memory region associated with unknown
/// memory space.
- const MemSpaceRegion *getUnknownRegion();
+ const UnknownSpaceRegion *getUnknownRegion();
- const MemSpaceRegion *getCodeRegion();
+ const CodeSpaceRegion *getCodeRegion();
/// getAllocaRegion - Retrieve a region associated with a call to alloca().
const AllocaRegion *getAllocaRegion(const Expr *Ex, unsigned Cnt,
@@ -1262,8 +1273,8 @@ public:
baseReg->isVirtual());
}
- const FunctionTextRegion *getFunctionTextRegion(const NamedDecl *FD);
- const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD,
+ const FunctionCodeRegion *getFunctionCodeRegion(const NamedDecl *FD);
+ const BlockCodeRegion *getBlockCodeRegion(const BlockDecl *BD,
CanQualType locTy,
AnalysisDeclContext *AC);
@@ -1271,7 +1282,7 @@ public:
/// of a block. Unlike many other MemRegions, the LocationContext*
/// argument is allowed to be NULL for cases where we have no known
/// context.
- const BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc,
+ const BlockDataRegion *getBlockDataRegion(const BlockCodeRegion *bc,
const LocationContext *lc,
unsigned blockCount);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index a68d3410a87b..3c47114e2de2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -83,7 +83,11 @@ public:
}
SVal evalCast(SVal val, QualType castTy, QualType originalType);
-
+
+ // Handles casts of type CK_IntegralCast.
+ SVal evalIntegralCast(ProgramStateRef state, SVal val, QualType castTy,
+ QualType originalType);
+
virtual SVal evalMinus(NonLoc val) = 0;
virtual SVal evalComplement(NonLoc val) = 0;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 642e11af0e6c..d64425412c89 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -45,8 +45,8 @@ class SVal {
public:
enum BaseKind {
// The enumerators must be representable using 2 bits.
- UndefinedKind = 0, // for subclass UndefinedVal (an uninitialized value)
- UnknownKind = 1, // for subclass UnknownVal (a void value)
+ UndefinedValKind = 0, // for subclass UndefinedVal (an uninitialized value)
+ UnknownValKind = 1, // for subclass UnknownVal (a void value)
LocKind = 2, // for subclass Loc (an L-value)
NonLocKind = 3 // for subclass NonLoc (an R-value that's not
// an L-value)
@@ -115,19 +115,19 @@ public:
}
inline bool isUnknown() const {
- return getRawKind() == UnknownKind;
+ return getRawKind() == UnknownValKind;
}
inline bool isUndef() const {
- return getRawKind() == UndefinedKind;
+ return getRawKind() == UndefinedValKind;
}
inline bool isUnknownOrUndef() const {
- return getRawKind() <= UnknownKind;
+ return getRawKind() <= UnknownValKind;
}
inline bool isValid() const {
- return getRawKind() > UnknownKind;
+ return getRawKind() > UnknownValKind;
}
bool isConstant() const;
@@ -190,12 +190,12 @@ public:
class UndefinedVal : public SVal {
public:
- UndefinedVal() : SVal(UndefinedKind) {}
+ UndefinedVal() : SVal(UndefinedValKind) {}
private:
friend class SVal;
static bool isKind(const SVal& V) {
- return V.getBaseKind() == UndefinedKind;
+ return V.getBaseKind() == UndefinedValKind;
}
};
@@ -223,12 +223,12 @@ private:
class UnknownVal : public DefinedOrUnknownSVal {
public:
- explicit UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {}
+ explicit UnknownVal() : DefinedOrUnknownSVal(UnknownValKind) {}
private:
friend class SVal;
static bool isKind(const SVal &V) {
- return V.getBaseKind() == UnknownKind;
+ return V.getBaseKind() == UnknownValKind;
}
};
@@ -465,7 +465,7 @@ private:
namespace loc {
-enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind };
+enum Kind { GotoLabelKind, MemRegionValKind, ConcreteIntKind };
class GotoLabel : public Loc {
public:
@@ -490,7 +490,7 @@ private:
class MemRegionVal : public Loc {
public:
- explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {}
+ explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) {}
/// \brief Get the underlining region.
const MemRegion* getRegion() const {
@@ -518,11 +518,11 @@ private:
MemRegionVal() {}
static bool isKind(const SVal& V) {
return V.getBaseKind() == LocKind &&
- V.getSubKind() == MemRegionKind;
+ V.getSubKind() == MemRegionValKind;
}
static bool isKind(const Loc& V) {
- return V.getSubKind() == MemRegionKind;
+ return V.getSubKind() == MemRegionValKind;
}
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 9dbfab24b417..77d12e5ba666 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -42,14 +42,22 @@ namespace ento {
class SymExpr : public llvm::FoldingSetNode {
virtual void anchor();
public:
- enum Kind { RegionValueKind, ConjuredKind, DerivedKind, ExtentKind,
- MetadataKind,
- BEGIN_SYMBOLS = RegionValueKind,
- END_SYMBOLS = MetadataKind,
- SymIntKind, IntSymKind, SymSymKind,
- BEGIN_BINARYSYMEXPRS = SymIntKind,
- END_BINARYSYMEXPRS = SymSymKind,
- CastSymbolKind };
+ enum Kind {
+ SymbolRegionValueKind,
+ SymbolConjuredKind,
+ SymbolDerivedKind,
+ SymbolExtentKind,
+ SymbolMetadataKind,
+ BEGIN_SYMBOLS = SymbolRegionValueKind,
+ END_SYMBOLS = SymbolMetadataKind,
+ SymIntExprKind,
+ IntSymExprKind,
+ SymSymExprKind,
+ BEGIN_BINARYSYMEXPRS = SymIntExprKind,
+ END_BINARYSYMEXPRS = SymSymExprKind,
+ SymbolCastKind
+ };
+
private:
Kind K;
@@ -126,12 +134,12 @@ class SymbolRegionValue : public SymbolData {
public:
SymbolRegionValue(SymbolID sym, const TypedValueRegion *r)
- : SymbolData(RegionValueKind, sym), R(r) {}
+ : SymbolData(SymbolRegionValueKind, sym), R(r) {}
const TypedValueRegion* getRegion() const { return R; }
static void Profile(llvm::FoldingSetNodeID& profile, const TypedValueRegion* R) {
- profile.AddInteger((unsigned) RegionValueKind);
+ profile.AddInteger((unsigned) SymbolRegionValueKind);
profile.AddPointer(R);
}
@@ -145,7 +153,7 @@ public:
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == RegionValueKind;
+ return SE->getKind() == SymbolRegionValueKind;
}
};
@@ -160,11 +168,9 @@ class SymbolConjured : public SymbolData {
public:
SymbolConjured(SymbolID sym, const Stmt *s, const LocationContext *lctx,
- QualType t, unsigned count,
- const void *symbolTag)
- : SymbolData(ConjuredKind, sym), S(s), T(t), Count(count),
- LCtx(lctx),
- SymbolTag(symbolTag) {}
+ QualType t, unsigned count, const void *symbolTag)
+ : SymbolData(SymbolConjuredKind, sym), S(s), T(t), Count(count),
+ LCtx(lctx), SymbolTag(symbolTag) {}
const Stmt *getStmt() const { return S; }
unsigned getCount() const { return Count; }
@@ -177,7 +183,7 @@ public:
static void Profile(llvm::FoldingSetNodeID& profile, const Stmt *S,
QualType T, unsigned Count, const LocationContext *LCtx,
const void *SymbolTag) {
- profile.AddInteger((unsigned) ConjuredKind);
+ profile.AddInteger((unsigned) SymbolConjuredKind);
profile.AddPointer(S);
profile.AddPointer(LCtx);
profile.Add(T);
@@ -191,7 +197,7 @@ public:
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == ConjuredKind;
+ return SE->getKind() == SymbolConjuredKind;
}
};
@@ -203,7 +209,7 @@ class SymbolDerived : public SymbolData {
public:
SymbolDerived(SymbolID sym, SymbolRef parent, const TypedValueRegion *r)
- : SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {}
+ : SymbolData(SymbolDerivedKind, sym), parentSymbol(parent), R(r) {}
SymbolRef getParentSymbol() const { return parentSymbol; }
const TypedValueRegion *getRegion() const { return R; }
@@ -214,7 +220,7 @@ public:
static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent,
const TypedValueRegion *r) {
- profile.AddInteger((unsigned) DerivedKind);
+ profile.AddInteger((unsigned) SymbolDerivedKind);
profile.AddPointer(r);
profile.AddPointer(parent);
}
@@ -225,7 +231,7 @@ public:
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == DerivedKind;
+ return SE->getKind() == SymbolDerivedKind;
}
};
@@ -237,7 +243,7 @@ class SymbolExtent : public SymbolData {
public:
SymbolExtent(SymbolID sym, const SubRegion *r)
- : SymbolData(ExtentKind, sym), R(r) {}
+ : SymbolData(SymbolExtentKind, sym), R(r) {}
const SubRegion *getRegion() const { return R; }
@@ -246,7 +252,7 @@ public:
void dumpToStream(raw_ostream &os) const override;
static void Profile(llvm::FoldingSetNodeID& profile, const SubRegion *R) {
- profile.AddInteger((unsigned) ExtentKind);
+ profile.AddInteger((unsigned) SymbolExtentKind);
profile.AddPointer(R);
}
@@ -256,7 +262,7 @@ public:
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == ExtentKind;
+ return SE->getKind() == SymbolExtentKind;
}
};
@@ -273,7 +279,7 @@ class SymbolMetadata : public SymbolData {
public:
SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt *s, QualType t,
unsigned count, const void *tag)
- : SymbolData(MetadataKind, sym), R(r), S(s), T(t), Count(count), Tag(tag) {}
+ : SymbolData(SymbolMetadataKind, sym), R(r), S(s), T(t), Count(count), Tag(tag) {}
const MemRegion *getRegion() const { return R; }
const Stmt *getStmt() const { return S; }
@@ -287,7 +293,7 @@ public:
static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion *R,
const Stmt *S, QualType T, unsigned Count,
const void *Tag) {
- profile.AddInteger((unsigned) MetadataKind);
+ profile.AddInteger((unsigned) SymbolMetadataKind);
profile.AddPointer(R);
profile.AddPointer(S);
profile.Add(T);
@@ -301,7 +307,7 @@ public:
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == MetadataKind;
+ return SE->getKind() == SymbolMetadataKind;
}
};
@@ -315,7 +321,7 @@ class SymbolCast : public SymExpr {
public:
SymbolCast(const SymExpr *In, QualType From, QualType To) :
- SymExpr(CastSymbolKind), Operand(In), FromTy(From), ToTy(To) { }
+ SymExpr(SymbolCastKind), Operand(In), FromTy(From), ToTy(To) { }
QualType getType() const override { return ToTy; }
@@ -325,7 +331,7 @@ public:
static void Profile(llvm::FoldingSetNodeID& ID,
const SymExpr *In, QualType From, QualType To) {
- ID.AddInteger((unsigned) CastSymbolKind);
+ ID.AddInteger((unsigned) SymbolCastKind);
ID.AddPointer(In);
ID.Add(From);
ID.Add(To);
@@ -337,7 +343,7 @@ public:
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == CastSymbolKind;
+ return SE->getKind() == SymbolCastKind;
}
};
@@ -372,7 +378,7 @@ class SymIntExpr : public BinarySymExpr {
public:
SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
const llvm::APSInt& rhs, QualType t)
- : BinarySymExpr(SymIntKind, op, t), LHS(lhs), RHS(rhs) {}
+ : BinarySymExpr(SymIntExprKind, op, t), LHS(lhs), RHS(rhs) {}
void dumpToStream(raw_ostream &os) const override;
@@ -382,7 +388,7 @@ public:
static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
BinaryOperator::Opcode op, const llvm::APSInt& rhs,
QualType t) {
- ID.AddInteger((unsigned) SymIntKind);
+ ID.AddInteger((unsigned) SymIntExprKind);
ID.AddPointer(lhs);
ID.AddInteger(op);
ID.AddPointer(&rhs);
@@ -395,7 +401,7 @@ public:
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == SymIntKind;
+ return SE->getKind() == SymIntExprKind;
}
};
@@ -407,7 +413,7 @@ class IntSymExpr : public BinarySymExpr {
public:
IntSymExpr(const llvm::APSInt& lhs, BinaryOperator::Opcode op,
const SymExpr *rhs, QualType t)
- : BinarySymExpr(IntSymKind, op, t), LHS(lhs), RHS(rhs) {}
+ : BinarySymExpr(IntSymExprKind, op, t), LHS(lhs), RHS(rhs) {}
void dumpToStream(raw_ostream &os) const override;
@@ -417,7 +423,7 @@ public:
static void Profile(llvm::FoldingSetNodeID& ID, const llvm::APSInt& lhs,
BinaryOperator::Opcode op, const SymExpr *rhs,
QualType t) {
- ID.AddInteger((unsigned) IntSymKind);
+ ID.AddInteger((unsigned) IntSymExprKind);
ID.AddPointer(&lhs);
ID.AddInteger(op);
ID.AddPointer(rhs);
@@ -430,7 +436,7 @@ public:
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == IntSymKind;
+ return SE->getKind() == IntSymExprKind;
}
};
@@ -442,7 +448,7 @@ class SymSymExpr : public BinarySymExpr {
public:
SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs,
QualType t)
- : BinarySymExpr(SymSymKind, op, t), LHS(lhs), RHS(rhs) {}
+ : BinarySymExpr(SymSymExprKind, op, t), LHS(lhs), RHS(rhs) {}
const SymExpr *getLHS() const { return LHS; }
const SymExpr *getRHS() const { return RHS; }
@@ -451,7 +457,7 @@ public:
static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) {
- ID.AddInteger((unsigned) SymSymKind);
+ ID.AddInteger((unsigned) SymSymExprKind);
ID.AddPointer(lhs);
ID.AddInteger(op);
ID.AddPointer(rhs);
@@ -464,7 +470,7 @@ public:
// Implement isa<T> support.
static inline bool classof(const SymExpr *SE) {
- return SE->getKind() == SymSymKind;
+ return SE->getKind() == SymSymExprKind;
}
};
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index d4abbe47cafb..64386967b220 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1836,6 +1836,13 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
Align = static_cast<unsigned>(Width);
}
}
+ break;
+
+ case Type::Pipe: {
+ TypeInfo Info = getTypeInfo(cast<PipeType>(T)->getElementType());
+ Width = Info.Width;
+ Align = Info.Align;
+ }
}
@@ -2663,6 +2670,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
case Type::FunctionProto:
case Type::BlockPointer:
case Type::MemberPointer:
+ case Type::Pipe:
return type;
// These types can be variably-modified. All these modifications
@@ -3117,6 +3125,32 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
return QualType(FTP, 0);
}
+/// Return pipe type for the specified type.
+QualType ASTContext::getPipeType(QualType T) const {
+ llvm::FoldingSetNodeID ID;
+ PipeType::Profile(ID, T);
+
+ void *InsertPos = 0;
+ if (PipeType *PT = PipeTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(PT, 0);
+
+ // If the pipe element type isn't canonical, this won't be a canonical type
+ // either, so fill in the canonical type field.
+ QualType Canonical;
+ if (!T.isCanonical()) {
+ Canonical = getPipeType(getCanonicalType(T));
+
+ // Get the new insert position for the node we care about.
+ PipeType *NewIP = PipeTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!NewIP && "Shouldn't be in the map!");
+ (void)NewIP;
+ }
+ PipeType *New = new (*this, TypeAlignment) PipeType(T, Canonical);
+ Types.push_back(New);
+ PipeTypes.InsertNode(New, InsertPos);
+ return QualType(New, 0);
+}
+
#ifndef NDEBUG
static bool NeedsInjectedClassNameType(const RecordDecl *D) {
if (!isa<CXXRecordDecl>(D)) return false;
@@ -5857,6 +5891,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
case Type::Auto:
return;
+ case Type::Pipe:
#define ABSTRACT_TYPE(KIND, BASE)
#define TYPE(KIND, BASE)
#define DEPENDENT_TYPE(KIND, BASE) \
@@ -7792,6 +7827,24 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
return QualType();
}
+ case Type::Pipe:
+ {
+ // Merge two pointer types, while trying to preserve typedef info
+ QualType LHSValue = LHS->getAs<PipeType>()->getElementType();
+ QualType RHSValue = RHS->getAs<PipeType>()->getElementType();
+ if (Unqualified) {
+ LHSValue = LHSValue.getUnqualifiedType();
+ RHSValue = RHSValue.getUnqualifiedType();
+ }
+ QualType ResultType = mergeTypes(LHSValue, RHSValue, false,
+ Unqualified);
+ if (ResultType.isNull()) return QualType();
+ if (getCanonicalType(LHSValue) == getCanonicalType(ResultType))
+ return LHS;
+ if (getCanonicalType(RHSValue) == getCanonicalType(ResultType))
+ return RHS;
+ return getPipeType(ResultType);
+ }
}
llvm_unreachable("Invalid Type::Class!");
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index e7fee0316b69..4622a75ac2c6 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -1055,6 +1055,7 @@ void ASTDumper::VisitTypedefDecl(const TypedefDecl *D) {
dumpType(D->getUnderlyingType());
if (D->isModulePrivate())
OS << " __module_private__";
+ dumpTypeAsChild(D->getUnderlyingType());
}
void ASTDumper::VisitEnumDecl(const EnumDecl *D) {
@@ -1226,6 +1227,7 @@ void ASTDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
void ASTDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) {
dumpName(D);
dumpType(D->getUnderlyingType());
+ dumpTypeAsChild(D->getUnderlyingType());
}
void ASTDumper::VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) {
@@ -1419,6 +1421,8 @@ void ASTDumper::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D)
void ASTDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) {
OS << ' ';
dumpBareDeclRef(D->getTargetDecl());
+ if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl()))
+ dumpTypeAsChild(TD->getTypeForDecl());
}
void ASTDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 359db1ba81b3..916f1081798d 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -878,6 +878,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
break;
}
+ case Type::Pipe: {
+ if (!IsStructurallyEquivalent(Context,
+ cast<PipeType>(T1)->getElementType(),
+ cast<PipeType>(T2)->getElementType()))
+ return false;
+ break;
+ }
+
} // end switch
return true;
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 42bebc543e3e..427ca5efcd69 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1184,7 +1184,7 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
return LinkageInfo::none();
const Decl *OuterD = getOutermostFuncOrBlockContext(D);
- if (!OuterD)
+ if (!OuterD || OuterD->isInvalidDecl())
return LinkageInfo::none();
LinkageInfo LV;
@@ -4024,16 +4024,26 @@ EnumConstantDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void IndirectFieldDecl::anchor() { }
+IndirectFieldDecl::IndirectFieldDecl(ASTContext &C, DeclContext *DC,
+ SourceLocation L, DeclarationName N,
+ QualType T, NamedDecl **CH, unsigned CHS)
+ : ValueDecl(IndirectField, DC, L, N, T), Chaining(CH), ChainingSize(CHS) {
+ // In C++, indirect field declarations conflict with tag declarations in the
+ // same scope, so add them to IDNS_Tag so that tag redeclaration finds them.
+ if (C.getLangOpts().CPlusPlus)
+ IdentifierNamespace |= IDNS_Tag;
+}
+
IndirectFieldDecl *
IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, QualType T, NamedDecl **CH,
unsigned CHS) {
- return new (C, DC) IndirectFieldDecl(DC, L, Id, T, CH, CHS);
+ return new (C, DC) IndirectFieldDecl(C, DC, L, Id, T, CH, CHS);
}
IndirectFieldDecl *IndirectFieldDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- return new (C, ID) IndirectFieldDecl(nullptr, SourceLocation(),
+ return new (C, ID) IndirectFieldDecl(C, nullptr, SourceLocation(),
DeclarationName(), QualType(), nullptr,
0);
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 16394e865eb1..72587e388e47 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -569,7 +569,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Var:
case ImplicitParam:
case ParmVar:
- case NonTypeTemplateParm:
case ObjCMethod:
case ObjCProperty:
case MSProperty:
@@ -579,6 +578,12 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case IndirectField:
return IDNS_Ordinary | IDNS_Member;
+ case NonTypeTemplateParm:
+ // Non-type template parameters are not found by lookups that ignore
+ // non-types, but they are found by redeclaration lookups for tag types,
+ // so we include them in the tag namespace.
+ return IDNS_Ordinary | IDNS_Tag;
+
case ObjCCompatibleAlias:
case ObjCInterface:
return IDNS_Ordinary | IDNS_Type;
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index f9757b209294..52f34df43565 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1553,6 +1553,7 @@ bool CastExpr::CastConsistency() const {
case CK_ToVoid:
case CK_VectorSplat:
case CK_IntegralCast:
+ case CK_BooleanToSignedIntegral:
case CK_IntegralToFloating:
case CK_FloatingToIntegral:
case CK_FloatingCast:
@@ -1646,6 +1647,8 @@ const char *CastExpr::getCastKindName() const {
return "VectorSplat";
case CK_IntegralCast:
return "IntegralCast";
+ case CK_BooleanToSignedIntegral:
+ return "BooleanToSignedIntegral";
case CK_IntegralToBoolean:
return "IntegralToBoolean";
case CK_IntegralToFloating:
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index d35efcb101b5..ea983340a293 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -763,14 +763,6 @@ const IdentifierInfo *UserDefinedLiteral::getUDSuffix() const {
return cast<FunctionDecl>(getCalleeDecl())->getLiteralIdentifier();
}
-CXXDefaultArgExpr *
-CXXDefaultArgExpr::Create(const ASTContext &C, SourceLocation Loc,
- ParmVarDecl *Param, Expr *SubExpr) {
- void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(1));
- return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param,
- SubExpr);
-}
-
CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &C, SourceLocation Loc,
FieldDecl *Field, QualType T)
: Expr(CXXDefaultInitExprClass, T.getNonLValueExprType(C),
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index c4c4398c3622..fa652ba1b0ab 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -7781,12 +7781,16 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_PointerToBoolean:
case CK_IntegralToBoolean:
case CK_FloatingToBoolean:
+ case CK_BooleanToSignedIntegral:
case CK_FloatingComplexToBoolean:
case CK_IntegralComplexToBoolean: {
bool BoolResult;
if (!EvaluateAsBooleanCondition(SubExpr, BoolResult, Info))
return false;
- return Success(BoolResult, E);
+ uint64_t IntResult = BoolResult;
+ if (BoolResult && E->getCastKind() == CK_BooleanToSignedIntegral)
+ IntResult = (uint64_t)-1;
+ return Success(IntResult, E);
}
case CK_IntegralCast: {
@@ -8223,6 +8227,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_ToVoid:
case CK_VectorSplat:
case CK_IntegralCast:
+ case CK_BooleanToSignedIntegral:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
case CK_FloatingToIntegral:
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 8018188a6b24..3f6b682f238f 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -1509,6 +1509,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
case Type::ObjCInterface:
case Type::ObjCObjectPointer:
case Type::Atomic:
+ case Type::Pipe:
llvm_unreachable("type is illegal as a nested name specifier");
case Type::SubstTemplateTypeParmPack:
@@ -2682,6 +2683,13 @@ void CXXNameMangler::mangleType(const AtomicType *T) {
mangleType(T->getValueType());
}
+void CXXNameMangler::mangleType(const PipeType *T) {
+ // Pipe type mangling rules are described in SPIR 2.0 specification
+ // A.1 Data types and A.3 Summary of changes
+ // <type> ::= 8ocl_pipe
+ Out << "8ocl_pipe";
+}
+
void CXXNameMangler::mangleIntegerLiteral(QualType T,
const llvm::APSInt &Value) {
// <expr-primary> ::= L <type> <value number> E # integer literal
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index d45232b6deb0..4a45f9e4051f 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -2428,6 +2428,15 @@ void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, Qualifiers,
mangleArtificalTagType(TTK_Struct, TemplateMangling, {"__clang"});
}
+void MicrosoftCXXNameMangler::mangleType(const PipeType *T, Qualifiers,
+ SourceRange Range) {
+ DiagnosticsEngine &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle this OpenCL pipe type yet");
+ Diags.Report(Range.getBegin(), DiagID)
+ << Range;
+}
+
void MicrosoftMangleContextImpl::mangleCXXName(const NamedDecl *D,
raw_ostream &Out) {
assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index bc3c2a831c47..bc5ae0ffc469 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -1552,7 +1552,8 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
FieldAlign = 1;
// But, if there's an 'aligned' attribute on the field, honor that.
- if (unsigned ExplicitFieldAlign = D->getMaxAlignment()) {
+ unsigned ExplicitFieldAlign = D->getMaxAlignment();
+ if (ExplicitFieldAlign) {
FieldAlign = std::max(FieldAlign, ExplicitFieldAlign);
UnpackedFieldAlign = std::max(UnpackedFieldAlign, ExplicitFieldAlign);
}
@@ -1601,6 +1602,10 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
(AllowPadding &&
(FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)) {
FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+ } else if (ExplicitFieldAlign) {
+ // TODO: figure it out what needs to be done on targets that don't honor
+ // bit-field type alignment like ARM APCS ABI.
+ FieldOffset = llvm::RoundUpToAlignment(FieldOffset, ExplicitFieldAlign);
}
// Repeat the computation for diagnostic purposes.
@@ -1609,6 +1614,9 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
(UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize))
UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
UnpackedFieldAlign);
+ else if (ExplicitFieldAlign)
+ UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
+ ExplicitFieldAlign);
}
// If we're using external layout, give the external layout a chance
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index e55b2fc19a1a..69f52f52b669 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1165,6 +1165,7 @@ void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
switch (Node->getKind()) {
case CharacterLiteral::Ascii: break; // no prefix.
case CharacterLiteral::Wide: OS << 'L'; break;
+ case CharacterLiteral::UTF8: OS << "u8"; break;
case CharacterLiteral::UTF16: OS << 'u'; break;
case CharacterLiteral::UTF32: OS << 'U'; break;
}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 7dd38cba229b..b467dac66b57 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -2614,7 +2614,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
case OCLQueue:
return "queue_t";
case OCLNDRange:
- return "event_t";
+ return "ndrange_t";
case OCLReserveID:
return "reserve_id_t";
case OMPArraySection:
@@ -3361,6 +3361,8 @@ static CachedProperties computeCachedProperties(const Type *T) {
return Cache::get(cast<ObjCObjectPointerType>(T)->getPointeeType());
case Type::Atomic:
return Cache::get(cast<AtomicType>(T)->getValueType());
+ case Type::Pipe:
+ return Cache::get(cast<PipeType>(T)->getElementType());
}
llvm_unreachable("unhandled type class");
@@ -3443,6 +3445,8 @@ static LinkageInfo computeLinkageInfo(const Type *T) {
return computeLinkageInfo(cast<ObjCObjectPointerType>(T)->getPointeeType());
case Type::Atomic:
return computeLinkageInfo(cast<AtomicType>(T)->getValueType());
+ case Type::Pipe:
+ return computeLinkageInfo(cast<PipeType>(T)->getElementType());
}
llvm_unreachable("unhandled type class");
@@ -3601,6 +3605,7 @@ bool Type::canHaveNullability() const {
case Type::ObjCObject:
case Type::ObjCInterface:
case Type::Atomic:
+ case Type::Pipe:
return false;
}
llvm_unreachable("bad type kind!");
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 4617e1d3803f..b202523bdaf3 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -193,6 +193,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
case Type::ObjCObject:
case Type::ObjCInterface:
case Type::Atomic:
+ case Type::Pipe:
CanPrefixQualifiers = true;
break;
@@ -859,6 +860,15 @@ void TypePrinter::printAtomicBefore(const AtomicType *T, raw_ostream &OS) {
}
void TypePrinter::printAtomicAfter(const AtomicType *T, raw_ostream &OS) { }
+void TypePrinter::printPipeBefore(const PipeType *T, raw_ostream &OS) {
+ IncludeStrongLifetimeRAII Strong(Policy);
+
+ OS << "pipe";
+ spaceBeforePlaceHolder(OS);
+}
+
+void TypePrinter::printPipeAfter(const PipeType *T, raw_ostream &OS) {
+}
/// Appends the given scope to the end of a string.
void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) {
if (DC->isTranslationUnit()) return;
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 9ce525709cf4..1bc6c51b9b85 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -223,7 +223,24 @@ protected:
public:
DarwinTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {
- this->TLSSupported = Triple.isMacOSX() && !Triple.isMacOSXVersionLT(10, 7);
+ // By default, no TLS, and we whitelist permitted architecture/OS
+ // combinations.
+ this->TLSSupported = false;
+
+ if (Triple.isMacOSX())
+ this->TLSSupported = !Triple.isMacOSXVersionLT(10, 7);
+ else if (Triple.isiOS()) {
+ // 64-bit iOS supported it from 8 onwards, 32-bit from 9 onwards.
+ if (Triple.getArch() == llvm::Triple::x86_64 ||
+ Triple.getArch() == llvm::Triple::aarch64)
+ this->TLSSupported = !Triple.isOSVersionLT(8);
+ else if (Triple.getArch() == llvm::Triple::x86 ||
+ Triple.getArch() == llvm::Triple::arm ||
+ Triple.getArch() == llvm::Triple::thumb)
+ this->TLSSupported = !Triple.isOSVersionLT(9);
+ } else if (Triple.isWatchOS())
+ this->TLSSupported = !Triple.isOSVersionLT(2);
+
this->MCountName = "\01mcount";
}
@@ -7281,7 +7298,7 @@ public:
explicit WebAssembly32TargetInfo(const llvm::Triple &T)
: WebAssemblyTargetInfo(T) {
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
- DataLayoutString = "e-p:32:32-i64:64-n32:64-S128";
+ DataLayoutString = "e-m:e-p:32:32-i64:64-n32:64-S128";
}
protected:
@@ -7299,7 +7316,7 @@ public:
LongAlign = LongWidth = 64;
PointerAlign = PointerWidth = 64;
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
- DataLayoutString = "e-p:64:64-i64:64-n32:64-S128";
+ DataLayoutString = "e-m:e-p:64:64-i64:64-n32:64-S128";
}
protected:
diff --git a/lib/Basic/VirtualFileSystem.cpp b/lib/Basic/VirtualFileSystem.cpp
index cf5a8d681eac..6977f400287f 100644
--- a/lib/Basic/VirtualFileSystem.cpp
+++ b/lib/Basic/VirtualFileSystem.cpp
@@ -658,6 +658,23 @@ directory_iterator InMemoryFileSystem::dir_begin(const Twine &Dir,
EC = make_error_code(llvm::errc::not_a_directory);
return directory_iterator(std::make_shared<InMemoryDirIterator>());
}
+
+std::error_code InMemoryFileSystem::setCurrentWorkingDirectory(const Twine &P) {
+ SmallString<128> Path;
+ P.toVector(Path);
+
+ // Fix up relative paths. This just prepends the current working directory.
+ std::error_code EC = makeAbsolute(Path);
+ assert(!EC);
+ (void)EC;
+
+ if (useNormalizedPaths())
+ llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
+
+ if (!Path.empty())
+ WorkingDirectory = Path.str();
+ return std::error_code();
+}
}
}
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 7032d00386f3..6d746c25eed1 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -28,6 +28,7 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/Object/FunctionIndexObjectFile.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/TargetRegistry.h"
@@ -54,7 +55,6 @@ class EmitAssemblyHelper {
const clang::TargetOptions &TargetOpts;
const LangOptions &LangOpts;
Module *TheModule;
- std::unique_ptr<FunctionInfoIndex> FunctionIndex;
Timer CodeGenerationTime;
@@ -97,7 +97,7 @@ private:
return PerFunctionPasses;
}
- void CreatePasses();
+ void CreatePasses(FunctionInfoIndex *FunctionIndex);
/// Generates the TargetMachine.
/// Returns Null if it is unable to create the target machine.
@@ -117,12 +117,11 @@ private:
public:
EmitAssemblyHelper(DiagnosticsEngine &_Diags, const CodeGenOptions &CGOpts,
const clang::TargetOptions &TOpts,
- const LangOptions &LOpts, Module *M,
- std::unique_ptr<FunctionInfoIndex> Index)
+ const LangOptions &LOpts, Module *M)
: Diags(_Diags), CodeGenOpts(CGOpts), TargetOpts(TOpts), LangOpts(LOpts),
- TheModule(M), FunctionIndex(std::move(Index)),
- CodeGenerationTime("Code Generation Time"), CodeGenPasses(nullptr),
- PerModulePasses(nullptr), PerFunctionPasses(nullptr) {}
+ TheModule(M), CodeGenerationTime("Code Generation Time"),
+ CodeGenPasses(nullptr), PerModulePasses(nullptr),
+ PerFunctionPasses(nullptr) {}
~EmitAssemblyHelper() {
delete CodeGenPasses;
@@ -278,7 +277,7 @@ static void addSymbolRewriterPass(const CodeGenOptions &Opts,
MPM->add(createRewriteSymbolsPass(DL));
}
-void EmitAssemblyHelper::CreatePasses() {
+void EmitAssemblyHelper::CreatePasses(FunctionInfoIndex *FunctionIndex) {
if (CodeGenOpts.DisableLLVMPasses)
return;
@@ -332,9 +331,8 @@ void EmitAssemblyHelper::CreatePasses() {
// If we are performing a ThinLTO importing compile, invoke the LTO
// pipeline and pass down the in-memory function index.
- if (!CodeGenOpts.ThinLTOIndexFile.empty()) {
- assert(FunctionIndex && "Expected non-empty function index");
- PMBuilder.FunctionIndex = FunctionIndex.get();
+ if (FunctionIndex) {
+ PMBuilder.FunctionIndex = FunctionIndex;
PMBuilder.populateLTOPassManager(*MPM);
return;
}
@@ -642,7 +640,28 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action,
return;
if (TM)
TheModule->setDataLayout(TM->createDataLayout());
- CreatePasses();
+
+ // If we are performing a ThinLTO importing compile, load the function
+ // index into memory and pass it into CreatePasses, which will add it
+ // to the PassManagerBuilder and invoke LTO passes.
+ std::unique_ptr<FunctionInfoIndex> FunctionIndex;
+ if (!CodeGenOpts.ThinLTOIndexFile.empty()) {
+ ErrorOr<std::unique_ptr<FunctionInfoIndex>> IndexOrErr =
+ llvm::getFunctionIndexForFile(CodeGenOpts.ThinLTOIndexFile,
+ [&](const DiagnosticInfo &DI) {
+ TheModule->getContext().diagnose(DI);
+ });
+ if (std::error_code EC = IndexOrErr.getError()) {
+ std::string Error = EC.message();
+ errs() << "Error loading index file '" << CodeGenOpts.ThinLTOIndexFile
+ << "': " << Error << "\n";
+ return;
+ }
+ FunctionIndex = std::move(IndexOrErr.get());
+ assert(FunctionIndex && "Expected non-empty function index");
+ }
+
+ CreatePasses(FunctionIndex.get());
switch (Action) {
case Backend_EmitNothing:
@@ -695,10 +714,8 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
const clang::TargetOptions &TOpts,
const LangOptions &LOpts, StringRef TDesc,
Module *M, BackendAction Action,
- raw_pwrite_stream *OS,
- std::unique_ptr<FunctionInfoIndex> Index) {
- EmitAssemblyHelper AsmHelper(Diags, CGOpts, TOpts, LOpts, M,
- std::move(Index));
+ raw_pwrite_stream *OS) {
+ EmitAssemblyHelper AsmHelper(Diags, CGOpts, TOpts, LOpts, M);
AsmHelper.EmitAssembly(Action, OS);
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 78e3978e0ff9..5df85194878d 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -2025,6 +2025,11 @@ llvm::DIType *CGDebugInfo::CreateType(const AtomicType *Ty, llvm::DIFile *U) {
return getOrCreateType(Ty->getValueType(), U);
}
+llvm::DIType* CGDebugInfo::CreateType(const PipeType *Ty,
+ llvm::DIFile *U) {
+ return getOrCreateType(Ty->getElementType(), U);
+}
+
llvm::DIType *CGDebugInfo::CreateEnumType(const EnumType *Ty) {
const EnumDecl *ED = Ty->getDecl();
@@ -2284,6 +2289,9 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
case Type::Atomic:
return CreateType(cast<AtomicType>(Ty), Unit);
+ case Type::Pipe:
+ return CreateType(cast<PipeType>(Ty), Unit);
+
case Type::TemplateSpecialization:
return CreateType(cast<TemplateSpecializationType>(Ty), Unit);
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 57d5c808f297..a68dd33fa5fe 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -168,6 +168,7 @@ class CGDebugInfo {
llvm::DIType *CreateType(const RValueReferenceType *Ty, llvm::DIFile *Unit);
llvm::DIType *CreateType(const MemberPointerType *Ty, llvm::DIFile *F);
llvm::DIType *CreateType(const AtomicType *Ty, llvm::DIFile *F);
+ llvm::DIType *CreateType(const PipeType *Ty, llvm::DIFile *F);
/// Get enumeration type.
llvm::DIType *CreateEnumType(const EnumType *Ty);
llvm::DIType *CreateTypeDefinition(const EnumType *Ty);
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index dabd2b1528bb..507ce3d7d0ce 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -3365,6 +3365,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_PointerToBoolean:
case CK_VectorSplat:
case CK_IntegralCast:
+ case CK_BooleanToSignedIntegral:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
case CK_FloatingToIntegral:
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 20838db044c9..a4547a9982be 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -721,6 +721,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_ToVoid:
case CK_VectorSplat:
case CK_IntegralCast:
+ case CK_BooleanToSignedIntegral:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
case CK_FloatingToIntegral:
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index ccdb53287e9f..22910d931ded 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -462,6 +462,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
case CK_ToVoid:
case CK_VectorSplat:
case CK_IntegralCast:
+ case CK_BooleanToSignedIntegral:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
case CK_FloatingToIntegral:
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 3839ab718fa3..ee049f1810a2 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -735,6 +735,7 @@ public:
case CK_PointerToBoolean:
case CK_NullToPointer:
case CK_IntegralCast:
+ case CK_BooleanToSignedIntegral:
case CK_IntegralToPointer:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 725d96f29877..268e7967b808 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -811,14 +811,15 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
// A scalar can be splatted to an extended vector of the same element type
if (DstType->isExtVectorType() && !SrcType->isVectorType()) {
- // Cast the scalar to element type
- QualType EltTy = DstType->getAs<ExtVectorType>()->getElementType();
- llvm::Value *Elt = EmitScalarConversion(
- Src, SrcType, EltTy, Loc, CGF.getContext().getLangOpts().OpenCL);
+ // Sema should add casts to make sure that the source expression's type is
+ // the same as the vector's element type (sans qualifiers)
+ assert(DstType->castAs<ExtVectorType>()->getElementType().getTypePtr() ==
+ SrcType.getTypePtr() &&
+ "Splatted expr doesn't match with vector element type?");
// Splat the element across to all elements
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
- return Builder.CreateVectorSplat(NumElements, Elt, "splat");
+ return Builder.CreateVectorSplat(NumElements, Src, "splat");
}
// Allow bitcast from vector to integer/fp of the same size.
@@ -1541,15 +1542,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
}
case CK_VectorSplat: {
llvm::Type *DstTy = ConvertType(DestTy);
- // Need an IgnoreImpCasts here as by default a boolean will be promoted to
- // an int, which will not perform the sign extension, so if we know we are
- // going to cast to a vector we have to strip the implicit cast off.
- Value *Elt = Visit(const_cast<Expr*>(E->IgnoreImpCasts()));
- Elt = EmitScalarConversion(Elt, E->IgnoreImpCasts()->getType(),
- DestTy->getAs<VectorType>()->getElementType(),
- CE->getExprLoc(),
- CGF.getContext().getLangOpts().OpenCL);
-
+ Value *Elt = Visit(const_cast<Expr*>(E));
// Splat the element across to all elements
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
return Builder.CreateVectorSplat(NumElements, Elt, "splat");
@@ -1561,6 +1554,10 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_FloatingCast:
return EmitScalarConversion(Visit(E), E->getType(), DestTy,
CE->getExprLoc());
+ case CK_BooleanToSignedIntegral:
+ return EmitScalarConversion(Visit(E), E->getType(), DestTy,
+ CE->getExprLoc(),
+ /*TreatBooleanAsSigned=*/true);
case CK_IntegralToBoolean:
return EmitIntToBoolConversion(Visit(E));
case CK_PointerToBoolean:
diff --git a/lib/CodeGen/CGOpenCLRuntime.cpp b/lib/CodeGen/CGOpenCLRuntime.cpp
index 8af39ceecdfe..686678962d3e 100644
--- a/lib/CodeGen/CGOpenCLRuntime.cpp
+++ b/lib/CodeGen/CGOpenCLRuntime.cpp
@@ -99,3 +99,14 @@ llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
llvm::StructType::create(Ctx, "opencl.reserve_id_t"), 0);
}
}
+
+llvm::Type *CGOpenCLRuntime::getPipeType() {
+ if (!PipeTy){
+ uint32_t PipeAddrSpc =
+ CGM.getContext().getTargetAddressSpace(LangAS::opencl_global);
+ PipeTy = llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.pipe_t"), PipeAddrSpc);
+ }
+
+ return PipeTy;
+}
diff --git a/lib/CodeGen/CGOpenCLRuntime.h b/lib/CodeGen/CGOpenCLRuntime.h
index 0c50b92914b8..f1a7a3106443 100644
--- a/lib/CodeGen/CGOpenCLRuntime.h
+++ b/lib/CodeGen/CGOpenCLRuntime.h
@@ -32,9 +32,10 @@ class CodeGenModule;
class CGOpenCLRuntime {
protected:
CodeGenModule &CGM;
+ llvm::Type *PipeTy;
public:
- CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM) {}
+ CGOpenCLRuntime(CodeGenModule &CGM) : CGM(CGM), PipeTy(nullptr) {}
virtual ~CGOpenCLRuntime();
/// Emit the IR required for a work-group-local variable declaration, and add
@@ -44,6 +45,8 @@ public:
const VarDecl &D);
virtual llvm::Type *convertOpenCLSpecificType(const Type *T);
+
+ virtual llvm::Type *getPipeType();
};
}
diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp
index 6d4fc9f64b47..3b97ba2469ae 100644
--- a/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -84,7 +84,7 @@ public:
protected:
CGOpenMPRegionKind RegionKind;
- const RegionCodeGenTy &CodeGen;
+ RegionCodeGenTy CodeGen;
OpenMPDirectiveKind Kind;
bool HasCancel;
};
diff --git a/lib/CodeGen/CGOpenMPRuntime.h b/lib/CodeGen/CGOpenMPRuntime.h
index 6b04fbeb09b5..b3256375d9b6 100644
--- a/lib/CodeGen/CGOpenMPRuntime.h
+++ b/lib/CodeGen/CGOpenMPRuntime.h
@@ -335,7 +335,7 @@ private:
public:
/// \brief Kind of a given entry. Currently, only target regions are
/// supported.
- enum OffloadingEntryInfoKinds {
+ enum OffloadingEntryInfoKinds : unsigned {
// Entry is a target region.
OFFLOAD_ENTRY_INFO_TARGET_REGION = 0,
// Invalid entry info.
@@ -955,7 +955,7 @@ public:
/// \brief Emit the target regions enclosed in \a GD function definition or
/// the function itself in case it is a valid device function. Returns true if
/// \a GD was dealt with successfully.
- /// \param FD Function to scan.
+ /// \param GD Function to scan.
virtual bool emitTargetFunctions(GlobalDecl GD);
/// \brief Emit the global variable if it is a valid device global variable.
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index abef5432518e..0a670ab19aa5 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -26,12 +26,10 @@
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
-#include "llvm/IR/FunctionInfo.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Linker/Linker.h"
-#include "llvm/Object/FunctionIndexObjectFile.h"
#include "llvm/Pass.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
@@ -781,43 +779,11 @@ void CodeGenAction::ExecuteAction() {
TheModule->setTargetTriple(TargetOpts.Triple);
}
- auto DiagHandler = [&](const DiagnosticInfo &DI) {
- TheModule->getContext().diagnose(DI);
- };
-
- // If we are performing ThinLTO importing compilation (indicated by
- // a non-empty index file option), then we need promote to global scope
- // and rename any local values that are potentially exported to other
- // modules. Do this early so that the rest of the compilation sees the
- // promoted symbols.
- std::unique_ptr<FunctionInfoIndex> Index;
- if (!CI.getCodeGenOpts().ThinLTOIndexFile.empty()) {
- ErrorOr<std::unique_ptr<FunctionInfoIndex>> IndexOrErr =
- llvm::getFunctionIndexForFile(CI.getCodeGenOpts().ThinLTOIndexFile,
- DiagHandler);
- if (std::error_code EC = IndexOrErr.getError()) {
- std::string Error = EC.message();
- errs() << "Error loading index file '"
- << CI.getCodeGenOpts().ThinLTOIndexFile << "': " << Error
- << "\n";
- return;
- }
- Index = std::move(IndexOrErr.get());
- assert(Index);
- // Currently this requires creating a new Module object.
- std::unique_ptr<llvm::Module> RenamedModule =
- renameModuleForThinLTO(std::move(TheModule), Index.get());
- if (!RenamedModule)
- return;
-
- TheModule = std::move(RenamedModule);
- }
-
LLVMContext &Ctx = TheModule->getContext();
Ctx.setInlineAsmDiagnosticHandler(BitcodeInlineAsmDiagHandler);
EmitBackendOutput(CI.getDiagnostics(), CI.getCodeGenOpts(), TargetOpts,
CI.getLangOpts(), CI.getTarget().getDataLayoutString(),
- TheModule.get(), BA, OS, std::move(Index));
+ TheModule.get(), BA, OS);
return;
}
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 048a04328fc2..e38ff0a39da3 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -79,7 +79,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
if (CGM.getCodeGenOpts().ReciprocalMath) {
FMF.setAllowReciprocal();
}
- Builder.SetFastMathFlags(FMF);
+ Builder.setFastMathFlags(FMF);
}
CodeGenFunction::~CodeGenFunction() {
@@ -195,6 +195,7 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
case Type::FunctionNoProto:
case Type::Enum:
case Type::ObjCObjectPointer:
+ case Type::Pipe:
return TEK_Scalar;
// Complexes.
@@ -511,7 +512,8 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
typeQuals += typeQuals.empty() ? "volatile" : " volatile";
} else {
uint32_t AddrSpc = 0;
- if (ty->isImageType())
+ bool isPipe = ty->isPipeType();
+ if (ty->isImageType() || isPipe)
AddrSpc =
CGM.getContext().getTargetAddressSpace(LangAS::opencl_global);
@@ -519,7 +521,11 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
llvm::ConstantAsMetadata::get(Builder.getInt32(AddrSpc)));
// Get argument type name.
- std::string typeName = ty.getUnqualifiedType().getAsString(Policy);
+ std::string typeName;
+ if (isPipe)
+ typeName = cast<PipeType>(ty)->getElementType().getAsString(Policy);
+ else
+ typeName = ty.getUnqualifiedType().getAsString(Policy);
// Turn "unsigned type" to "utype"
std::string::size_type pos = typeName.find("unsigned");
@@ -528,7 +534,12 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
argTypeNames.push_back(llvm::MDString::get(Context, typeName));
- std::string baseTypeName =
+ std::string baseTypeName;
+ if (isPipe)
+ baseTypeName =
+ cast<PipeType>(ty)->getElementType().getCanonicalType().getAsString(Policy);
+ else
+ baseTypeName =
ty.getUnqualifiedType().getCanonicalType().getAsString(Policy);
// Turn "unsigned type" to "utype"
@@ -543,12 +554,16 @@ static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
typeQuals = "const";
if (ty.isVolatileQualified())
typeQuals += typeQuals.empty() ? "volatile" : " volatile";
+ if (isPipe)
+ typeQuals = "pipe";
}
argTypeQuals.push_back(llvm::MDString::get(Context, typeQuals));
- // Get image access qualifier:
- if (ty->isImageType()) {
+ // Get image and pipe access qualifier:
+ // FIXME: now image and pipe share the same access qualifier maybe we can
+ // refine it to OpenCL access qualifier and also handle write_read
+ if (ty->isImageType()|| ty->isPipeType()) {
const OpenCLImageAccessAttr *A = parm->getAttr<OpenCLImageAccessAttr>();
if (A && A->isWriteOnly())
accessQuals.push_back(llvm::MDString::get(Context, "write_only"));
@@ -1727,6 +1742,10 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
case Type::Atomic:
type = cast<AtomicType>(ty)->getValueType();
break;
+
+ case Type::Pipe:
+ type = cast<PipeType>(ty)->getElementType();
+ break;
}
} while (type->isVariablyModifiedType());
}
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 536c55ae4e18..97b166278f81 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -615,7 +615,20 @@ void CodeGenModule::setTLSMode(llvm::GlobalValue *GV, const VarDecl &D) const {
}
StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
- StringRef &FoundStr = MangledDeclNames[GD.getCanonicalDecl()];
+ GlobalDecl CanonicalGD = GD.getCanonicalDecl();
+
+ // Some ABIs don't have constructor variants. Make sure that base and
+ // complete constructors get mangled the same.
+ if (const auto *CD = dyn_cast<CXXConstructorDecl>(CanonicalGD.getDecl())) {
+ if (!getTarget().getCXXABI().hasConstructorVariants()) {
+ CXXCtorType OrigCtorType = GD.getCtorType();
+ assert(OrigCtorType == Ctor_Base || OrigCtorType == Ctor_Complete);
+ if (OrigCtorType == Ctor_Base)
+ CanonicalGD = GlobalDecl(CD, Ctor_Complete);
+ }
+ }
+
+ StringRef &FoundStr = MangledDeclNames[CanonicalGD];
if (!FoundStr.empty())
return FoundStr;
diff --git a/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp
index 5ae861eab0d3..2c0d93b394ac 100644
--- a/lib/CodeGen/CodeGenPGO.cpp
+++ b/lib/CodeGen/CodeGenPGO.cpp
@@ -699,7 +699,7 @@ CodeGenPGO::emitEmptyCounterMapping(const Decl *D, StringRef Name,
setFuncName(Name, Linkage);
CGM.getCoverageMapping()->addFunctionMappingRecord(
- FuncNameVar, FuncName, FunctionHash, CoverageMapping);
+ FuncNameVar, FuncName, FunctionHash, CoverageMapping, false);
}
void CodeGenPGO::computeRegionCounts(const Decl *D) {
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index fcda05320551..09d9bf17b3bf 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -628,6 +628,10 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
}
break;
}
+ case Type::Pipe: {
+ ResultType = CGM.getOpenCLRuntime().getPipeType();
+ break;
+ }
}
assert(ResultType && "Didn't convert a type?");
diff --git a/lib/CodeGen/CoverageMappingGen.cpp b/lib/CodeGen/CoverageMappingGen.cpp
index 1d4d7099e194..03e22cd398aa 100644
--- a/lib/CodeGen/CoverageMappingGen.cpp
+++ b/lib/CodeGen/CoverageMappingGen.cpp
@@ -910,11 +910,11 @@ static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
}
void CoverageMappingModuleGen::addFunctionMappingRecord(
- llvm::GlobalVariable *NamePtr, StringRef NameValue,
- uint64_t FuncHash, const std::string &CoverageMapping) {
+ llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
+ const std::string &CoverageMapping, bool isUsed) {
llvm::LLVMContext &Ctx = CGM.getLLVMContext();
if (!FunctionRecordTy) {
- #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
+#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
llvm::Type *FunctionRecordTypes[] = {
#include "llvm/ProfileData/InstrProfData.inc"
};
@@ -929,6 +929,9 @@ void CoverageMappingModuleGen::addFunctionMappingRecord(
};
FunctionRecords.push_back(llvm::ConstantStruct::get(
FunctionRecordTy, makeArrayRef(FunctionRecordVals)));
+ if (!isUsed)
+ FunctionNames.push_back(
+ llvm::ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx)));
CoverageMappings += CoverageMapping;
if (CGM.getCodeGenOpts().DumpCoverageMapping) {
@@ -1023,6 +1026,17 @@ void CoverageMappingModuleGen::emit() {
// Make sure the data doesn't get deleted.
CGM.addUsedGlobal(CovData);
+ // Create the deferred function records array
+ if (!FunctionNames.empty()) {
+ auto NamesArrTy = llvm::ArrayType::get(llvm::Type::getInt8PtrTy(Ctx),
+ FunctionNames.size());
+ auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
+ // This variable will *NOT* be emitted to the object file. It is used
+ // to pass the list of names referenced to codegen.
+ new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true,
+ llvm::GlobalValue::InternalLinkage, NamesArrVal,
+ llvm::getCoverageNamesVarName());
+ }
}
unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) {
diff --git a/lib/CodeGen/CoverageMappingGen.h b/lib/CodeGen/CoverageMappingGen.h
index 0d1bf6d975c9..9ae2bcffe4ca 100644
--- a/lib/CodeGen/CoverageMappingGen.h
+++ b/lib/CodeGen/CoverageMappingGen.h
@@ -54,6 +54,7 @@ class CoverageMappingModuleGen {
CoverageSourceInfo &SourceInfo;
llvm::SmallDenseMap<const FileEntry *, unsigned, 8> FileEntries;
std::vector<llvm::Constant *> FunctionRecords;
+ std::vector<llvm::Constant *> FunctionNames;
llvm::StructType *FunctionRecordTy;
std::string CoverageMappings;
@@ -70,7 +71,8 @@ public:
void addFunctionMappingRecord(llvm::GlobalVariable *FunctionName,
StringRef FunctionNameValue,
uint64_t FunctionHash,
- const std::string &CoverageMapping);
+ const std::string &CoverageMapping,
+ bool isUsed = true);
/// \brief Emit the coverage mapping data for a translation unit.
void emit();
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 0c4008f8ee78..e02c8dc3a86a 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -2715,6 +2715,9 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
case Type::Auto:
llvm_unreachable("Undeduced auto type shouldn't get here");
+ case Type::Pipe:
+ llvm_unreachable("Pipe types shouldn't get here");
+
case Type::Builtin:
// GCC treats vector and complex types as fundamental types.
case Type::Vector:
@@ -2939,6 +2942,9 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
case Type::Auto:
llvm_unreachable("Undeduced auto type shouldn't get here");
+ case Type::Pipe:
+ llvm_unreachable("Pipe type shouldn't get here");
+
case Type::ConstantArray:
case Type::IncompleteArray:
case Type::VariableArray:
diff --git a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
index b397eb352a60..f385e53fa01f 100644
--- a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
+++ b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
@@ -59,8 +59,10 @@ class PCHContainerGenerator : public ASTConsumer {
struct DebugTypeVisitor : public RecursiveASTVisitor<DebugTypeVisitor> {
clang::CodeGen::CGDebugInfo &DI;
ASTContext &Ctx;
- DebugTypeVisitor(clang::CodeGen::CGDebugInfo &DI, ASTContext &Ctx)
- : DI(DI), Ctx(Ctx) {}
+ bool SkipTagDecls;
+ DebugTypeVisitor(clang::CodeGen::CGDebugInfo &DI, ASTContext &Ctx,
+ bool SkipTagDecls)
+ : DI(DI), Ctx(Ctx), SkipTagDecls(SkipTagDecls) {}
/// Determine whether this type can be represented in DWARF.
static bool CanRepresent(const Type *Ty) {
@@ -75,6 +77,12 @@ class PCHContainerGenerator : public ASTConsumer {
}
bool VisitTypeDecl(TypeDecl *D) {
+ // TagDecls may be deferred until after all decls have been merged and we
+ // know the complete type. Pure forward declarations will be skipped, but
+ // they don't need to be emitted into the module anyway.
+ if (SkipTagDecls && isa<TagDecl>(D))
+ return true;
+
QualType QualTy = Ctx.getTypeDeclType(D);
if (!QualTy.isNull() && CanRepresent(QualTy.getTypePtr()))
DI.getOrCreateStandaloneType(QualTy, D->getLocation());
@@ -165,7 +173,7 @@ public:
// Collect debug info for all decls in this group.
for (auto *I : D)
if (!I->isFromASTFile()) {
- DebugTypeVisitor DTV(*Builder->getModuleDebugInfo(), *Ctx);
+ DebugTypeVisitor DTV(*Builder->getModuleDebugInfo(), *Ctx, true);
DTV.TraverseDecl(I);
}
return true;
@@ -179,6 +187,11 @@ public:
if (Diags.hasErrorOccurred())
return;
+ if (D->isFromASTFile())
+ return;
+
+ DebugTypeVisitor DTV(*Builder->getModuleDebugInfo(), *Ctx, false);
+ DTV.TraverseDecl(D);
Builder->UpdateCompletedType(D);
}
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp
index 49dccd224bff..e9490e96db8d 100644
--- a/lib/Driver/Action.cpp
+++ b/lib/Driver/Action.cpp
@@ -8,17 +8,14 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Action.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Regex.h"
#include <cassert>
using namespace clang::driver;
using namespace llvm::opt;
-Action::~Action() {
- if (OwnsInputs) {
- for (iterator it = begin(), ie = end(); it != ie; ++it)
- delete *it;
- }
-}
+Action::~Action() {}
const char *Action::getClassName(ActionClass AC) {
switch (AC) {
@@ -51,33 +48,53 @@ InputAction::InputAction(const Arg &_Input, types::ID _Type)
void BindArchAction::anchor() {}
-BindArchAction::BindArchAction(std::unique_ptr<Action> Input,
- const char *_ArchName)
- : Action(BindArchClass, std::move(Input)), ArchName(_ArchName) {}
+BindArchAction::BindArchAction(Action *Input, const char *_ArchName)
+ : Action(BindArchClass, Input), ArchName(_ArchName) {}
+
+// Converts CUDA GPU architecture, e.g. "sm_21", to its corresponding virtual
+// compute arch, e.g. "compute_20". Returns null if the input arch is null or
+// doesn't match an existing arch.
+static const char* GpuArchToComputeName(const char *ArchName) {
+ if (!ArchName)
+ return nullptr;
+ return llvm::StringSwitch<const char *>(ArchName)
+ .Cases("sm_20", "sm_21", "compute_20")
+ .Case("sm_30", "compute_30")
+ .Case("sm_32", "compute_32")
+ .Case("sm_35", "compute_35")
+ .Case("sm_37", "compute_37")
+ .Case("sm_50", "compute_50")
+ .Case("sm_52", "compute_52")
+ .Case("sm_53", "compute_53")
+ .Default(nullptr);
+}
void CudaDeviceAction::anchor() {}
-CudaDeviceAction::CudaDeviceAction(std::unique_ptr<Action> Input,
- const char *ArchName, bool AtTopLevel)
- : Action(CudaDeviceClass, std::move(Input)), GpuArchName(ArchName),
- AtTopLevel(AtTopLevel) {}
-
-void CudaHostAction::anchor() {}
+CudaDeviceAction::CudaDeviceAction(Action *Input, const char *ArchName,
+ bool AtTopLevel)
+ : Action(CudaDeviceClass, Input), GpuArchName(ArchName),
+ AtTopLevel(AtTopLevel) {
+ assert(IsValidGpuArchName(GpuArchName));
+}
-CudaHostAction::CudaHostAction(std::unique_ptr<Action> Input,
- const ActionList &DeviceActions)
- : Action(CudaHostClass, std::move(Input)), DeviceActions(DeviceActions) {}
+const char *CudaDeviceAction::getComputeArchName() const {
+ return GpuArchToComputeName(GpuArchName);
+}
-CudaHostAction::~CudaHostAction() {
- for (auto &DA : DeviceActions)
- delete DA;
+bool CudaDeviceAction::IsValidGpuArchName(llvm::StringRef ArchName) {
+ return GpuArchToComputeName(ArchName.data()) != nullptr;
}
+void CudaHostAction::anchor() {}
+
+CudaHostAction::CudaHostAction(Action *Input, const ActionList &DeviceActions)
+ : Action(CudaHostClass, Input), DeviceActions(DeviceActions) {}
+
void JobAction::anchor() {}
-JobAction::JobAction(ActionClass Kind, std::unique_ptr<Action> Input,
- types::ID Type)
- : Action(Kind, std::move(Input), Type) {}
+JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type)
+ : Action(Kind, Input, Type) {}
JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
: Action(Kind, Inputs, Type) {
@@ -85,45 +102,38 @@ JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type)
void PreprocessJobAction::anchor() {}
-PreprocessJobAction::PreprocessJobAction(std::unique_ptr<Action> Input,
- types::ID OutputType)
- : JobAction(PreprocessJobClass, std::move(Input), OutputType) {}
+PreprocessJobAction::PreprocessJobAction(Action *Input, types::ID OutputType)
+ : JobAction(PreprocessJobClass, Input, OutputType) {}
void PrecompileJobAction::anchor() {}
-PrecompileJobAction::PrecompileJobAction(std::unique_ptr<Action> Input,
- types::ID OutputType)
- : JobAction(PrecompileJobClass, std::move(Input), OutputType) {}
+PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType)
+ : JobAction(PrecompileJobClass, Input, OutputType) {}
void AnalyzeJobAction::anchor() {}
-AnalyzeJobAction::AnalyzeJobAction(std::unique_ptr<Action> Input,
- types::ID OutputType)
- : JobAction(AnalyzeJobClass, std::move(Input), OutputType) {}
+AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)
+ : JobAction(AnalyzeJobClass, Input, OutputType) {}
void MigrateJobAction::anchor() {}
-MigrateJobAction::MigrateJobAction(std::unique_ptr<Action> Input,
- types::ID OutputType)
- : JobAction(MigrateJobClass, std::move(Input), OutputType) {}
+MigrateJobAction::MigrateJobAction(Action *Input, types::ID OutputType)
+ : JobAction(MigrateJobClass, Input, OutputType) {}
void CompileJobAction::anchor() {}
-CompileJobAction::CompileJobAction(std::unique_ptr<Action> Input,
- types::ID OutputType)
- : JobAction(CompileJobClass, std::move(Input), OutputType) {}
+CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType)
+ : JobAction(CompileJobClass, Input, OutputType) {}
void BackendJobAction::anchor() {}
-BackendJobAction::BackendJobAction(std::unique_ptr<Action> Input,
- types::ID OutputType)
- : JobAction(BackendJobClass, std::move(Input), OutputType) {}
+BackendJobAction::BackendJobAction(Action *Input, types::ID OutputType)
+ : JobAction(BackendJobClass, Input, OutputType) {}
void AssembleJobAction::anchor() {}
-AssembleJobAction::AssembleJobAction(std::unique_ptr<Action> Input,
- types::ID OutputType)
- : JobAction(AssembleJobClass, std::move(Input), OutputType) {}
+AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType)
+ : JobAction(AssembleJobClass, Input, OutputType) {}
void LinkJobAction::anchor() {}
@@ -145,21 +155,20 @@ DsymutilJobAction::DsymutilJobAction(ActionList &Inputs, types::ID Type)
void VerifyJobAction::anchor() {}
-VerifyJobAction::VerifyJobAction(ActionClass Kind,
- std::unique_ptr<Action> Input, types::ID Type)
- : JobAction(Kind, std::move(Input), Type) {
+VerifyJobAction::VerifyJobAction(ActionClass Kind, Action *Input,
+ types::ID Type)
+ : JobAction(Kind, Input, Type) {
assert((Kind == VerifyDebugInfoJobClass || Kind == VerifyPCHJobClass) &&
"ActionClass is not a valid VerifyJobAction");
}
void VerifyDebugInfoJobAction::anchor() {}
-VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(
- std::unique_ptr<Action> Input, types::ID Type)
- : VerifyJobAction(VerifyDebugInfoJobClass, std::move(Input), Type) {}
+VerifyDebugInfoJobAction::VerifyDebugInfoJobAction(Action *Input,
+ types::ID Type)
+ : VerifyJobAction(VerifyDebugInfoJobClass, Input, Type) {}
void VerifyPCHJobAction::anchor() {}
-VerifyPCHJobAction::VerifyPCHJobAction(std::unique_ptr<Action> Input,
- types::ID Type)
- : VerifyJobAction(VerifyPCHJobClass, std::move(Input), Type) {}
+VerifyPCHJobAction::VerifyPCHJobAction(Action *Input, types::ID Type)
+ : VerifyJobAction(VerifyPCHJobClass, Input, Type) {}
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index e4af2a6ced8a..1c2eecd3ccc5 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -40,11 +40,6 @@ Compilation::~Compilation() {
if (it->second != TranslatedArgs)
delete it->second;
- // Free the actions, if built.
- for (ActionList::iterator it = Actions.begin(), ie = Actions.end();
- it != ie; ++it)
- delete *it;
-
// Free redirections of stdout/stderr.
if (Redirects) {
delete Redirects[1];
@@ -208,7 +203,8 @@ void Compilation::initCompilationForDiagnostics() {
ForDiagnostics = true;
// Free actions and jobs.
- DeleteContainerPointers(Actions);
+ Actions.clear();
+ AllActions.clear();
Jobs.clear();
// Clear temporary/results file lists.
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 85bbcb4113ab..1e0a48d52928 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -1049,19 +1049,15 @@ void Driver::BuildUniversalActions(Compilation &C, const ToolChain &TC,
<< types::getTypeName(Act->getType());
ActionList Inputs;
- for (unsigned i = 0, e = Archs.size(); i != e; ++i) {
- Inputs.push_back(
- new BindArchAction(std::unique_ptr<Action>(Act), Archs[i]));
- if (i != 0)
- Inputs.back()->setOwnsInputs(false);
- }
+ for (unsigned i = 0, e = Archs.size(); i != e; ++i)
+ Inputs.push_back(C.MakeAction<BindArchAction>(Act, Archs[i]));
// Lipo if necessary, we do it this way because we need to set the arch flag
// so that -Xarch_ gets overwritten.
if (Inputs.size() == 1 || Act->getType() == types::TY_Nothing)
Actions.append(Inputs.begin(), Inputs.end());
else
- Actions.push_back(new LipoJobAction(Inputs, Act->getType()));
+ Actions.push_back(C.MakeAction<LipoJobAction>(Inputs, Act->getType()));
// Handle debug info queries.
Arg *A = Args.getLastArg(options::OPT_g_Group);
@@ -1077,15 +1073,16 @@ void Driver::BuildUniversalActions(Compilation &C, const ToolChain &TC,
ActionList Inputs;
Inputs.push_back(Actions.back());
Actions.pop_back();
- Actions.push_back(new DsymutilJobAction(Inputs, types::TY_dSYM));
+ Actions.push_back(
+ C.MakeAction<DsymutilJobAction>(Inputs, types::TY_dSYM));
}
// Verify the debug info output.
if (Args.hasArg(options::OPT_verify_debug_info)) {
- std::unique_ptr<Action> VerifyInput(Actions.back());
+ Action* LastAction = Actions.back();
Actions.pop_back();
- Actions.push_back(new VerifyDebugInfoJobAction(std::move(VerifyInput),
- types::TY_Nothing));
+ Actions.push_back(C.MakeAction<VerifyDebugInfoJobAction>(
+ LastAction, types::TY_Nothing));
}
}
}
@@ -1283,26 +1280,29 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args,
// Actions and /p Current is released. Otherwise the function creates
// and returns a new CudaHostAction which wraps /p Current and device
// side actions.
-static std::unique_ptr<Action>
-buildCudaActions(Compilation &C, DerivedArgList &Args, const Arg *InputArg,
- std::unique_ptr<Action> HostAction, ActionList &Actions) {
+static Action *buildCudaActions(Compilation &C, DerivedArgList &Args,
+ const Arg *InputArg, Action *HostAction,
+ ActionList &Actions) {
Arg *PartialCompilationArg = Args.getLastArg(options::OPT_cuda_host_only,
options::OPT_cuda_device_only);
// Host-only compilation case.
if (PartialCompilationArg &&
PartialCompilationArg->getOption().matches(options::OPT_cuda_host_only))
- return std::unique_ptr<Action>(
- new CudaHostAction(std::move(HostAction), {}));
+ return C.MakeAction<CudaHostAction>(HostAction, ActionList());
// Collect all cuda_gpu_arch parameters, removing duplicates.
SmallVector<const char *, 4> GpuArchList;
llvm::StringSet<> GpuArchNames;
for (Arg *A : Args) {
- if (A->getOption().matches(options::OPT_cuda_gpu_arch_EQ)) {
- A->claim();
- if (GpuArchNames.insert(A->getValue()).second)
- GpuArchList.push_back(A->getValue());
- }
+ if (!A->getOption().matches(options::OPT_cuda_gpu_arch_EQ))
+ continue;
+ A->claim();
+
+ const auto& Arch = A->getValue();
+ if (!CudaDeviceAction::IsValidGpuArchName(Arch))
+ C.getDriver().Diag(clang::diag::err_drv_cuda_bad_gpu_arch) << Arch;
+ else if (GpuArchNames.insert(Arch).second)
+ GpuArchList.push_back(Arch);
}
// Default to sm_20 which is the lowest common denominator for supported GPUs.
@@ -1325,13 +1325,10 @@ buildCudaActions(Compilation &C, DerivedArgList &Args, const Arg *InputArg,
"Failed to create actions for all devices");
// Check whether any of device actions stopped before they could generate PTX.
- bool PartialCompilation = false;
- for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) {
- if (CudaDeviceActions[I]->getKind() != Action::BackendJobClass) {
- PartialCompilation = true;
- break;
- }
- }
+ bool PartialCompilation =
+ llvm::any_of(CudaDeviceActions, [](const Action *a) {
+ return a->getKind() != Action::BackendJobClass;
+ });
// Figure out what to do with device actions -- pass them as inputs to the
// host action or run each of them independently.
@@ -1350,12 +1347,12 @@ buildCudaActions(Compilation &C, DerivedArgList &Args, const Arg *InputArg,
}
for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I)
- Actions.push_back(new CudaDeviceAction(
- std::unique_ptr<Action>(CudaDeviceActions[I]), GpuArchList[I],
- /* AtTopLevel */ true));
+ Actions.push_back(C.MakeAction<CudaDeviceAction>(CudaDeviceActions[I],
+ GpuArchList[I],
+ /* AtTopLevel */ true));
// Kill host action in case of device-only compilation.
if (DeviceOnlyCompilation)
- HostAction.reset(nullptr);
+ return nullptr;
return HostAction;
}
@@ -1363,13 +1360,12 @@ buildCudaActions(Compilation &C, DerivedArgList &Args, const Arg *InputArg,
// with AtTopLevel=false and become inputs for the host action.
ActionList DeviceActions;
for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I)
- DeviceActions.push_back(new CudaDeviceAction(
- std::unique_ptr<Action>(CudaDeviceActions[I]), GpuArchList[I],
- /* AtTopLevel */ false));
+ DeviceActions.push_back(
+ C.MakeAction<CudaDeviceAction>(CudaDeviceActions[I], GpuArchList[I],
+ /* AtTopLevel */ false));
// Return a new host action that incorporates original host action and all
// device actions.
- return std::unique_ptr<Action>(
- new CudaHostAction(std::move(HostAction), DeviceActions));
+ return C.MakeAction<CudaHostAction>(HostAction, DeviceActions);
}
void Driver::BuildActions(Compilation &C, const ToolChain &TC,
@@ -1470,15 +1466,14 @@ void Driver::BuildActions(Compilation &C, const ToolChain &TC,
continue;
}
- phases::ID CudaInjectionPhase = FinalPhase;
- for (const auto &Phase : PL)
- if (Phase <= FinalPhase && Phase == phases::Compile) {
- CudaInjectionPhase = Phase;
- break;
- }
+ phases::ID CudaInjectionPhase =
+ (phases::Compile < FinalPhase &&
+ llvm::find(PL, phases::Compile) != PL.end())
+ ? phases::Compile
+ : FinalPhase;
// Build the pipeline for this file.
- std::unique_ptr<Action> Current(new InputAction(*InputArg, InputType));
+ Action *Current = C.MakeAction<InputAction>(*InputArg, InputType);
for (SmallVectorImpl<phases::ID>::iterator i = PL.begin(), e = PL.end();
i != e; ++i) {
phases::ID Phase = *i;
@@ -1490,7 +1485,8 @@ void Driver::BuildActions(Compilation &C, const ToolChain &TC,
// Queue linker inputs.
if (Phase == phases::Link) {
assert((i + 1) == e && "linking must be final compilation step.");
- LinkerInputs.push_back(Current.release());
+ LinkerInputs.push_back(Current);
+ Current = nullptr;
break;
}
@@ -1501,11 +1497,10 @@ void Driver::BuildActions(Compilation &C, const ToolChain &TC,
continue;
// Otherwise construct the appropriate action.
- Current = ConstructPhaseAction(TC, Args, Phase, std::move(Current));
+ Current = ConstructPhaseAction(C, TC, Args, Phase, Current);
if (InputType == types::TY_CUDA && Phase == CudaInjectionPhase) {
- Current =
- buildCudaActions(C, Args, InputArg, std::move(Current), Actions);
+ Current = buildCudaActions(C, Args, InputArg, Current, Actions);
if (!Current)
break;
}
@@ -1516,12 +1511,13 @@ void Driver::BuildActions(Compilation &C, const ToolChain &TC,
// If we ended with something, add to the output list.
if (Current)
- Actions.push_back(Current.release());
+ Actions.push_back(Current);
}
// Add a link action if necessary.
if (!LinkerInputs.empty())
- Actions.push_back(new LinkJobAction(LinkerInputs, types::TY_Image));
+ Actions.push_back(
+ C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image));
// If we are linking, claim any options which are obviously only used for
// compilation.
@@ -1538,10 +1534,9 @@ void Driver::BuildActions(Compilation &C, const ToolChain &TC,
Args.ClaimAllArgs(options::OPT_cuda_host_only);
}
-std::unique_ptr<Action>
-Driver::ConstructPhaseAction(const ToolChain &TC, const ArgList &Args,
- phases::ID Phase,
- std::unique_ptr<Action> Input) const {
+Action *Driver::ConstructPhaseAction(Compilation &C, const ToolChain &TC,
+ const ArgList &Args, phases::ID Phase,
+ Action *Input) const {
llvm::PrettyStackTraceString CrashInfo("Constructing phase actions");
// Build the appropriate action.
switch (Phase) {
@@ -1561,7 +1556,7 @@ Driver::ConstructPhaseAction(const ToolChain &TC, const ArgList &Args,
assert(OutputTy != types::TY_INVALID &&
"Cannot preprocess this input type!");
}
- return llvm::make_unique<PreprocessJobAction>(std::move(Input), OutputTy);
+ return C.MakeAction<PreprocessJobAction>(Input, OutputTy);
}
case phases::Precompile: {
types::ID OutputTy = types::TY_PCH;
@@ -1569,53 +1564,43 @@ Driver::ConstructPhaseAction(const ToolChain &TC, const ArgList &Args,
// Syntax checks should not emit a PCH file
OutputTy = types::TY_Nothing;
}
- return llvm::make_unique<PrecompileJobAction>(std::move(Input), OutputTy);
+ return C.MakeAction<PrecompileJobAction>(Input, OutputTy);
}
case phases::Compile: {
if (Args.hasArg(options::OPT_fsyntax_only))
- return llvm::make_unique<CompileJobAction>(std::move(Input),
- types::TY_Nothing);
+ return C.MakeAction<CompileJobAction>(Input, types::TY_Nothing);
if (Args.hasArg(options::OPT_rewrite_objc))
- return llvm::make_unique<CompileJobAction>(std::move(Input),
- types::TY_RewrittenObjC);
+ return C.MakeAction<CompileJobAction>(Input, types::TY_RewrittenObjC);
if (Args.hasArg(options::OPT_rewrite_legacy_objc))
- return llvm::make_unique<CompileJobAction>(std::move(Input),
- types::TY_RewrittenLegacyObjC);
+ return C.MakeAction<CompileJobAction>(Input,
+ types::TY_RewrittenLegacyObjC);
if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto))
- return llvm::make_unique<AnalyzeJobAction>(std::move(Input),
- types::TY_Plist);
+ return C.MakeAction<AnalyzeJobAction>(Input, types::TY_Plist);
if (Args.hasArg(options::OPT__migrate))
- return llvm::make_unique<MigrateJobAction>(std::move(Input),
- types::TY_Remap);
+ return C.MakeAction<MigrateJobAction>(Input, types::TY_Remap);
if (Args.hasArg(options::OPT_emit_ast))
- return llvm::make_unique<CompileJobAction>(std::move(Input),
- types::TY_AST);
+ return C.MakeAction<CompileJobAction>(Input, types::TY_AST);
if (Args.hasArg(options::OPT_module_file_info))
- return llvm::make_unique<CompileJobAction>(std::move(Input),
- types::TY_ModuleFile);
+ return C.MakeAction<CompileJobAction>(Input, types::TY_ModuleFile);
if (Args.hasArg(options::OPT_verify_pch))
- return llvm::make_unique<VerifyPCHJobAction>(std::move(Input),
- types::TY_Nothing);
- return llvm::make_unique<CompileJobAction>(std::move(Input),
- types::TY_LLVM_BC);
+ return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing);
+ return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC);
}
case phases::Backend: {
if (isUsingLTO()) {
types::ID Output =
Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC;
- return llvm::make_unique<BackendJobAction>(std::move(Input), Output);
+ return C.MakeAction<BackendJobAction>(Input, Output);
}
if (Args.hasArg(options::OPT_emit_llvm)) {
types::ID Output =
Args.hasArg(options::OPT_S) ? types::TY_LLVM_IR : types::TY_LLVM_BC;
- return llvm::make_unique<BackendJobAction>(std::move(Input), Output);
+ return C.MakeAction<BackendJobAction>(Input, Output);
}
- return llvm::make_unique<BackendJobAction>(std::move(Input),
- types::TY_PP_Asm);
+ return C.MakeAction<BackendJobAction>(Input, types::TY_PP_Asm);
}
case phases::Assemble:
- return llvm::make_unique<AssembleJobAction>(std::move(Input),
- types::TY_Object);
+ return C.MakeAction<AssembleJobAction>(Input, types::TY_Object);
}
llvm_unreachable("invalid phase in ConstructPhaseAction");
@@ -1662,12 +1647,11 @@ void Driver::BuildJobs(Compilation &C) const {
LinkingOutput = getDefaultImageName();
}
- InputInfo II;
BuildJobsForAction(C, A, &C.getDefaultToolChain(),
/*BoundArch*/ nullptr,
/*AtTopLevel*/ true,
/*MultipleArchs*/ ArchNames.size() > 1,
- /*LinkingOutput*/ LinkingOutput, II);
+ /*LinkingOutput*/ LinkingOutput);
}
// If the user passed -Qunused-arguments or there were errors, don't warn
@@ -1795,21 +1779,19 @@ static const Tool *selectToolForJob(Compilation &C, bool SaveTemps,
return ToolForJob;
}
-void Driver::BuildJobsForAction(Compilation &C, const Action *A,
- const ToolChain *TC, const char *BoundArch,
- bool AtTopLevel, bool MultipleArchs,
- const char *LinkingOutput,
- InputInfo &Result) const {
+InputInfo Driver::BuildJobsForAction(Compilation &C, const Action *A,
+ const ToolChain *TC, const char *BoundArch,
+ bool AtTopLevel, bool MultipleArchs,
+ const char *LinkingOutput) const {
llvm::PrettyStackTraceString CrashInfo("Building compilation jobs");
InputInfoList CudaDeviceInputInfos;
if (const CudaHostAction *CHA = dyn_cast<CudaHostAction>(A)) {
- InputInfo II;
// Append outputs of device jobs to the input list.
for (const Action *DA : CHA->getDeviceActions()) {
- BuildJobsForAction(C, DA, TC, nullptr, AtTopLevel,
- /*MultipleArchs*/ false, LinkingOutput, II);
- CudaDeviceInputInfos.push_back(II);
+ CudaDeviceInputInfos.push_back(
+ BuildJobsForAction(C, DA, TC, nullptr, AtTopLevel,
+ /*MultipleArchs*/ false, LinkingOutput));
}
// Override current action with a real host compile action and continue
// processing it.
@@ -1823,11 +1805,9 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A,
Input.claim();
if (Input.getOption().matches(options::OPT_INPUT)) {
const char *Name = Input.getValue();
- Result = InputInfo(Name, A->getType(), Name);
- } else {
- Result = InputInfo(&Input, A->getType(), "");
+ return InputInfo(A, Name, /* BaseInput = */ Name);
}
- return;
+ return InputInfo(A, &Input, /* BaseInput = */ "");
}
if (const BindArchAction *BAA = dyn_cast<BindArchAction>(A)) {
@@ -1841,19 +1821,17 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A,
else
TC = &C.getDefaultToolChain();
- BuildJobsForAction(C, *BAA->begin(), TC, ArchName, AtTopLevel,
- MultipleArchs, LinkingOutput, Result);
- return;
+ return BuildJobsForAction(C, *BAA->begin(), TC, ArchName, AtTopLevel,
+ MultipleArchs, LinkingOutput);
}
if (const CudaDeviceAction *CDA = dyn_cast<CudaDeviceAction>(A)) {
// Initial processing of CudaDeviceAction carries host params.
// Call BuildJobsForAction() again, now with correct device parameters.
assert(CDA->getGpuArchName() && "No GPU name in device action.");
- BuildJobsForAction(C, *CDA->begin(), C.getCudaDeviceToolChain(),
- CDA->getGpuArchName(), CDA->isAtTopLevel(),
- /*MultipleArchs*/ true, LinkingOutput, Result);
- return;
+ return BuildJobsForAction(C, *CDA->begin(), C.getCudaDeviceToolChain(),
+ CDA->getGpuArchName(), CDA->isAtTopLevel(),
+ /*MultipleArchs*/ true, LinkingOutput);
}
const ActionList *Inputs = &A->getInputs();
@@ -1863,16 +1841,15 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A,
const Tool *T =
selectToolForJob(C, isSaveTempsEnabled(), TC, JA, Inputs, CollapsedCHA);
if (!T)
- return;
+ return InputInfo();
// If we've collapsed action list that contained CudaHostAction we
// need to build jobs for device-side inputs it may have held.
if (CollapsedCHA) {
- InputInfo II;
for (const Action *DA : CollapsedCHA->getDeviceActions()) {
- BuildJobsForAction(C, DA, TC, "", AtTopLevel,
- /*MultipleArchs*/ false, LinkingOutput, II);
- CudaDeviceInputInfos.push_back(II);
+ CudaDeviceInputInfos.push_back(
+ BuildJobsForAction(C, DA, TC, "", AtTopLevel,
+ /*MultipleArchs*/ false, LinkingOutput));
}
}
@@ -1882,14 +1859,11 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A,
// Treat dsymutil and verify sub-jobs as being at the top-level too, they
// shouldn't get temporary output names.
// FIXME: Clean this up.
- bool SubJobAtTopLevel = false;
- if (AtTopLevel && (isa<DsymutilJobAction>(A) || isa<VerifyJobAction>(A)))
- SubJobAtTopLevel = true;
-
- InputInfo II;
- BuildJobsForAction(C, Input, TC, BoundArch, SubJobAtTopLevel, MultipleArchs,
- LinkingOutput, II);
- InputInfos.push_back(II);
+ bool SubJobAtTopLevel =
+ AtTopLevel && (isa<DsymutilJobAction>(A) || isa<VerifyJobAction>(A));
+ InputInfos.push_back(BuildJobsForAction(C, Input, TC, BoundArch,
+ SubJobAtTopLevel, MultipleArchs,
+ LinkingOutput));
}
// Always use the first input as the base input.
@@ -1905,12 +1879,13 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A,
InputInfos.append(CudaDeviceInputInfos.begin(), CudaDeviceInputInfos.end());
// Determine the place to write output to, if any.
+ InputInfo Result;
if (JA->getType() == types::TY_Nothing)
- Result = InputInfo(A->getType(), BaseInput);
+ Result = InputInfo(A, BaseInput);
else
- Result = InputInfo(GetNamedOutputPath(C, *JA, BaseInput, BoundArch,
- AtTopLevel, MultipleArchs),
- A->getType(), BaseInput);
+ Result = InputInfo(A, GetNamedOutputPath(C, *JA, BaseInput, BoundArch,
+ AtTopLevel, MultipleArchs),
+ BaseInput);
if (CCCPrintBindings && !CCGenDiagnostics) {
llvm::errs() << "# \"" << T->getToolChain().getTripleString() << '"'
@@ -1925,6 +1900,7 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A,
T->ConstructJob(C, *JA, Result, InputInfos,
C.getArgsForToolChain(TC, BoundArch), LinkingOutput);
}
+ return Result;
}
const char *Driver::getDefaultImageName() const {
diff --git a/lib/Driver/InputInfo.h b/lib/Driver/InputInfo.h
index b23ba575b65e..0c36e817c135 100644
--- a/lib/Driver/InputInfo.h
+++ b/lib/Driver/InputInfo.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_LIB_DRIVER_INPUTINFO_H
#define LLVM_CLANG_LIB_DRIVER_INPUTINFO_H
+#include "clang/Driver/Action.h"
#include "clang/Driver/Types.h"
#include "llvm/Option/Arg.h"
#include <cassert>
@@ -38,21 +39,36 @@ class InputInfo {
const llvm::opt::Arg *InputArg;
} Data;
Class Kind;
+ const Action* Act;
types::ID Type;
const char *BaseInput;
+ static types::ID GetActionType(const Action *A) {
+ return A != nullptr ? A->getType() : types::TY_Nothing;
+ }
+
public:
- InputInfo() {}
- InputInfo(types::ID _Type, const char *_BaseInput)
- : Kind(Nothing), Type(_Type), BaseInput(_BaseInput) {
+ InputInfo() : InputInfo(nullptr, nullptr) {}
+ InputInfo(const Action *A, const char *_BaseInput)
+ : Kind(Nothing), Act(A), Type(GetActionType(A)), BaseInput(_BaseInput) {}
+
+ InputInfo(types::ID _Type, const char *_Filename, const char *_BaseInput)
+ : Kind(Filename), Act(nullptr), Type(_Type), BaseInput(_BaseInput) {
+ Data.Filename = _Filename;
}
- InputInfo(const char *_Filename, types::ID _Type, const char *_BaseInput)
- : Kind(Filename), Type(_Type), BaseInput(_BaseInput) {
+ InputInfo(const Action *A, const char *_Filename, const char *_BaseInput)
+ : Kind(Filename), Act(A), Type(GetActionType(A)), BaseInput(_BaseInput) {
Data.Filename = _Filename;
}
- InputInfo(const llvm::opt::Arg *_InputArg, types::ID _Type,
+
+ InputInfo(types::ID _Type, const llvm::opt::Arg *_InputArg,
+ const char *_BaseInput)
+ : Kind(InputArg), Act(nullptr), Type(_Type), BaseInput(_BaseInput) {
+ Data.InputArg = _InputArg;
+ }
+ InputInfo(const Action *A, const llvm::opt::Arg *_InputArg,
const char *_BaseInput)
- : Kind(InputArg), Type(_Type), BaseInput(_BaseInput) {
+ : Kind(InputArg), Act(A), Type(GetActionType(A)), BaseInput(_BaseInput) {
Data.InputArg = _InputArg;
}
@@ -61,6 +77,9 @@ public:
bool isInputArg() const { return Kind == InputArg; }
types::ID getType() const { return Type; }
const char *getBaseInput() const { return BaseInput; }
+ /// The action for which this InputInfo was created. May be null.
+ const Action *getAction() const { return Act; }
+ void setAction(const Action *A) { Act = A; }
const char *getFilename() const {
assert(isFilename() && "Invalid accessor.");
diff --git a/lib/Driver/MSVCToolChain.cpp b/lib/Driver/MSVCToolChain.cpp
index b7e576e53e8f..68747155b81c 100644
--- a/lib/Driver/MSVCToolChain.cpp
+++ b/lib/Driver/MSVCToolChain.cpp
@@ -634,6 +634,96 @@ SanitizerMask MSVCToolChain::getSupportedSanitizers() const {
return Res;
}
+static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL,
+ bool SupportsForcingFramePointer,
+ const char *ExpandChar, const OptTable &Opts) {
+ assert(A->getOption().matches(options::OPT__SLASH_O));
+
+ StringRef OptStr = A->getValue();
+ for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
+ const char &OptChar = *(OptStr.data() + I);
+ switch (OptChar) {
+ default:
+ break;
+ case '1':
+ case '2':
+ case 'x':
+ case 'd':
+ if (&OptChar == ExpandChar) {
+ if (OptChar == 'd') {
+ DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0));
+ } else {
+ if (OptChar == '1') {
+ DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
+ } else if (OptChar == '2' || OptChar == 'x') {
+ DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
+ DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
+ }
+ if (SupportsForcingFramePointer)
+ DAL.AddFlagArg(A,
+ Opts.getOption(options::OPT_fomit_frame_pointer));
+ if (OptChar == '1' || OptChar == '2')
+ DAL.AddFlagArg(A,
+ Opts.getOption(options::OPT_ffunction_sections));
+ }
+ }
+ break;
+ case 'b':
+ if (I + 1 != E && isdigit(OptStr[I + 1]))
+ ++I;
+ break;
+ case 'g':
+ break;
+ case 'i':
+ if (I + 1 != E && OptStr[I + 1] == '-') {
+ ++I;
+ DAL.AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin));
+ } else {
+ DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
+ }
+ break;
+ case 's':
+ DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
+ break;
+ case 't':
+ DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
+ break;
+ case 'y': {
+ bool OmitFramePointer = true;
+ if (I + 1 != E && OptStr[I + 1] == '-') {
+ OmitFramePointer = false;
+ ++I;
+ }
+ if (SupportsForcingFramePointer) {
+ if (OmitFramePointer)
+ DAL.AddFlagArg(A,
+ Opts.getOption(options::OPT_fomit_frame_pointer));
+ else
+ DAL.AddFlagArg(
+ A, Opts.getOption(options::OPT_fno_omit_frame_pointer));
+ }
+ break;
+ }
+ }
+ }
+}
+
+static void TranslateDArg(Arg *A, llvm::opt::DerivedArgList &DAL,
+ const OptTable &Opts) {
+ assert(A->getOption().matches(options::OPT_D));
+
+ StringRef Val = A->getValue();
+ size_t Hash = Val.find('#');
+ if (Hash == StringRef::npos || Hash > Val.find('=')) {
+ DAL.append(A);
+ return;
+ }
+
+ std::string NewVal = Val;
+ NewVal[Hash] = '=';
+ DAL.AddJoinedArg(A, Opts.getOption(options::OPT_D), NewVal);
+}
+
llvm::opt::DerivedArgList *
MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
const char *BoundArch) const {
@@ -664,81 +754,18 @@ MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args,
}
}
- // The -O flag actually takes an amalgam of other options. For example,
- // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'.
for (Arg *A : Args) {
- if (!A->getOption().matches(options::OPT__SLASH_O)) {
+ if (A->getOption().matches(options::OPT__SLASH_O)) {
+ // The -O flag actually takes an amalgam of other options. For example,
+ // '/Ogyb2' is equivalent to '/Og' '/Oy' '/Ob2'.
+ TranslateOptArg(A, *DAL, SupportsForcingFramePointer, ExpandChar, Opts);
+ } else if (A->getOption().matches(options::OPT_D)) {
+ // Translate -Dfoo#bar into -Dfoo=bar.
+ TranslateDArg(A, *DAL, Opts);
+ } else {
DAL->append(A);
- continue;
- }
-
- StringRef OptStr = A->getValue();
- for (size_t I = 0, E = OptStr.size(); I != E; ++I) {
- const char &OptChar = *(OptStr.data() + I);
- switch (OptChar) {
- default:
- break;
- case '1':
- case '2':
- case 'x':
- case 'd':
- if (&OptChar == ExpandChar) {
- if (OptChar == 'd') {
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_O0));
- } else {
- if (OptChar == '1') {
- DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
- } else if (OptChar == '2' || OptChar == 'x') {
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
- DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
- }
- if (SupportsForcingFramePointer)
- DAL->AddFlagArg(A,
- Opts.getOption(options::OPT_fomit_frame_pointer));
- if (OptChar == '1' || OptChar == '2')
- DAL->AddFlagArg(A,
- Opts.getOption(options::OPT_ffunction_sections));
- }
- }
- break;
- case 'b':
- if (I + 1 != E && isdigit(OptStr[I + 1]))
- ++I;
- break;
- case 'g':
- break;
- case 'i':
- if (I + 1 != E && OptStr[I + 1] == '-') {
- ++I;
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_fno_builtin));
- } else {
- DAL->AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin));
- }
- break;
- case 's':
- DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "s");
- break;
- case 't':
- DAL->AddJoinedArg(A, Opts.getOption(options::OPT_O), "2");
- break;
- case 'y': {
- bool OmitFramePointer = true;
- if (I + 1 != E && OptStr[I + 1] == '-') {
- OmitFramePointer = false;
- ++I;
- }
- if (SupportsForcingFramePointer) {
- if (OmitFramePointer)
- DAL->AddFlagArg(A,
- Opts.getOption(options::OPT_fomit_frame_pointer));
- else
- DAL->AddFlagArg(
- A, Opts.getOption(options::OPT_fno_omit_frame_pointer));
- }
- break;
- }
- }
}
}
+
return DAL;
}
diff --git a/lib/Driver/MinGWToolChain.cpp b/lib/Driver/MinGWToolChain.cpp
index c5287bb41575..938440b08f60 100644
--- a/lib/Driver/MinGWToolChain.cpp
+++ b/lib/Driver/MinGWToolChain.cpp
@@ -66,17 +66,23 @@ MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
: ToolChain(D, Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
- // On Windows if there is no sysroot we search for gcc on the PATH.
- if (getDriver().SysRoot.size())
- Base = getDriver().SysRoot;
+// In Windows there aren't any standard install locations, we search
+// for gcc on the PATH. In Linux the base is always /usr.
#ifdef LLVM_ON_WIN32
+ if (getDriver().SysRoot.size())
+ Base = getDriver().SysRoot;
else if (llvm::ErrorOr<std::string> GPPName =
llvm::sys::findProgramByName("gcc"))
Base = llvm::sys::path::parent_path(
llvm::sys::path::parent_path(GPPName.get()));
-#endif
- if (!Base.size())
+ else
Base = llvm::sys::path::parent_path(getDriver().getInstalledDir());
+#else
+ if (getDriver().SysRoot.size())
+ Base = getDriver().SysRoot;
+ else
+ Base = "/usr";
+#endif
Base += llvm::sys::path::get_separator();
findGccLibDir();
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 7ece3216297f..beede2e05804 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -526,7 +526,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
// no environment variable defined, see if we can set the default based
// on -isysroot.
if (OSXTarget.empty() && iOSTarget.empty() && WatchOSTarget.empty() &&
- Args.hasArg(options::OPT_isysroot)) {
+ TvOSTarget.empty() && Args.hasArg(options::OPT_isysroot)) {
if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
StringRef isysroot = A->getValue();
// Assume SDK has path: SOME_PATH/SDKs/PlatformXX.YY.sdk
@@ -2716,13 +2716,8 @@ const StringRef HexagonToolChain::GetDefaultCPU() {
const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
Arg *CpuArg = nullptr;
-
- for (auto &A : Args) {
- if (A->getOption().matches(options::OPT_mcpu_EQ)) {
- CpuArg = A;
- A->claim();
- }
- }
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ))
+ CpuArg = A;
StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
if (CPU.startswith("hexagon"))
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index f4b6b1529b30..b6fd42696ed4 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -730,9 +730,6 @@ public:
// Until dtrace (via CTF) and LLDB can deal with distributed debug info,
// FreeBSD defaults to standalone/full debug info.
bool GetDefaultStandaloneDebug() const override { return true; }
- llvm::DebuggerKind getDefaultDebuggerTuning() const override {
- return llvm::DebuggerKind::LLDB;
- }
protected:
Tool *buildAssembler() const override;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 84681053dd1a..5a2dbd388fc1 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -2069,6 +2069,16 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args,
CmdArgs.push_back("-machine-sink-split=0");
}
+void Clang::AddWebAssemblyTargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Default to "hidden" visibility.
+ if (!Args.hasArg(options::OPT_fvisibility_EQ,
+ options::OPT_fvisibility_ms_compat)) {
+ CmdArgs.push_back("-fvisibility");
+ CmdArgs.push_back("hidden");
+ }
+}
+
// Decode AArch64 features from string like +[no]featureA+[no]featureB+...
static bool DecodeAArch64Features(const Driver &D, StringRef text,
std::vector<const char *> &Features) {
@@ -2970,7 +2980,7 @@ static void SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T,
ExtractArgs.push_back(OutFile);
const char *Exec = Args.MakeArgString(TC.GetProgramPath("objcopy"));
- InputInfo II(Output.getFilename(), types::TY_Object, Output.getFilename());
+ InputInfo II(types::TY_Object, Output.getFilename(), Output.getFilename());
// First extract the dwo sections.
C.addCommand(llvm::make_unique<Command>(JA, T, Exec, ExtractArgs, II));
@@ -3253,8 +3263,9 @@ ParsePICArgs(const ToolChain &ToolChain, const llvm::Triple &Triple,
// ToolChain.getTriple() and Triple?
bool PIE = ToolChain.isPIEDefault();
bool PIC = PIE || ToolChain.isPICDefault();
- // The Darwin default to use PIC does not apply when using -static.
- if (ToolChain.getTriple().isOSDarwin() && Args.hasArg(options::OPT_static))
+ // The Darwin/MachO default to use PIC does not apply when using -static.
+ if (ToolChain.getTriple().isOSBinFormatMachO() &&
+ Args.hasArg(options::OPT_static))
PIE = PIC = false;
bool IsPICLevelTwo = PIC;
@@ -4015,6 +4026,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
case llvm::Triple::hexagon:
AddHexagonTargetArgs(Args, CmdArgs);
break;
+
+ case llvm::Triple::wasm32:
+ case llvm::Triple::wasm64:
+ AddWebAssemblyTargetArgs(Args, CmdArgs);
+ break;
}
// The 'g' groups options involve a somewhat intricate sequence of decisions
@@ -4176,8 +4192,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-generate-type-units");
}
- // CloudABI uses -ffunction-sections and -fdata-sections by default.
- bool UseSeparateSections = Triple.getOS() == llvm::Triple::CloudABI;
+ // CloudABI and WebAssembly use -ffunction-sections and -fdata-sections by
+ // default.
+ bool UseSeparateSections = Triple.getOS() == llvm::Triple::CloudABI ||
+ Triple.getArch() == llvm::Triple::wasm32 ||
+ Triple.getArch() == llvm::Triple::wasm64;
if (Args.hasFlag(options::OPT_ffunction_sections,
options::OPT_fno_function_sections, UseSeparateSections)) {
@@ -6040,8 +6059,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
// doesn't handle that so rather than warning about unused flags that are
// actually used, we'll lie by omission instead.
// FIXME: Stop lying and consume only the appropriate driver flags
- for (const Arg *A : Args.filtered(options::OPT_W_Group))
- A->claim();
+ Args.ClaimAllArgs(options::OPT_W_Group);
CollectArgsForIntegratedAssembler(C, Args, CmdArgs,
getToolChain().getDriver());
@@ -6078,6 +6096,12 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
for (const auto &A : Args) {
if (forwardToGCC(A->getOption())) {
+ // It is unfortunate that we have to claim here, as this means
+ // we will basically never report anything interesting for
+ // platforms using a generic gcc, even if we are just using gcc
+ // to get to the assembler.
+ A->claim();
+
// Don't forward any -g arguments to assembly steps.
if (isa<AssembleJobAction>(JA) &&
A->getOption().matches(options::OPT_g_Group))
@@ -6088,11 +6112,6 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
A->getOption().matches(options::OPT_W_Group))
continue;
- // It is unfortunate that we have to claim here, as this means
- // we will basically never report anything interesting for
- // platforms using a generic gcc, even if we are just using gcc
- // to get to the assembler.
- A->claim();
A->render(Args, CmdArgs);
}
}
@@ -6502,10 +6521,6 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
std::string Linker = getToolChain().GetProgramPath(getShortName());
ArgStringList CmdArgs;
- CmdArgs.push_back("-flavor");
- CmdArgs.push_back("old-gnu");
- CmdArgs.push_back("-target");
- CmdArgs.push_back(Args.MakeArgString(getToolChain().getTripleString()));
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
@@ -6534,6 +6549,14 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
ArgStringList CmdArgs;
CmdArgs.push_back("-flavor");
CmdArgs.push_back("ld");
+
+ // Enable garbage collection of unused input sections by default, since code
+ // size is of particular importance. This is significantly facilitated by
+ // the enabling of -ffunction-sections and -fdata-sections in
+ // Clang::ConstructJob.
+ if (areOptimizationsEnabled(Args))
+ CmdArgs.push_back("--gc-sections");
+
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
@@ -8965,7 +8988,7 @@ void nacltools::AssemblerARM::ConstructJob(Compilation &C, const JobAction &JA,
const char *LinkingOutput) const {
const toolchains::NaClToolChain &ToolChain =
static_cast<const toolchains::NaClToolChain &>(getToolChain());
- InputInfo NaClMacros(ToolChain.GetNaClArmMacrosPath(), types::TY_PP_Asm,
+ InputInfo NaClMacros(types::TY_PP_Asm, ToolChain.GetNaClArmMacrosPath(),
"nacl-arm-macros.s");
InputInfoList NewInputs;
NewInputs.push_back(NaClMacros);
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 168662f7e7fe..2b137f4a6d0b 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -82,6 +82,8 @@ private:
llvm::opt::ArgStringList &CmdArgs) const;
void AddHexagonTargetArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const;
+ void AddWebAssemblyTargetArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile };
@@ -238,7 +240,7 @@ namespace amdgpu {
class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool {
public:
- Linker(const ToolChain &TC) : GnuTool("amdgpu::Linker", "lld", TC) {}
+ Linker(const ToolChain &TC) : GnuTool("amdgpu::Linker", "ld.lld", TC) {}
bool isLinkJob() const override { return true; }
bool hasIntegratedCPP() const override { return false; }
void ConstructJob(Compilation &C, const JobAction &JA,
diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp
index 9f71168de8fc..482c0f6f8568 100644
--- a/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -1077,6 +1077,9 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLEvent:
return false;
+
+ case CK_BooleanToSignedIntegral:
+ llvm_unreachable("OpenCL-specific cast in Objective-C?");
}
}
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index 8faab2869de6..11183355f73a 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -150,7 +150,12 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
if (Previous.is(tok::semi) && State.LineContainsContinuedForLoopSection)
return true;
if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) ||
- (Previous.is(TT_TemplateCloser) && Current.is(TT_StartOfName)) ||
+ (Previous.is(TT_TemplateCloser) && Current.is(TT_StartOfName) &&
+ // FIXME: This is a temporary workaround for the case where clang-format
+ // sets BreakBeforeParameter to avoid bin packing and this creates a
+ // completely unnecessary line break after a template type that isn't
+ // line-wrapped.
+ (Previous.NestingLevel == 1 || Style.BinPackParameters)) ||
(Style.BreakBeforeTernaryOperators && Current.is(TT_ConditionalExpr) &&
Previous.isNot(tok::question)) ||
(!Style.BreakBeforeTernaryOperators &&
@@ -177,13 +182,15 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
return true;
unsigned NewLineColumn = getNewLineColumn(State);
- if (State.Column <= NewLineColumn)
- return false;
-
if (Current.isMemberAccess() &&
- State.Column + getLengthToNextOperator(Current) > Style.ColumnLimit)
+ State.Column + getLengthToNextOperator(Current) > Style.ColumnLimit &&
+ (State.Column > NewLineColumn ||
+ Current.NestingLevel < State.StartOfLineLevel))
return true;
+ if (State.Column <= NewLineColumn)
+ return false;
+
if (Style.AlwaysBreakBeforeMultilineStrings &&
(NewLineColumn == State.FirstIndent + Style.ContinuationIndentWidth ||
Previous.is(tok::comma) || Current.NestingLevel < 2) &&
@@ -383,7 +390,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
State.Stack.back().LastSpace = State.Column;
State.Stack.back().NestedBlockIndent = State.Column;
} else if (!Current.isOneOf(tok::comment, tok::caret) &&
- (Previous.is(tok::comma) ||
+ ((Previous.is(tok::comma) &&
+ !Previous.is(TT_OverloadedOperator)) ||
(Previous.is(tok::colon) && Previous.is(TT_ObjCMethodExpr)))) {
State.Stack.back().LastSpace = State.Column;
} else if ((Previous.isOneOf(TT_BinaryOperator, TT_ConditionalExpr,
@@ -860,7 +868,7 @@ void ContinuationIndenter::moveStatePastFakeLParens(LineState &State,
(!SkipFirstExtraIndent && *I > prec::Assignment &&
!Current.isTrailingComment()))
NewParenState.Indent += Style.ContinuationIndentWidth;
- if ((Previous && !Previous->opensScope()) || *I > prec::Comma)
+ if ((Previous && !Previous->opensScope()) || *I != prec::Comma)
NewParenState.BreakBeforeParameter = false;
State.Stack.push_back(NewParenState);
SkipFirstExtraIndent = false;
@@ -906,8 +914,12 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
NewIndent = State.Stack.back().LastSpace + Style.ContinuationIndentWidth;
}
const FormatToken *NextNoComment = Current.getNextNonComment();
+ bool EndsInComma = Current.MatchingParen &&
+ Current.MatchingParen->Previous &&
+ Current.MatchingParen->Previous->is(tok::comma);
AvoidBinPacking =
- Current.isOneOf(TT_ArrayInitializerLSquare, TT_DictLiteral) ||
+ (Current.is(TT_ArrayInitializerLSquare) && EndsInComma) ||
+ Current.is(TT_DictLiteral) ||
Style.Language == FormatStyle::LK_Proto || !Style.BinPackArguments ||
(NextNoComment && NextNoComment->is(TT_DesignatedInitializerPeriod));
if (Current.ParameterCount > 1)
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 5068fca5c44d..2689368da513 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -583,6 +583,7 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
GoogleStyle.AlwaysBreakBeforeMultilineStrings = false;
GoogleStyle.BreakBeforeTernaryOperators = false;
+ GoogleStyle.CommentPragmas = "@(export|visibility) {";
GoogleStyle.MaxEmptyLinesToKeep = 3;
GoogleStyle.SpacesInContainerLiterals = false;
} else if (Language == FormatStyle::LK_Proto) {
@@ -1238,6 +1239,8 @@ private:
FormatTok->Type = TT_ImplicitStringLiteral;
break;
}
+ if (FormatTok->Type == TT_ImplicitStringLiteral)
+ break;
}
if (FormatTok->is(TT_ImplicitStringLiteral))
@@ -1901,8 +1904,9 @@ tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
new DiagnosticOptions);
SourceManager SourceMgr(Diagnostics, Files);
- InMemoryFileSystem->addFile(FileName, 0,
- llvm::MemoryBuffer::getMemBuffer(Code, FileName));
+ InMemoryFileSystem->addFile(
+ FileName, 0, llvm::MemoryBuffer::getMemBuffer(
+ Code, FileName, /*RequiresNullTerminator=*/false));
FileID ID = SourceMgr.createFileID(Files.getFile(FileName), SourceLocation(),
clang::SrcMgr::C_User);
SourceLocation StartOfFile = SourceMgr.getLocForStartOfFile(ID);
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index caff1312f300..8fbb43b7996d 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -119,7 +119,9 @@ private:
}
}
- if (Left->Previous &&
+ if (Left->is(TT_OverloadedOperatorLParen)) {
+ Contexts.back().IsExpression = false;
+ } else if (Left->Previous &&
(Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_decltype,
tok::kw_if, tok::kw_while, tok::l_paren,
tok::comma) ||
@@ -132,9 +134,7 @@ private:
// This is a parameter list of a lambda expression.
Contexts.back().IsExpression = false;
} else if (Line.InPPDirective &&
- (!Left->Previous ||
- !Left->Previous->isOneOf(tok::identifier,
- TT_OverloadedOperator))) {
+ (!Left->Previous || !Left->Previous->is(tok::identifier))) {
Contexts.back().IsExpression = true;
} else if (Contexts[Contexts.size() - 2].CaretFound) {
// This is the parameter list of an ObjC block.
@@ -199,6 +199,18 @@ private:
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
+ if (CurrentToken->Next && CurrentToken->Next->is(tok::l_brace) &&
+ Left->Previous && Left->Previous->is(tok::l_paren)) {
+ // Detect the case where macros are used to generate lambdas or
+ // function bodies, e.g.:
+ // auto my_lambda = MARCO((Type *type, int i) { .. body .. });
+ for (FormatToken *Tok = Left; Tok != CurrentToken; Tok = Tok->Next) {
+ if (Tok->is(TT_BinaryOperator) &&
+ Tok->isOneOf(tok::star, tok::amp, tok::ampamp))
+ Tok->Type = TT_PointerOrReference;
+ }
+ }
+
if (StartsObjCMethodExpr) {
CurrentToken->Type = TT_ObjCMethodExpr;
if (Contexts.back().FirstObjCSelectorName) {
@@ -568,7 +580,8 @@ private:
if (CurrentToken->isOneOf(tok::star, tok::amp))
CurrentToken->Type = TT_PointerOrReference;
consumeToken();
- if (CurrentToken && CurrentToken->Previous->is(TT_BinaryOperator))
+ if (CurrentToken &&
+ CurrentToken->Previous->isOneOf(TT_BinaryOperator, tok::comma))
CurrentToken->Previous->Type = TT_OverloadedOperator;
}
if (CurrentToken) {
@@ -1713,7 +1726,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Right.is(Keywords.kw_function) && Left.isNot(tok::comma))
return 100;
if (Left.is(TT_JsTypeColon))
- return 100;
+ return 35;
}
if (Left.is(tok::comma) || (Right.is(tok::identifier) && Right.Next &&
@@ -2058,14 +2071,14 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
if (Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow) ||
Left.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow))
return true;
+ if (Right.is(TT_OverloadedOperatorLParen))
+ return Style.SpaceBeforeParens == FormatStyle::SBPO_Always;
if (Left.is(tok::comma))
return true;
if (Right.is(tok::comma))
return false;
if (Right.isOneOf(TT_CtorInitializerColon, TT_ObjCBlockLParen))
return true;
- if (Right.is(TT_OverloadedOperatorLParen))
- return Style.SpaceBeforeParens == FormatStyle::SBPO_Always;
if (Right.is(tok::colon)) {
if (Line.First->isOneOf(tok::kw_case, tok::kw_default) ||
!Right.getNextNonComment() || Right.getNextNonComment()->is(tok::semi))
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index 94b849881941..7b8f6e652416 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -315,6 +315,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
// definitions, too.
unsigned StoredPosition = Tokens->getPosition();
FormatToken *Tok = FormatTok;
+ const FormatToken *PrevTok = getPreviousToken();
// Keep a stack of positions of lbrace tokens. We will
// update information about whether an lbrace starts a
// braced init list or a different block during the loop.
@@ -331,47 +332,53 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
switch (Tok->Tok.getKind()) {
case tok::l_brace:
- Tok->BlockKind = BK_Unknown;
+ if (Style.Language == FormatStyle::LK_JavaScript && PrevTok &&
+ PrevTok->is(tok::colon))
+ // In TypeScript's TypeMemberLists, there can be semicolons between the
+ // individual members.
+ Tok->BlockKind = BK_BracedInit;
+ else
+ Tok->BlockKind = BK_Unknown;
LBraceStack.push_back(Tok);
break;
case tok::r_brace:
- if (!LBraceStack.empty()) {
- if (LBraceStack.back()->BlockKind == BK_Unknown) {
- bool ProbablyBracedList = false;
- if (Style.Language == FormatStyle::LK_Proto) {
- ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square);
- } else {
- // Using OriginalColumn to distinguish between ObjC methods and
- // binary operators is a bit hacky.
- bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) &&
- NextTok->OriginalColumn == 0;
-
- // If there is a comma, semicolon or right paren after the closing
- // brace, we assume this is a braced initializer list. Note that
- // regardless how we mark inner braces here, we will overwrite the
- // BlockKind later if we parse a braced list (where all blocks
- // inside are by default braced lists), or when we explicitly detect
- // blocks (for example while parsing lambdas).
- //
- // We exclude + and - as they can be ObjC visibility modifiers.
- ProbablyBracedList =
- NextTok->isOneOf(tok::comma, tok::period, tok::colon,
- tok::r_paren, tok::r_square, tok::l_brace,
- tok::l_square, tok::l_paren, tok::ellipsis) ||
- (NextTok->is(tok::semi) &&
- (!ExpectClassBody || LBraceStack.size() != 1)) ||
- (NextTok->isBinaryOperator() && !NextIsObjCMethod);
- }
- if (ProbablyBracedList) {
- Tok->BlockKind = BK_BracedInit;
- LBraceStack.back()->BlockKind = BK_BracedInit;
- } else {
- Tok->BlockKind = BK_Block;
- LBraceStack.back()->BlockKind = BK_Block;
- }
+ if (LBraceStack.empty())
+ break;
+ if (LBraceStack.back()->BlockKind == BK_Unknown) {
+ bool ProbablyBracedList = false;
+ if (Style.Language == FormatStyle::LK_Proto) {
+ ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square);
+ } else {
+ // Using OriginalColumn to distinguish between ObjC methods and
+ // binary operators is a bit hacky.
+ bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) &&
+ NextTok->OriginalColumn == 0;
+
+ // If there is a comma, semicolon or right paren after the closing
+ // brace, we assume this is a braced initializer list. Note that
+ // regardless how we mark inner braces here, we will overwrite the
+ // BlockKind later if we parse a braced list (where all blocks
+ // inside are by default braced lists), or when we explicitly detect
+ // blocks (for example while parsing lambdas).
+ //
+ // We exclude + and - as they can be ObjC visibility modifiers.
+ ProbablyBracedList =
+ NextTok->isOneOf(tok::comma, tok::period, tok::colon,
+ tok::r_paren, tok::r_square, tok::l_brace,
+ tok::l_square, tok::l_paren, tok::ellipsis) ||
+ (NextTok->is(tok::semi) &&
+ (!ExpectClassBody || LBraceStack.size() != 1)) ||
+ (NextTok->isBinaryOperator() && !NextIsObjCMethod);
+ }
+ if (ProbablyBracedList) {
+ Tok->BlockKind = BK_BracedInit;
+ LBraceStack.back()->BlockKind = BK_BracedInit;
+ } else {
+ Tok->BlockKind = BK_Block;
+ LBraceStack.back()->BlockKind = BK_Block;
}
- LBraceStack.pop_back();
}
+ LBraceStack.pop_back();
break;
case tok::at:
case tok::semi:
@@ -381,14 +388,16 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
case tok::kw_switch:
case tok::kw_try:
case tok::kw___try:
- if (!LBraceStack.empty())
+ if (!LBraceStack.empty() && LBraceStack.back()->BlockKind == BK_Unknown)
LBraceStack.back()->BlockKind = BK_Block;
break;
default:
break;
}
+ PrevTok = Tok;
Tok = NextTok;
} while (Tok->Tok.isNot(tok::eof) && !LBraceStack.empty());
+
// Assume other blocks for all unclosed opening braces.
for (unsigned i = 0, e = LBraceStack.size(); i != e; ++i) {
if (LBraceStack[i]->BlockKind == BK_Unknown)
@@ -841,6 +850,8 @@ void UnwrappedLineParser::parseStructuralElement() {
// This does not apply for Java and JavaScript.
if (Style.Language == FormatStyle::LK_Java ||
Style.Language == FormatStyle::LK_JavaScript) {
+ if (FormatTok->is(tok::semi))
+ nextToken();
addUnwrappedLine();
return;
}
@@ -986,13 +997,11 @@ bool UnwrappedLineParser::tryToParseLambda() {
nextToken();
return false;
}
- // FIXME: This is a dirty way to access the previous token. Find a better
- // solution.
- if (!Line->Tokens.empty() &&
- (Line->Tokens.back().Tok->isOneOf(tok::identifier, tok::kw_operator,
- tok::kw_new, tok::kw_delete) ||
- Line->Tokens.back().Tok->closesScope() ||
- Line->Tokens.back().Tok->isSimpleTypeSpecifier())) {
+ const FormatToken* Previous = getPreviousToken();
+ if (Previous &&
+ (Previous->isOneOf(tok::identifier, tok::kw_operator, tok::kw_new,
+ tok::kw_delete) ||
+ Previous->closesScope() || Previous->isSimpleTypeSpecifier())) {
nextToken();
return false;
}
@@ -1174,6 +1183,14 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
nextToken();
return !HasError;
case tok::semi:
+ // JavaScript (or more precisely TypeScript) can have semicolons in braced
+ // lists (in so-called TypeMemberLists). Thus, the semicolon cannot be
+ // used for error recovery if we have otherwise determined that this is
+ // a braced list.
+ if (Style.Language == FormatStyle::LK_JavaScript) {
+ nextToken();
+ break;
+ }
HasError = true;
if (!ContinueOnSemicolons)
return !HasError;
@@ -1792,18 +1809,22 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() {
return;
}
+ // Consume the "abstract" in "export abstract class".
+ if (FormatTok->is(Keywords.kw_abstract))
+ nextToken();
+
if (FormatTok->isOneOf(tok::kw_const, tok::kw_class, tok::kw_enum,
- Keywords.kw_let, Keywords.kw_var))
+ Keywords.kw_interface, Keywords.kw_let,
+ Keywords.kw_var))
return; // Fall through to parsing the corresponding structure.
- if (FormatTok->is(tok::l_brace)) {
- FormatTok->BlockKind = BK_Block;
- parseBracedList();
- }
-
- while (!eof() && FormatTok->isNot(tok::semi) &&
- FormatTok->isNot(tok::l_brace)) {
- nextToken();
+ while (!eof() && FormatTok->isNot(tok::semi)) {
+ if (FormatTok->is(tok::l_brace)) {
+ FormatTok->BlockKind = BK_Block;
+ parseBracedList();
+ } else {
+ nextToken();
+ }
}
}
@@ -1877,6 +1898,14 @@ void UnwrappedLineParser::nextToken() {
readToken();
}
+const FormatToken *UnwrappedLineParser::getPreviousToken() {
+ // FIXME: This is a dirty way to access the previous token. Find a better
+ // solution.
+ if (!Line || Line->Tokens.empty())
+ return nullptr;
+ return Line->Tokens.back().Tok;
+}
+
void UnwrappedLineParser::readToken() {
bool CommentsInCurrentLine = true;
do {
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index a13c03f94086..6d40ab4f3120 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -110,6 +110,7 @@ private:
void addUnwrappedLine();
bool eof() const;
void nextToken();
+ const FormatToken *getPreviousToken();
void readToken();
void flushComments(bool NewlineBeforeNext);
void pushToken(FormatToken *Tok);
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index 725f05bcd8fc..d6e6ed2c2baa 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -30,7 +30,7 @@ WhitespaceManager::Change::Change(
unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn,
unsigned NewlinesBefore, StringRef PreviousLinePostfix,
StringRef CurrentLinePrefix, tok::TokenKind Kind, bool ContinuesPPDirective,
- bool IsStartOfDeclName)
+ bool IsStartOfDeclName, bool IsInsideToken)
: CreateReplacement(CreateReplacement),
OriginalWhitespaceRange(OriginalWhitespaceRange),
StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
@@ -38,8 +38,8 @@ WhitespaceManager::Change::Change(
CurrentLinePrefix(CurrentLinePrefix), Kind(Kind),
ContinuesPPDirective(ContinuesPPDirective),
IsStartOfDeclName(IsStartOfDeclName), IndentLevel(IndentLevel),
- Spaces(Spaces), IsTrailingComment(false), TokenLength(0),
- PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
+ Spaces(Spaces), IsInsideToken(IsInsideToken), IsTrailingComment(false),
+ TokenLength(0), PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
StartOfBlockComment(nullptr), IndentationOffset(0) {}
void WhitespaceManager::reset() {
@@ -55,20 +55,23 @@ void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines,
return;
Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue;
Changes.push_back(
- Change(true, Tok.WhitespaceRange, IndentLevel, Spaces, StartOfTokenColumn,
- Newlines, "", "", Tok.Tok.getKind(), InPPDirective && !Tok.IsFirst,
- Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName)));
+ Change(/*CreateReplacement=*/true, Tok.WhitespaceRange, IndentLevel,
+ Spaces, StartOfTokenColumn, Newlines, "", "", Tok.Tok.getKind(),
+ InPPDirective && !Tok.IsFirst,
+ Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName),
+ /*IsInsideToken=*/false));
}
void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
bool InPPDirective) {
if (Tok.Finalized)
return;
- Changes.push_back(
- Change(false, Tok.WhitespaceRange, /*IndentLevel=*/0,
- /*Spaces=*/0, Tok.OriginalColumn, Tok.NewlinesBefore, "", "",
- Tok.Tok.getKind(), InPPDirective && !Tok.IsFirst,
- Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName)));
+ Changes.push_back(Change(
+ /*CreateReplacement=*/false, Tok.WhitespaceRange, /*IndentLevel=*/0,
+ /*Spaces=*/0, Tok.OriginalColumn, Tok.NewlinesBefore, "", "",
+ Tok.Tok.getKind(), InPPDirective && !Tok.IsFirst,
+ Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName),
+ /*IsInsideToken=*/false));
}
void WhitespaceManager::replaceWhitespaceInToken(
@@ -81,15 +84,10 @@ void WhitespaceManager::replaceWhitespaceInToken(
Changes.push_back(Change(
true, SourceRange(Start, Start.getLocWithOffset(ReplaceChars)),
IndentLevel, Spaces, std::max(0, Spaces), Newlines, PreviousPostfix,
- CurrentPrefix,
- // If we don't add a newline this change doesn't start a comment. Thus,
- // when we align line comments, we don't need to treat this change as one.
- // FIXME: We still need to take this change in account to properly
- // calculate the new length of the comment and to calculate the changes
- // for which to do the alignment when aligning comments.
- Tok.is(TT_LineComment) && Newlines > 0 ? tok::comment : tok::unknown,
+ CurrentPrefix, Tok.is(TT_LineComment) ? tok::comment : tok::unknown,
InPPDirective && !Tok.IsFirst,
- Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName)));
+ Tok.is(TT_StartOfName) || Tok.is(TT_FunctionDeclarationName),
+ /*IsInsideToken=*/Newlines == 0));
}
const tooling::Replacements &WhitespaceManager::generateReplacements() {
@@ -109,6 +107,7 @@ const tooling::Replacements &WhitespaceManager::generateReplacements() {
void WhitespaceManager::calculateLineBreakInformation() {
Changes[0].PreviousEndOfTokenColumn = 0;
+ Change *LastOutsideTokenChange = &Changes[0];
for (unsigned i = 1, e = Changes.size(); i != e; ++i) {
unsigned OriginalWhitespaceStart =
SourceMgr.getFileOffset(Changes[i].OriginalWhitespaceRange.getBegin());
@@ -119,11 +118,20 @@ void WhitespaceManager::calculateLineBreakInformation() {
Changes[i].PreviousLinePostfix.size() +
Changes[i - 1].CurrentLinePrefix.size();
+ // If there are multiple changes in this token, sum up all the changes until
+ // the end of the line.
+ if (Changes[i - 1].IsInsideToken)
+ LastOutsideTokenChange->TokenLength +=
+ Changes[i - 1].TokenLength + Changes[i - 1].Spaces;
+ else
+ LastOutsideTokenChange = &Changes[i - 1];
+
Changes[i].PreviousEndOfTokenColumn =
Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength;
Changes[i - 1].IsTrailingComment =
- (Changes[i].NewlinesBefore > 0 || Changes[i].Kind == tok::eof) &&
+ (Changes[i].NewlinesBefore > 0 || Changes[i].Kind == tok::eof ||
+ (Changes[i].IsInsideToken && Changes[i].Kind == tok::comment)) &&
Changes[i - 1].Kind == tok::comment;
}
// FIXME: The last token is currently not always an eof token; in those
@@ -133,6 +141,10 @@ void WhitespaceManager::calculateLineBreakInformation() {
const WhitespaceManager::Change *LastBlockComment = nullptr;
for (auto &Change : Changes) {
+ // Reset the IsTrailingComment flag for changes inside of trailing comments
+ // so they don't get realigned later.
+ if (Change.IsInsideToken)
+ Change.IsTrailingComment = false;
Change.StartOfBlockComment = nullptr;
Change.IndentationOffset = 0;
if (Change.Kind == tok::comment) {
@@ -342,6 +354,12 @@ void WhitespaceManager::alignTrailingComments() {
unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
unsigned ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
+
+ // If we don't create a replacement for this change, we have to consider
+ // it to be immovable.
+ if (!Changes[i].CreateReplacement)
+ ChangeMaxColumn = ChangeMinColumn;
+
if (i + 1 != e && Changes[i + 1].ContinuesPPDirective)
ChangeMaxColumn -= 2;
// If this comment follows an } in column 0, it probably documents the
diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h
index f83971b4add6..9ca9db6f7488 100644
--- a/lib/Format/WhitespaceManager.h
+++ b/lib/Format/WhitespaceManager.h
@@ -109,7 +109,8 @@ public:
unsigned IndentLevel, int Spaces, unsigned StartOfTokenColumn,
unsigned NewlinesBefore, StringRef PreviousLinePostfix,
StringRef CurrentLinePrefix, tok::TokenKind Kind,
- bool ContinuesPPDirective, bool IsStartOfDeclName);
+ bool ContinuesPPDirective, bool IsStartOfDeclName,
+ bool IsInsideToken);
bool CreateReplacement;
// Changes might be in the middle of a token, so we cannot just keep the
@@ -139,6 +140,10 @@ public:
// comments. Uncompensated negative offset is truncated to 0.
int Spaces;
+ // If this change is inside of a token but not at the start of the token or
+ // directly after a newline.
+ bool IsInsideToken;
+
// \c IsTrailingComment, \c TokenLength, \c PreviousEndOfTokenColumn and
// \c EscapedNewlineColumn will be calculated in
// \c calculateLineBreakInformation.
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 3a32f476566c..237a44704096 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1,4 +1,4 @@
-//===---
+//===--- CompilerInvocation.cpp -------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -2202,8 +2202,11 @@ std::string CompilerInvocation::getModuleHash() const {
code = hash_combine(code, I->first, I->second);
}
- // Extend the signature with the sysroot.
- code = hash_combine(code, hsOpts.Sysroot, hsOpts.UseBuiltinIncludes,
+ // Extend the signature with the sysroot and other header search options.
+ code = hash_combine(code, hsOpts.Sysroot,
+ hsOpts.ModuleFormat,
+ hsOpts.UseDebugInfo,
+ hsOpts.UseBuiltinIncludes,
hsOpts.UseStandardSystemIncludes,
hsOpts.UseStandardCXXIncludes,
hsOpts.UseLibcxx);
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index d6c88d20fc2a..407ccea2e7d1 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -187,15 +187,17 @@ collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr,
return std::error_code();
// Add includes for each of these headers.
- for (Module::Header &H : Module->Headers[Module::HK_Normal]) {
- Module->addTopHeader(H.Entry);
- // Use the path as specified in the module map file. We'll look for this
- // file relative to the module build directory (the directory containing
- // the module map file) so this will find the same file that we found
- // while parsing the module map.
- if (std::error_code Err = addHeaderInclude(H.NameAsWritten, Includes,
- LangOpts, Module->IsExternC))
- return Err;
+ for (auto HK : {Module::HK_Normal, Module::HK_Private}) {
+ for (Module::Header &H : Module->Headers[HK]) {
+ Module->addTopHeader(H.Entry);
+ // Use the path as specified in the module map file. We'll look for this
+ // file relative to the module build directory (the directory containing
+ // the module map file) so this will find the same file that we found
+ // while parsing the module map.
+ if (std::error_code Err = addHeaderInclude(H.NameAsWritten, Includes,
+ LangOpts, Module->IsExternC))
+ return Err;
+ }
}
// Note that Module->PrivateHeaders will not be a TopHeader.
diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp
index 12c85240bd75..f8b73e9034b3 100644
--- a/lib/Frontend/MultiplexConsumer.cpp
+++ b/lib/Frontend/MultiplexConsumer.cpp
@@ -119,6 +119,7 @@ public:
const FunctionDecl *Delete) override;
void CompletedImplicitDefinition(const FunctionDecl *D) override;
void StaticDataMemberInstantiated(const VarDecl *D) override;
+ void DefaultArgumentInstantiated(const ParmVarDecl *D) override;
void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD) override;
void FunctionDefinitionInstantiated(const FunctionDecl *D) override;
@@ -193,6 +194,11 @@ void MultiplexASTMutationListener::StaticDataMemberInstantiated(
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->StaticDataMemberInstantiated(D);
}
+void MultiplexASTMutationListener::DefaultArgumentInstantiated(
+ const ParmVarDecl *D) {
+ for (size_t i = 0, e = Listeners.size(); i != e; ++i)
+ Listeners[i]->DefaultArgumentInstantiated(D);
+}
void MultiplexASTMutationListener::AddedObjCCategoryToInterface(
const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD) {
diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h
index dc0dcbc7385c..a5b4f7434d1c 100644
--- a/lib/Headers/altivec.h
+++ b/lib/Headers/altivec.h
@@ -1891,6 +1891,22 @@ static vector float __ATTRS_o_ai vec_ctf(vector unsigned int __a, int __b) {
return __builtin_altivec_vcfux((vector int)__a, __b);
}
+#ifdef __VSX__
+static vector double __ATTRS_o_ai vec_ctf(vector unsigned long long __a,
+ int __b) {
+ vector double __ret = __builtin_convertvector(__a, vector double);
+ __ret *= (vector double)(vector unsigned long long)((0x3ffULL - __b) << 52);
+ return __ret;
+}
+
+static vector double __ATTRS_o_ai vec_ctf(vector signed long long __a,
+ int __b) {
+ vector double __ret = __builtin_convertvector(__a, vector double);
+ __ret *= (vector double)(vector unsigned long long)((0x3ffULL - __b) << 52);
+ return __ret;
+}
+#endif
+
/* vec_vcfsx */
static vector float __attribute__((__always_inline__))
@@ -1907,11 +1923,18 @@ vec_vcfux(vector unsigned int __a, int __b) {
/* vec_cts */
-static vector int __attribute__((__always_inline__))
-vec_cts(vector float __a, int __b) {
+static vector int __ATTRS_o_ai vec_cts(vector float __a, int __b) {
return __builtin_altivec_vctsxs(__a, __b);
}
+#ifdef __VSX__
+static vector signed long long __ATTRS_o_ai vec_cts(vector double __a,
+ int __b) {
+ __a *= (vector double)(vector unsigned long long)((0x3ffULL + __b) << 52);
+ return __builtin_convertvector(__a, vector signed long long);
+}
+#endif
+
/* vec_vctsxs */
static vector int __attribute__((__always_inline__))
@@ -1921,11 +1944,18 @@ vec_vctsxs(vector float __a, int __b) {
/* vec_ctu */
-static vector unsigned int __attribute__((__always_inline__))
-vec_ctu(vector float __a, int __b) {
+static vector unsigned int __ATTRS_o_ai vec_ctu(vector float __a, int __b) {
return __builtin_altivec_vctuxs(__a, __b);
}
+#ifdef __VSX__
+static vector unsigned long long __ATTRS_o_ai vec_ctu(vector double __a,
+ int __b) {
+ __a *= (vector double)(vector unsigned long long)((0x3ffULL + __b) << 52);
+ return __builtin_convertvector(__a, vector unsigned long long);
+}
+#endif
+
/* vec_vctuxs */
static vector unsigned int __attribute__((__always_inline__))
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 8a686a7f3d74..2d005dd2e1f0 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -153,8 +153,7 @@ std::string HeaderSearch::getModuleFileName(StringRef ModuleName,
auto FileName = llvm::sys::path::filename(ModuleMapPath);
llvm::hash_code Hash =
- llvm::hash_combine(DirName.lower(), FileName.lower(),
- HSOpts->ModuleFormat, HSOpts->UseDebugInfo);
+ llvm::hash_combine(DirName.lower(), FileName.lower());
SmallString<128> HashStr;
llvm::APInt(64, size_t(Hash)).toStringUnsigned(HashStr, /*Radix*/36);
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 1e7858af8948..5b1c49344e8d 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -983,6 +983,7 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) {
/// u' c-char-sequence '
/// U' c-char-sequence '
/// L' c-char-sequence '
+/// u8' c-char-sequence ' [C++1z lex.ccon]
/// c-char-sequence:
/// c-char
/// c-char-sequence c-char
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 3134790ccb90..afb41a240776 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -876,6 +876,22 @@ struct PragmaDebugHandler : public PragmaHandler {
Crasher.setKind(tok::annot_pragma_parser_crash);
Crasher.setAnnotationRange(SourceRange(Tok.getLocation()));
PP.EnterToken(Crasher);
+ } else if (II->isStr("dump")) {
+ Token Identifier;
+ PP.LexUnexpandedToken(Identifier);
+ if (auto *DumpII = Identifier.getIdentifierInfo()) {
+ Token DumpAnnot;
+ DumpAnnot.startToken();
+ DumpAnnot.setKind(tok::annot_pragma_dump);
+ DumpAnnot.setAnnotationRange(
+ SourceRange(Tok.getLocation(), Identifier.getLocation()));
+ DumpAnnot.setAnnotationValue(DumpII);
+ PP.DiscardUntilEndOfDirective();
+ PP.EnterToken(DumpAnnot);
+ } else {
+ PP.Diag(Identifier, diag::warn_pragma_debug_missing_argument)
+ << II->getName();
+ }
} else if (II->isStr("llvm_fatal_error")) {
llvm::report_fatal_error("#pragma clang __debug llvm_fatal_error");
} else if (II->isStr("llvm_unreachable")) {
@@ -887,7 +903,8 @@ struct PragmaDebugHandler : public PragmaHandler {
if (MacroII)
PP.dumpMacroInfo(MacroII);
else
- PP.Diag(MacroName, diag::warn_pragma_diagnostic_invalid);
+ PP.Diag(MacroName, diag::warn_pragma_debug_missing_argument)
+ << II->getName();
} else if (II->isStr("overflow_stack")) {
DebugOverflowStack();
} else if (II->isStr("handle_crash")) {
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index e69bb2745c43..c64b97d01b9a 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -3326,6 +3326,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw___bool:
isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID, Policy);
break;
+ case tok::kw_pipe:
+ if (!getLangOpts().OpenCL || (getLangOpts().OpenCLVersion < 200)) {
+ // OpenCL 2.0 defined this keyword. OpenCL 1.2 and earlier should
+ // support the "pipe" word as identifier.
+ Tok.getIdentifierInfo()->revertTokenIDToIdentifier();
+ goto DoneWithDeclSpec;
+ }
+ isInvalid = DS.SetTypePipe(true, Loc, PrevSpec, DiagID, Policy);
+ break;
case tok::kw___unknown_anytype:
isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc,
PrevSpec, DiagID, Policy);
@@ -4401,6 +4410,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
switch (Tok.getKind()) {
default: return false;
+ case tok::kw_pipe:
+ return getLangOpts().OpenCL && (getLangOpts().OpenCLVersion >= 200);
+
case tok::identifier: // foo::bar
// Unfortunate hack to support "Class.factoryMethod" notation.
if (getLangOpts().ObjC1 && NextToken().is(tok::period))
@@ -4847,6 +4859,9 @@ static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang,
if (Kind == tok::star || Kind == tok::caret)
return true;
+ if ((Kind == tok::kw_pipe) && Lang.OpenCL && (Lang.OpenCLVersion >= 200))
+ return true;
+
if (!Lang.CPlusPlus)
return false;
@@ -4865,6 +4880,17 @@ static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang,
return false;
}
+// Indicates whether the given declarator is a pipe declarator.
+static bool isPipeDeclerator(const Declarator &D) {
+ const unsigned NumTypes = D.getNumTypeObjects();
+
+ for (unsigned Idx = 0; Idx != NumTypes; ++Idx)
+ if (DeclaratorChunk::Pipe == D.getTypeObject(Idx).Kind)
+ return true;
+
+ return false;
+}
+
/// ParseDeclaratorInternal - Parse a C or C++ declarator. The direct-declarator
/// is parsed by the function passed to it. Pass null, and the direct-declarator
/// isn't parsed at all, making this function effectively parse the C++
@@ -4941,6 +4967,15 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
}
tok::TokenKind Kind = Tok.getKind();
+
+ if (D.getDeclSpec().isTypeSpecPipe() && !isPipeDeclerator(D)) {
+ DeclSpec &DS = D.getMutableDeclSpec();
+
+ D.AddTypeInfo(
+ DeclaratorChunk::getPipe(DS.getTypeQualifiers(), DS.getPipeLoc()),
+ DS.getAttributes(), SourceLocation());
+ }
+
// Not a pointer, C++ reference, or block.
if (!isPtrOperatorToken(Kind, getLangOpts(), D.getContext())) {
if (DirectDeclParser)
@@ -6092,6 +6127,7 @@ void Parser::ParseMisplacedBracketDeclarator(Declarator &D) {
case DeclaratorChunk::Reference:
case DeclaratorChunk::BlockPointer:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
NeedParens = true;
break;
case DeclaratorChunk::Array:
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index a4de9751f9a0..3f22ad4ddaba 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -3363,7 +3363,8 @@ Parser::tryParseExceptionSpecification(bool Delayed,
ConsumeAndStoreUntil(tok::r_paren, *ExceptionSpecTokens,
/*StopAtSemi=*/true,
/*ConsumeFinalToken=*/true);
- SpecificationRange.setEnd(Tok.getLocation());
+ SpecificationRange.setEnd(ExceptionSpecTokens->back().getLocation());
+
return EST_Unparsed;
}
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index 078f4c388705..a08db5490fa9 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -165,8 +165,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
/// 'distribute'
/// annot_pragma_openmp_end
///
-StmtResult
-Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
+StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
+ AllowedContsructsKind Allowed) {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
ParenBraceBracketBalancer BalancerRAIIObj(*this);
SmallVector<Expr *, 5> Identifiers;
@@ -186,6 +186,10 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
switch (DKind) {
case OMPD_threadprivate:
+ if (Allowed != ACK_Any) {
+ Diag(Tok, diag::err_omp_immediate_directive)
+ << getOpenMPDirectiveName(DKind) << 0;
+ }
ConsumeToken();
if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) {
// The last seen token is annot_pragma_openmp_end - need to check for
@@ -213,7 +217,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_cancel:
- if (!StandAloneAllowed) {
+ if (Allowed == ACK_StatementsOpenMPNonStandalone) {
Diag(Tok, diag::err_omp_immediate_directive)
<< getOpenMPDirectiveName(DKind) << 0;
}
@@ -299,7 +303,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
// If the depend clause is specified, the ordered construct is a stand-alone
// directive.
if (DKind == OMPD_ordered && FirstClauses[OMPC_depend].getInt()) {
- if (!StandAloneAllowed) {
+ if (Allowed == ACK_StatementsOpenMPNonStandalone) {
Diag(Loc, diag::err_omp_immediate_directive)
<< getOpenMPDirectiveName(DKind) << 1
<< getOpenMPClauseName(OMPC_depend);
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 4430eb8d03da..bc70942851e2 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -377,6 +377,14 @@ void Parser::HandlePragmaAlign() {
Actions.ActOnPragmaOptionsAlign(Kind, PragmaLoc);
}
+void Parser::HandlePragmaDump() {
+ assert(Tok.is(tok::annot_pragma_dump));
+ IdentifierInfo *II =
+ reinterpret_cast<IdentifierInfo *>(Tok.getAnnotationValue());
+ Actions.ActOnPragmaDump(getCurScope(), Tok.getLocation(), II);
+ ConsumeToken();
+}
+
void Parser::HandlePragmaWeak() {
assert(Tok.is(tok::annot_pragma_weak));
SourceLocation PragmaLoc = ConsumeToken();
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 717bcff0c168..edf0dda7df8c 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -32,14 +32,18 @@ using namespace clang;
/// \brief Parse a standalone statement (for instance, as the body of an 'if',
/// 'while', or 'for').
-StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc) {
+StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc,
+ bool AllowOpenMPStandalone) {
StmtResult Res;
// We may get back a null statement if we found a #pragma. Keep going until
// we get an actual statement.
do {
StmtVector Stmts;
- Res = ParseStatementOrDeclaration(Stmts, true, TrailingElseLoc);
+ Res = ParseStatementOrDeclaration(
+ Stmts, AllowOpenMPStandalone ? ACK_StatementsOpenMPAnyExecutable
+ : ACK_StatementsOpenMPNonStandalone,
+ TrailingElseLoc);
} while (!Res.isInvalid() && !Res.get());
return Res;
@@ -95,7 +99,8 @@ StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc) {
/// [OBC] '@' 'throw' ';'
///
StmtResult
-Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement,
+Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
+ AllowedContsructsKind Allowed,
SourceLocation *TrailingElseLoc) {
ParenBraceBracketBalancer BalancerRAIIObj(*this);
@@ -103,8 +108,8 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement,
ParsedAttributesWithRange Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true);
- StmtResult Res = ParseStatementOrDeclarationAfterAttributes(Stmts,
- OnlyStatement, TrailingElseLoc, Attrs);
+ StmtResult Res = ParseStatementOrDeclarationAfterAttributes(
+ Stmts, Allowed, TrailingElseLoc, Attrs);
assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) &&
"attributes on empty statement");
@@ -146,7 +151,7 @@ private:
StmtResult
Parser::ParseStatementOrDeclarationAfterAttributes(StmtVector &Stmts,
- bool OnlyStatement, SourceLocation *TrailingElseLoc,
+ AllowedContsructsKind Allowed, SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs) {
const char *SemiError = nullptr;
StmtResult Res;
@@ -202,7 +207,8 @@ Retry:
}
default: {
- if ((getLangOpts().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
+ if ((getLangOpts().CPlusPlus || Allowed == ACK_Any) &&
+ isDeclarationStatement()) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy Decl = ParseDeclaration(Declarator::BlockContext,
DeclEnd, Attrs);
@@ -346,7 +352,7 @@ Retry:
case tok::annot_pragma_openmp:
ProhibitAttributes(Attrs);
- return ParseOpenMPDeclarativeOrExecutableDirective(!OnlyStatement);
+ return ParseOpenMPDeclarativeOrExecutableDirective(Allowed);
case tok::annot_pragma_ms_pointers_to_members:
ProhibitAttributes(Attrs);
@@ -365,7 +371,11 @@ Retry:
case tok::annot_pragma_loop_hint:
ProhibitAttributes(Attrs);
- return ParsePragmaLoopHint(Stmts, OnlyStatement, TrailingElseLoc, Attrs);
+ return ParsePragmaLoopHint(Stmts, Allowed, TrailingElseLoc, Attrs);
+
+ case tok::annot_pragma_dump:
+ HandlePragmaDump();
+ return StmtEmpty();
}
// If we reached this code, the statement must end in a semicolon.
@@ -583,7 +593,8 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs) {
// can't handle GNU attributes), so only call it in the one case where
// GNU attributes are allowed.
SubStmt = ParseStatementOrDeclarationAfterAttributes(
- Stmts, /*OnlyStmts*/ true, nullptr, TempAttrs);
+ Stmts, /*Allowed=*/ACK_StatementsOpenMPNonStandalone, nullptr,
+ TempAttrs);
if (!TempAttrs.empty() && !SubStmt.isInvalid())
SubStmt = Actions.ProcessStmtAttributes(
SubStmt.get(), TempAttrs.getList(), TempAttrs.Range);
@@ -722,7 +733,8 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
// continue parsing the sub-stmt.
if (Case.isInvalid()) {
if (TopLevelCase.isInvalid()) // No parsed case stmts.
- return ParseStatement();
+ return ParseStatement(/*TrailingElseLoc=*/nullptr,
+ /*AllowOpenMPStandalone=*/true);
// Otherwise, just don't add it as a nested case.
} else {
// If this is the first case statement we parsed, it becomes TopLevelCase.
@@ -742,7 +754,8 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) {
StmtResult SubStmt;
if (Tok.isNot(tok::r_brace)) {
- SubStmt = ParseStatement();
+ SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr,
+ /*AllowOpenMPStandalone=*/true);
} else {
// Nicely diagnose the common error "switch (X) { case 4: }", which is
// not valid. If ColonLoc doesn't point to a valid text location, there was
@@ -794,7 +807,8 @@ StmtResult Parser::ParseDefaultStatement() {
StmtResult SubStmt;
if (Tok.isNot(tok::r_brace)) {
- SubStmt = ParseStatement();
+ SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr,
+ /*AllowOpenMPStandalone=*/true);
} else {
// Diagnose the common error "switch (X) {... default: }", which is
// not valid.
@@ -893,6 +907,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
case tok::annot_pragma_ms_vtordisp:
HandlePragmaMSVtorDisp();
break;
+ case tok::annot_pragma_dump:
+ HandlePragmaDump();
+ break;
default:
checkForPragmas = false;
break;
@@ -965,7 +982,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
StmtResult R;
if (Tok.isNot(tok::kw___extension__)) {
- R = ParseStatementOrDeclaration(Stmts, false);
+ R = ParseStatementOrDeclaration(Stmts, ACK_Any);
} else {
// __extension__ can start declarations and it can also be a unary
// operator for expressions. Consume multiple __extension__ markers here
@@ -1861,7 +1878,8 @@ StmtResult Parser::ParseReturnStatement() {
return Actions.ActOnReturnStmt(ReturnLoc, R.get(), getCurScope());
}
-StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, bool OnlyStatement,
+StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts,
+ AllowedContsructsKind Allowed,
SourceLocation *TrailingElseLoc,
ParsedAttributesWithRange &Attrs) {
// Create temporary attribute list.
@@ -1884,7 +1902,7 @@ StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, bool OnlyStatement,
MaybeParseCXX11Attributes(Attrs);
StmtResult S = ParseStatementOrDeclarationAfterAttributes(
- Stmts, OnlyStatement, TrailingElseLoc, Attrs);
+ Stmts, Allowed, TrailingElseLoc, Attrs);
Attrs.takeAllFrom(TempAttrs);
return S;
@@ -2182,7 +2200,7 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
// Condition is true, parse the statements.
while (Tok.isNot(tok::r_brace)) {
- StmtResult R = ParseStatementOrDeclaration(Stmts, false);
+ StmtResult R = ParseStatementOrDeclaration(Stmts, ACK_Any);
if (R.isUsable())
Stmts.push_back(R.get());
}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index b3eeb9d58ff4..ccefb3dd3f5d 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -668,6 +668,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::annot_pragma_ms_pragma:
HandlePragmaMSPragma();
return DeclGroupPtrTy();
+ case tok::annot_pragma_dump:
+ HandlePragmaDump();
+ return DeclGroupPtrTy();
case tok::semi:
// Either a C++11 empty-declaration or attribute-declaration.
SingleDecl = Actions.ActOnEmptyDeclaration(getCurScope(),
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index d664d8704003..6f6c4ca5848f 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -270,6 +270,7 @@ bool Declarator::isDeclarationOfFunction() const {
case DeclaratorChunk::Array:
case DeclaratorChunk::BlockPointer:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
return false;
}
llvm_unreachable("Invalid type chunk");
@@ -713,6 +714,22 @@ bool DeclSpec::SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc,
return false;
}
+bool DeclSpec::SetTypePipe(bool isPipe, SourceLocation Loc,
+ const char *&PrevSpec, unsigned &DiagID,
+ const PrintingPolicy &Policy) {
+
+ if (TypeSpecType != TST_unspecified) {
+ PrevSpec = DeclSpec::getSpecifierName((TST)TypeSpecType, Policy);
+ DiagID = diag::err_invalid_decl_spec_combination;
+ return true;
+ }
+
+ if (isPipe) {
+ TypeSpecPipe = TSP_pipe;
+ }
+ return false;
+}
+
bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc,
const char *&PrevSpec, unsigned &DiagID,
const PrintingPolicy &Policy) {
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index 07b058911c2d..ad1d7da4d070 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -2105,6 +2105,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
&& (SrcExpr.get()->getType()->isIntegerType()
|| SrcExpr.get()->getType()->isFloatingType())) {
Kind = CK_VectorSplat;
+ SrcExpr = Self.prepareVectorSplat(DestType, SrcExpr.get());
return;
}
@@ -2339,6 +2340,7 @@ void CastOperation::CheckCStyleCast() {
if (DestVecTy->getVectorKind() == VectorType::AltiVecVector &&
(SrcType->isIntegerType() || SrcType->isFloatingType())) {
Kind = CK_VectorSplat;
+ SrcExpr = Self.prepareVectorSplat(DestType, SrcExpr.get());
} else if (Self.CheckVectorCast(OpRange, DestType, SrcType, Kind)) {
SrcExpr = ExprError();
}
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index cbdcb5e48391..6c2834b750ae 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -6243,7 +6243,8 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
IntRange OutputTypeRange = IntRange::forValueOfType(C, GetExprType(CE));
- bool isIntegerCast = (CE->getCastKind() == CK_IntegralCast);
+ bool isIntegerCast = CE->getCastKind() == CK_IntegralCast ||
+ CE->getCastKind() == CK_BooleanToSignedIntegral;
// Assume that non-integer casts can span the full range of the type.
if (!isIntegerCast)
@@ -7047,6 +7048,10 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
E->getExprLoc()))
return;
+ // Don't warn on functions which have return type nullptr_t.
+ if (isa<CallExpr>(E))
+ return;
+
// Check for NULL (GNUNull) or nullptr (CXX11_nullptr).
const Expr::NullPointerConstantKind NullKind =
E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull);
@@ -7062,8 +7067,12 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
// __null is usually wrapped in a macro. Go up a macro if that is the case.
if (NullKind == Expr::NPCK_GNUNull) {
- if (Loc.isMacroID())
- Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
+ if (Loc.isMacroID()) {
+ StringRef MacroName =
+ Lexer::getImmediateMacroName(Loc, S.SourceMgr, S.getLangOpts());
+ if (MacroName == "NULL")
+ Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
+ }
}
// Only warn if the null and context location are in the same macro expansion.
@@ -7845,6 +7854,10 @@ void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) {
void Sema::CheckForIntOverflow (Expr *E) {
if (isa<BinaryOperator>(E->IgnoreParenCasts()))
E->IgnoreParenCasts()->EvaluateForOverflow(Context);
+ else if (auto InitList = dyn_cast<InitListExpr>(E))
+ for (Expr *E : InitList->inits())
+ if (isa<BinaryOperator>(E->IgnoreParenCasts()))
+ E->IgnoreParenCasts()->EvaluateForOverflow(Context);
}
namespace {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index f27fb2b10712..f95d1068cc59 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3962,9 +3962,6 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef,
Sema::ForRedeclaration);
if (!SemaRef.LookupName(R, S)) return false;
- if (R.getAsSingle<TagDecl>())
- return false;
-
// Pick a representative declaration.
NamedDecl *PrevDecl = R.getRepresentativeDecl()->getUnderlyingDecl();
assert(PrevDecl && "Expected a non-null Decl");
@@ -4675,11 +4672,13 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC,
DeclarationNameInfo NameInfo) {
DeclarationName Name = NameInfo.getName();
- if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
- if (Record->getIdentifier() && Record->getDeclName() == Name) {
- Diag(NameInfo.getLoc(), diag::err_member_name_of_class) << Name;
- return true;
- }
+ CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC);
+ while (Record && Record->isAnonymousStructOrUnion())
+ Record = dyn_cast<CXXRecordDecl>(Record->getParent());
+ if (Record && Record->getIdentifier() && Record->getDeclName() == Name) {
+ Diag(NameInfo.getLoc(), diag::err_member_name_of_class) << Name;
+ return true;
+ }
return false;
}
@@ -8257,6 +8256,23 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
for (auto Param : NewFD->params())
checkIsValidOpenCLKernelParameter(*this, D, Param, ValidTypes);
}
+ for (FunctionDecl::param_iterator PI = NewFD->param_begin(),
+ PE = NewFD->param_end(); PI != PE; ++PI) {
+ ParmVarDecl *Param = *PI;
+ QualType PT = Param->getType();
+
+ // OpenCL 2.0 pipe restrictions forbids pipe packet types to be non-value
+ // types.
+ if (getLangOpts().OpenCLVersion >= 200) {
+ if(const PipeType *PipeTy = PT->getAs<PipeType>()) {
+ QualType ElemTy = PipeTy->getElementType();
+ if (ElemTy->isReferenceType() || ElemTy->isPointerType()) {
+ Diag(Param->getTypeSpecStartLoc(), diag::err_reference_pipe_type );
+ D.setInvalidType();
+ }
+ }
+ }
+ }
MarkUnusedFileScopedDecl(NewFD);
@@ -11799,6 +11815,28 @@ static bool isAcceptableTagRedeclContext(Sema &S, DeclContext *OldDC,
return false;
}
+/// Find the DeclContext in which a tag is implicitly declared if we see an
+/// elaborated type specifier in the specified context, and lookup finds
+/// nothing.
+static DeclContext *getTagInjectionContext(DeclContext *DC) {
+ while (!DC->isFileContext() && !DC->isFunctionOrMethod())
+ DC = DC->getParent();
+ return DC;
+}
+
+/// Find the Scope in which a tag is implicitly declared if we see an
+/// elaborated type specifier in the specified context, and lookup finds
+/// nothing.
+static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) {
+ while (S->isClassScope() ||
+ (LangOpts.CPlusPlus &&
+ S->isFunctionPrototypeScope()) ||
+ ((S->getFlags() & Scope::DeclScope) == 0) ||
+ (S->getEntity() && S->getEntity()->isTransparentContext()))
+ S = S->getParent();
+ return S;
+}
+
/// \brief This is invoked when we see 'struct foo' or 'struct {'. In the
/// former case, Name will be non-null. In the later case, Name will be null.
/// TagSpec indicates what kind of tag this is. TUK indicates whether this is a
@@ -12115,16 +12153,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// Find the context where we'll be declaring the tag.
// FIXME: We would like to maintain the current DeclContext as the
// lexical context,
- while (!SearchDC->isFileContext() && !SearchDC->isFunctionOrMethod())
- SearchDC = SearchDC->getParent();
+ SearchDC = getTagInjectionContext(SearchDC);
// Find the scope where we'll be declaring the tag.
- while (S->isClassScope() ||
- (getLangOpts().CPlusPlus &&
- S->isFunctionPrototypeScope()) ||
- ((S->getFlags() & Scope::DeclScope) == 0) ||
- (S->getEntity() && S->getEntity()->isTransparentContext()))
- S = S->getParent();
+ S = getTagInjectionScope(S, getLangOpts());
} else {
assert(TUK == TUK_Friend);
// C++ [namespace.memdef]p3:
@@ -12284,7 +12316,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
} else if (TUK == TUK_Reference &&
(PrevTagDecl->getFriendObjectKind() ==
Decl::FOK_Undeclared ||
- getOwningModule(PrevDecl) !=
+ PP.getModuleContainingLocation(
+ PrevDecl->getLocation()) !=
PP.getModuleContainingLocation(KWLoc)) &&
SS.isEmpty()) {
// This declaration is a reference to an existing entity, but
@@ -12294,14 +12327,12 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// the declaration would have meant the same thing if no prior
// declaration were found, that is, if it was found in the same
// scope where we would have injected a declaration.
- DeclContext *InjectedDC = CurContext;
- while (!InjectedDC->isFileContext() &&
- !InjectedDC->isFunctionOrMethod())
- InjectedDC = InjectedDC->getParent();
- if (!InjectedDC->getRedeclContext()->Equals(
- PrevDecl->getDeclContext()->getRedeclContext()))
+ if (!getTagInjectionContext(CurContext)->getRedeclContext()
+ ->Equals(PrevDecl->getDeclContext()->getRedeclContext()))
return PrevTagDecl;
- // This is in the injected scope, create a new declaration.
+ // This is in the injected scope, create a new declaration in
+ // that scope.
+ S = getTagInjectionScope(S, getLangOpts());
} else {
return PrevTagDecl;
}
@@ -12603,7 +12634,7 @@ CreateNewDecl:
<< Name;
Invalid = true;
}
- } else {
+ } else if (!PrevDecl) {
Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New);
}
DeclsInPrototypeScope.push_back(New);
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 5a0f0f84af7e..f94c822b90f5 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -348,6 +348,25 @@ static void handleSimpleAttribute(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
+template <typename AttrType>
+static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ handleSimpleAttribute<AttrType>(S, D, Attr);
+}
+
+/// \brief Applies the given attribute to the Decl so long as the Decl doesn't
+/// already have one of the given incompatible attributes.
+template <typename AttrType, typename IncompatibleAttrType,
+ typename... IncompatibleAttrTypes>
+static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, Attr.getRange(),
+ Attr.getName()))
+ return;
+ handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D,
+ Attr);
+}
+
/// \brief Check if the passed-in expression is of type int or bool.
static bool isIntOrBool(Expr *Exp) {
QualType QT = Exp->getType();
@@ -3588,6 +3607,12 @@ static void handleOptimizeNoneAttr(Sema &S, Decl *D,
}
static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (checkAttrMutualExclusion<CUDADeviceAttr>(S, D, Attr.getRange(),
+ Attr.getName()) ||
+ checkAttrMutualExclusion<CUDAHostAttr>(S, D, Attr.getRange(),
+ Attr.getName())) {
+ return;
+ }
FunctionDecl *FD = cast<FunctionDecl>(D);
if (!FD->getReturnType()->isVoidType()) {
SourceRange RTRange = FD->getReturnTypeSourceRange();
@@ -4558,14 +4583,6 @@ static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
handleARMInterruptAttr(S, D, Attr);
}
-static void handleMips16Attribute(Sema &S, Decl *D, const AttributeList &Attr) {
- if (checkAttrMutualExclusion<MipsInterruptAttr>(S, D, Attr.getRange(),
- Attr.getName()))
- return;
-
- handleSimpleAttribute<Mips16Attr>(S, D, Attr);
-}
-
static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
uint32_t NumRegs;
@@ -4955,7 +4972,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleDLLAttr(S, D, Attr);
break;
case AttributeList::AT_Mips16:
- handleMips16Attribute(S, D, Attr);
+ handleSimpleAttributeWithExclusions<Mips16Attr, MipsInterruptAttr>(S, D,
+ Attr);
break;
case AttributeList::AT_NoMips16:
handleSimpleAttribute<NoMips16Attr>(S, D, Attr);
@@ -5006,7 +5024,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleCommonAttr(S, D, Attr);
break;
case AttributeList::AT_CUDAConstant:
- handleSimpleAttribute<CUDAConstantAttr>(S, D, Attr);
+ handleSimpleAttributeWithExclusions<CUDAConstantAttr, CUDASharedAttr>(S, D,
+ Attr);
break;
case AttributeList::AT_PassObjectSize:
handlePassObjectSizeAttr(S, D, Attr);
@@ -5051,10 +5070,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleGlobalAttr(S, D, Attr);
break;
case AttributeList::AT_CUDADevice:
- handleSimpleAttribute<CUDADeviceAttr>(S, D, Attr);
+ handleSimpleAttributeWithExclusions<CUDADeviceAttr, CUDAGlobalAttr>(S, D,
+ Attr);
break;
case AttributeList::AT_CUDAHost:
- handleSimpleAttribute<CUDAHostAttr>(S, D, Attr);
+ handleSimpleAttributeWithExclusions<CUDAHostAttr, CUDAGlobalAttr>(S, D,
+ Attr);
break;
case AttributeList::AT_GNUInline:
handleGNUInlineAttr(S, D, Attr);
@@ -5114,7 +5135,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleSimpleAttribute<NoThrowAttr>(S, D, Attr);
break;
case AttributeList::AT_CUDAShared:
- handleSimpleAttribute<CUDASharedAttr>(S, D, Attr);
+ handleSimpleAttributeWithExclusions<CUDASharedAttr, CUDAConstantAttr>(S, D,
+ Attr);
break;
case AttributeList::AT_VecReturn:
handleVecReturnAttr(S, D, Attr);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 02091a7bd530..11f232934e5a 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -7000,6 +7000,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
case DeclaratorChunk::BlockPointer:
case DeclaratorChunk::Reference:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
extendLeft(Before, Chunk.getSourceRange());
break;
@@ -7796,6 +7797,10 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(*I))
PrevShadow = Shadow;
FoundEquivalentDecl = true;
+ } else if (isEquivalentInternalLinkageDeclaration(D, Target)) {
+ // We don't conflict with an existing using shadow decl of an equivalent
+ // declaration, but we're not a redeclaration of it.
+ FoundEquivalentDecl = true;
}
if (isVisible(D))
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 5d0c6057f54f..3e89af625d1a 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -3084,6 +3084,8 @@ ExprResult Sema::ActOnCharacterConstant(const Token &Tok, Scope *UDLScope) {
Kind = CharacterLiteral::UTF16;
else if (Literal.isUTF32())
Kind = CharacterLiteral::UTF32;
+ else if (Literal.isUTF8())
+ Kind = CharacterLiteral::UTF8;
Expr *Lit = new (Context) CharacterLiteral(Literal.getValue(), Kind, Ty,
Tok.getLocation());
@@ -4313,10 +4315,16 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
if (Result.isInvalid())
return ExprError();
- Expr *Arg = Result.getAs<Expr>();
- CheckCompletedExpr(Arg, Param->getOuterLocStart());
- // Build the default argument expression.
- return CXXDefaultArgExpr::Create(Context, CallLoc, Param, Arg);
+ Result = ActOnFinishFullExpr(Result.getAs<Expr>(),
+ Param->getOuterLocStart());
+ if (Result.isInvalid())
+ return ExprError();
+
+ // Remember the instantiated default argument.
+ Param->setDefaultArg(Result.getAs<Expr>());
+ if (ASTMutationListener *L = getASTMutationListener()) {
+ L->DefaultArgumentInstantiated(Param);
+ }
}
// If the default expression creates temporaries, we need to
@@ -4929,7 +4937,9 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
OverloadExpr *ovl = find.Expression;
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(ovl))
return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, ArgExprs,
- RParenLoc, ExecConfig);
+ RParenLoc, ExecConfig,
+ /*AllowTypoCorrection=*/true,
+ find.IsAddressOfOperand);
return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs, RParenLoc);
}
}
@@ -4943,10 +4953,14 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
Expr *NakedFn = Fn->IgnoreParens();
+ bool CallingNDeclIndirectly = false;
NamedDecl *NDecl = nullptr;
- if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(NakedFn))
- if (UnOp->getOpcode() == UO_AddrOf)
+ if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(NakedFn)) {
+ if (UnOp->getOpcode() == UO_AddrOf) {
+ CallingNDeclIndirectly = true;
NakedFn = UnOp->getSubExpr()->IgnoreParens();
+ }
+ }
if (isa<DeclRefExpr>(NakedFn)) {
NDecl = cast<DeclRefExpr>(NakedFn)->getDecl();
@@ -4968,6 +4982,11 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl();
if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NDecl)) {
+ if (CallingNDeclIndirectly &&
+ !checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
+ Fn->getLocStart()))
+ return ExprError();
+
if (FD->hasAttr<EnableIfAttr>()) {
if (const EnableIfAttr *Attr = CheckEnableIf(FD, ArgExprs, true)) {
Diag(Fn->getLocStart(),
@@ -5583,6 +5602,39 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty,
return false;
}
+ExprResult Sema::prepareVectorSplat(QualType VectorTy, Expr *SplattedExpr) {
+ QualType DestElemTy = VectorTy->castAs<VectorType>()->getElementType();
+
+ if (DestElemTy == SplattedExpr->getType())
+ return SplattedExpr;
+
+ assert(DestElemTy->isFloatingType() ||
+ DestElemTy->isIntegralOrEnumerationType());
+
+ CastKind CK;
+ if (VectorTy->isExtVectorType() && SplattedExpr->getType()->isBooleanType()) {
+ // OpenCL requires that we convert `true` boolean expressions to -1, but
+ // only when splatting vectors.
+ if (DestElemTy->isFloatingType()) {
+ // To avoid having to have a CK_BooleanToSignedFloating cast kind, we cast
+ // in two steps: boolean to signed integral, then to floating.
+ ExprResult CastExprRes = ImpCastExprToType(SplattedExpr, Context.IntTy,
+ CK_BooleanToSignedIntegral);
+ SplattedExpr = CastExprRes.get();
+ CK = CK_IntegralToFloating;
+ } else {
+ CK = CK_BooleanToSignedIntegral;
+ }
+ } else {
+ ExprResult CastExprRes = SplattedExpr;
+ CK = PrepareScalarCast(CastExprRes, DestElemTy);
+ if (CastExprRes.isInvalid())
+ return ExprError();
+ SplattedExpr = CastExprRes.get();
+ }
+ return ImpCastExprToType(SplattedExpr, DestElemTy, CK);
+}
+
ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
Expr *CastExpr, CastKind &Kind) {
assert(DestTy->isExtVectorType() && "Not an extended vector type!");
@@ -5613,15 +5665,8 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy,
diag::err_invalid_conversion_between_vector_and_scalar)
<< DestTy << SrcTy << R;
- QualType DestElemTy = DestTy->getAs<ExtVectorType>()->getElementType();
- ExprResult CastExprRes = CastExpr;
- CastKind CK = PrepareScalarCast(CastExprRes, DestElemTy);
- if (CastExprRes.isInvalid())
- return ExprError();
- CastExpr = ImpCastExprToType(CastExprRes.get(), DestElemTy, CK).get();
-
Kind = CK_VectorSplat;
- return CastExpr;
+ return prepareVectorSplat(DestTy, CastExpr);
}
ExprResult
@@ -6960,13 +7005,9 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
if (RHSType->isExtVectorType())
return Incompatible;
if (RHSType->isArithmeticType()) {
- // CK_VectorSplat does T -> vector T, so first cast to the
- // element type.
- QualType elType = cast<ExtVectorType>(LHSType)->getElementType();
- if (elType != RHSType && ConvertRHS) {
- Kind = PrepareScalarCast(RHS, elType);
- RHS = ImpCastExprToType(RHS.get(), elType, Kind);
- }
+ // CK_VectorSplat does T -> vector T, so first cast to the element type.
+ if (ConvertRHS)
+ RHS = prepareVectorSplat(LHSType, RHS.get());
Kind = CK_VectorSplat;
return Compatible;
}
@@ -8184,7 +8225,7 @@ static QualType checkOpenCLVectorShift(Sema &S,
if (RHS.isInvalid()) return QualType();
QualType LHSType = LHS.get()->getType();
- const VectorType *LHSVecTy = LHSType->getAs<VectorType>();
+ const VectorType *LHSVecTy = LHSType->castAs<VectorType>();
QualType LHSEleType = LHSVecTy->getElementType();
// Note that RHS might not be a vector.
@@ -13121,6 +13162,7 @@ bool Sema::tryCaptureVariable(
case Type::ObjCObject:
case Type::ObjCInterface:
case Type::ObjCObjectPointer:
+ case Type::Pipe:
llvm_unreachable("type class is never variably-modified!");
case Type::Adjusted:
QTy = cast<AdjustedType>(Ty)->getOriginalType();
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 2ad595f3a814..38fbea18d790 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -3353,20 +3353,13 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
VK_RValue, /*BasePath=*/nullptr, CCK).get();
break;
- case ICK_Vector_Splat:
+ case ICK_Vector_Splat: {
// Vector splat from any arithmetic type to a vector.
- // Cast to the element type.
- {
- QualType elType = ToType->getAs<ExtVectorType>()->getElementType();
- if (elType != From->getType()) {
- ExprResult E = From;
- From = ImpCastExprToType(From, elType,
- PrepareScalarCast(E, elType)).get();
- }
- From = ImpCastExprToType(From, ToType, CK_VectorSplat,
- VK_RValue, /*BasePath=*/nullptr, CCK).get();
- }
+ Expr *Elem = prepareVectorSplat(ToType, From).get();
+ From = ImpCastExprToType(Elem, ToType, CK_VectorSplat, VK_RValue,
+ /*BasePath=*/nullptr, CCK).get();
break;
+ }
case ICK_Complex_Real:
// Case 1. x -> _Complex y
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 57a08b94f5e8..1d86ca35412e 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -319,6 +319,7 @@ ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) {
// to use to determine the Objective-c literal kind.
switch (Char->getKind()) {
case CharacterLiteral::Ascii:
+ case CharacterLiteral::UTF8:
NumberType = Context.CharTy;
break;
@@ -577,6 +578,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
// to use to determine the Objective-c literal kind.
switch (Char->getKind()) {
case CharacterLiteral::Ascii:
+ case CharacterLiteral::UTF8:
ValueType = Context.CharTy;
break;
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 481ae6cd55b1..45dc2e33da93 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -650,6 +650,13 @@ void LookupResult::print(raw_ostream &Out) {
}
}
+LLVM_DUMP_METHOD void LookupResult::dump() {
+ llvm::errs() << "lookup results for " << getLookupName().getAsString()
+ << ":\n";
+ for (NamedDecl *D : *this)
+ D->dump();
+}
+
/// \brief Lookup a builtin function, when name lookup would otherwise
/// fail.
static bool LookupBuiltin(Sema &S, LookupResult &R) {
@@ -2616,6 +2623,9 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
case Type::Atomic:
T = cast<AtomicType>(T)->getValueType().getTypePtr();
continue;
+ case Type::Pipe:
+ T = cast<PipeType>(T)->getElementType().getTypePtr();
+ continue;
}
if (Queue.empty())
@@ -4988,3 +4998,12 @@ const Sema::TypoExprState &Sema::getTypoExprState(TypoExpr *TE) const {
void Sema::clearDelayedTypo(TypoExpr *TE) {
DelayedTypos.erase(TE);
}
+
+void Sema::ActOnPragmaDump(Scope *S, SourceLocation IILoc, IdentifierInfo *II) {
+ DeclarationNameInfo Name(II, IILoc);
+ LookupResult R(*this, Name, LookupAnyName, Sema::NotForRedeclaration);
+ R.suppressDiagnostics();
+ R.setHideTags(false);
+ LookupName(R, S);
+ R.dump();
+}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index e0c10e4479e2..663da0c0e804 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -258,6 +258,7 @@ static const Expr *IgnoreNarrowingConversion(const Expr *Converted) {
case CK_IntegralCast:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
+ case CK_BooleanToSignedIntegral:
case CK_FloatingToIntegral:
case CK_FloatingToBoolean:
case CK_FloatingCast:
@@ -9643,6 +9644,13 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
case ovl_fail_enable_if:
return DiagnoseFailedEnableIfAttr(S, Cand);
+
+ case ovl_fail_addr_not_available: {
+ bool Available = checkAddressOfCandidateIsAvailable(S, Cand->Function);
+ (void)Available;
+ assert(!Available);
+ break;
+ }
}
}
@@ -11245,6 +11253,17 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
return ExprError();
}
+static void markUnaddressableCandidatesUnviable(Sema &S,
+ OverloadCandidateSet &CS) {
+ for (auto I = CS.begin(), E = CS.end(); I != E; ++I) {
+ if (I->Viable &&
+ !S.checkAddressOfFunctionIsAvailable(I->Function, /*Complain=*/false)) {
+ I->Viable = false;
+ I->FailureKind = ovl_fail_addr_not_available;
+ }
+ }
+}
+
/// BuildOverloadedCallExpr - Given the call expression that calls Fn
/// (which eventually refers to the declaration Func) and the call
/// arguments Args/NumArgs, attempt to resolve the function call down
@@ -11257,7 +11276,8 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn,
MultiExprArg Args,
SourceLocation RParenLoc,
Expr *ExecConfig,
- bool AllowTypoCorrection) {
+ bool AllowTypoCorrection,
+ bool CalleesAddressIsTaken) {
OverloadCandidateSet CandidateSet(Fn->getExprLoc(),
OverloadCandidateSet::CSK_Normal);
ExprResult result;
@@ -11266,6 +11286,11 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn,
&result))
return result;
+ // If the user handed us something like `(&Foo)(Bar)`, we need to ensure that
+ // functions that aren't addressible are considered unviable.
+ if (CalleesAddressIsTaken)
+ markUnaddressableCandidatesUnviable(*this, CandidateSet);
+
OverloadCandidateSet::iterator Best;
OverloadingResult OverloadResult =
CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best);
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 6cc85883345d..57156078c80b 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -4184,6 +4184,10 @@ bool UnnamedLocalNoLinkageFinder::VisitAtomicType(const AtomicType* T) {
return Visit(T->getValueType());
}
+bool UnnamedLocalNoLinkageFinder::VisitPipeType(const PipeType* T) {
+ return false;
+}
+
bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) {
if (Tag->getDeclContext()->isFunctionOrMethod()) {
S.Diag(SR.getBegin(),
@@ -5503,6 +5507,8 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
Expr *E;
if (T->isAnyCharacterType()) {
+ // This does not need to handle u8 character literals because those are
+ // of type char, and so can also be covered by an ASCII character literal.
CharacterLiteral::CharacterKind Kind;
if (T->isWideCharType())
Kind = CharacterLiteral::Wide;
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index cd54920b08cf..71faafc6bc12 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -1652,6 +1652,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
case Type::Auto:
case Type::DependentTemplateSpecialization:
case Type::PackExpansion:
+ case Type::Pipe:
// No template argument deduction for these types
return Sema::TDK_Success;
}
@@ -4964,6 +4965,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
case Type::ObjCObject:
case Type::ObjCObjectPointer:
case Type::UnresolvedUsing:
+ case Type::Pipe:
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base)
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 61052f06c834..cb67d71f9e59 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -750,6 +750,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case DeclaratorChunk::Pointer:
case DeclaratorChunk::Reference:
case DeclaratorChunk::Paren:
+ case DeclaratorChunk::Pipe:
case DeclaratorChunk::BlockPointer:
// These declarator chunks cannot contain any parameter packs.
break;
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index c70568c23b57..f6ad132cde83 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -335,6 +335,7 @@ static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator,
case DeclaratorChunk::Array:
case DeclaratorChunk::Reference:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
return result;
// If we do find a function declarator, scan inwards from that,
@@ -347,6 +348,7 @@ static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator,
case DeclaratorChunk::Array:
case DeclaratorChunk::Function:
case DeclaratorChunk::Reference:
+ case DeclaratorChunk::Pipe:
continue;
case DeclaratorChunk::MemberPointer:
@@ -427,6 +429,7 @@ static void distributeObjCPointerTypeAttr(TypeProcessingState &state,
// Don't walk through these.
case DeclaratorChunk::Reference:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
goto error;
}
}
@@ -459,6 +462,7 @@ distributeObjCPointerTypeAttrFromDeclarator(TypeProcessingState &state,
case DeclaratorChunk::MemberPointer:
case DeclaratorChunk::Paren:
case DeclaratorChunk::Array:
+ case DeclaratorChunk::Pipe:
continue;
case DeclaratorChunk::Function:
@@ -520,6 +524,7 @@ static void distributeFunctionTypeAttr(TypeProcessingState &state,
case DeclaratorChunk::Array:
case DeclaratorChunk::Reference:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
continue;
}
}
@@ -1272,6 +1277,10 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// value being declared, poison it as invalid so we don't get chains of
// errors.
declarator.setInvalidType(true);
+ } else if (S.getLangOpts().OpenCLVersion >= 200 && DS.isTypeSpecPipe()){
+ S.Diag(DeclLoc, diag::err_missing_actual_pipe_type)
+ << DS.getSourceRange();
+ declarator.setInvalidType(true);
} else {
S.Diag(DeclLoc, diag::ext_missing_type_specifier)
<< DS.getSourceRange();
@@ -1564,7 +1573,9 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// Apply any type attributes from the decl spec. This may cause the
// list of type attributes to be temporarily saved while the type
// attributes are pushed around.
- processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes().getList());
+ // pipe attributes will be handled later ( at GetFullTypeForDeclarator )
+ if (!DS.isTypeSpecPipe())
+ processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes().getList());
// Apply const/volatile/restrict qualifiers to T.
if (unsigned TypeQuals = DS.getTypeQualifiers()) {
@@ -1924,6 +1935,21 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
return Context.getRValueReferenceType(T);
}
+/// \brief Build a Pipe type.
+///
+/// \param T The type to which we'll be building a Pipe.
+///
+/// \param Loc We do not use it for now.
+///
+/// \returns A suitable pipe type, if there are no errors. Otherwise, returns a
+/// NULL type.
+QualType Sema::BuildPipeType(QualType T, SourceLocation Loc) {
+ assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType");
+
+ // Build the pipe type.
+ return Context.getPipeType(T);
+}
+
/// Check whether the specified array size makes the array type a VLA. If so,
/// return true, if not, return the size of the array in SizeVal.
static bool isArraySizeVLA(Sema &S, Expr *ArraySize, llvm::APSInt &SizeVal) {
@@ -2393,6 +2419,7 @@ static void inferARCWriteback(TypeProcessingState &state,
case DeclaratorChunk::Array: // suppress if written (id[])?
case DeclaratorChunk::Function:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
return;
}
}
@@ -2532,6 +2559,7 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy,
case DeclaratorChunk::Reference:
case DeclaratorChunk::Array:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
// FIXME: We can't currently provide an accurate source location and a
// fix-it hint for these.
unsigned AtomicQual = RetTy->isAtomicType() ? DeclSpec::TQ_atomic : 0;
@@ -3057,6 +3085,7 @@ static PointerDeclaratorKind classifyPointerDeclarator(Sema &S,
switch (chunk.Kind) {
case DeclaratorChunk::Array:
case DeclaratorChunk::Function:
+ case DeclaratorChunk::Pipe:
break;
case DeclaratorChunk::BlockPointer:
@@ -3305,6 +3334,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case DeclaratorChunk::Array:
DiagKind = 2;
break;
+ case DeclaratorChunk::Pipe:
+ break;
}
S.Diag(DeclChunk.Loc, DiagId) << DiagKind;
@@ -3370,6 +3401,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
switch (chunk.Kind) {
case DeclaratorChunk::Array:
case DeclaratorChunk::Function:
+ case DeclaratorChunk::Pipe:
break;
case DeclaratorChunk::BlockPointer:
@@ -3689,6 +3721,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
break;
case DeclaratorChunk::Function:
case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::Pipe:
// These are invalid anyway, so just ignore.
break;
}
@@ -4038,7 +4071,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
break;
}
- case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::MemberPointer: {
// The scope spec must refer to a class, or be dependent.
CXXScopeSpec &SS = DeclType.Mem.Scope();
QualType ClsType;
@@ -4098,6 +4131,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
break;
}
+ case DeclaratorChunk::Pipe: {
+ T = S.BuildPipeType(T, DeclType.Loc );
+ break;
+ }
+ }
+
if (T.isNull()) {
D.setInvalidType(true);
T = Context.IntTy;
@@ -4392,6 +4431,7 @@ static void transferARCOwnership(TypeProcessingState &state,
case DeclaratorChunk::Function:
case DeclaratorChunk::MemberPointer:
+ case DeclaratorChunk::Pipe:
return;
}
}
@@ -4682,6 +4722,14 @@ namespace {
}
}
+ void VisitPipeTypeLoc(PipeTypeLoc TL) {
+ TL.setKWLoc(DS.getTypeSpecTypeLoc());
+
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
+ TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc());
+ }
+
void VisitTypeLoc(TypeLoc TL) {
// FIXME: add other typespec types and change this to an assert.
TL.initialize(Context, DS.getTypeSpecTypeLoc());
@@ -4802,6 +4850,10 @@ namespace {
TL.setLParenLoc(Chunk.Loc);
TL.setRParenLoc(Chunk.EndLoc);
}
+ void VisitPipeTypeLoc(PipeTypeLoc TL) {
+ assert(Chunk.Kind == DeclaratorChunk::Pipe);
+ TL.setKWLoc(Chunk.Loc);
+ }
void VisitTypeLoc(TypeLoc TL) {
llvm_unreachable("unsupported TypeLoc kind in declarator!");
@@ -4815,6 +4867,7 @@ static void fillAtomicQualLoc(AtomicTypeLoc ATL, const DeclaratorChunk &Chunk) {
case DeclaratorChunk::Function:
case DeclaratorChunk::Array:
case DeclaratorChunk::Paren:
+ case DeclaratorChunk::Pipe:
llvm_unreachable("cannot be _Atomic qualified");
case DeclaratorChunk::Pointer:
@@ -5738,6 +5791,7 @@ static bool distributeNullabilityTypeAttr(TypeProcessingState &state,
// Don't walk through these.
case DeclaratorChunk::Reference:
+ case DeclaratorChunk::Pipe:
return false;
}
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index e0a9653eb93b..935304fe4076 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1046,6 +1046,9 @@ public:
/// Subclasses may override this routine to provide different behavior.
QualType RebuildAtomicType(QualType ValueType, SourceLocation KWLoc);
+ /// \brief Build a new pipe type given its value type.
+ QualType RebuildPipeType(QualType ValueType, SourceLocation KWLoc);
+
/// \brief Build a new template name given a nested name specifier, a flag
/// indicating whether the "template" keyword was provided, and the template
/// that the template name refers to.
@@ -3580,7 +3583,7 @@ void TreeTransform<Derived>::InventTemplateArgumentLoc(
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion: {
NestedNameSpecifierLocBuilder Builder;
- TemplateName Template = Arg.getAsTemplate();
+ TemplateName Template = Arg.getAsTemplateOrTemplatePattern();
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
Builder.MakeTrivial(SemaRef.Context, DTN->getQualifier(), Loc);
else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
@@ -5324,6 +5327,26 @@ QualType TreeTransform<Derived>::TransformAtomicType(TypeLocBuilder &TLB,
return Result;
}
+template <typename Derived>
+QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB,
+ PipeTypeLoc TL) {
+ QualType ValueType = getDerived().TransformType(TLB, TL.getValueLoc());
+ if (ValueType.isNull())
+ return QualType();
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() || ValueType != TL.getValueLoc().getType()) {
+ Result = getDerived().RebuildPipeType(ValueType, TL.getKWLoc());
+ if (Result.isNull())
+ return QualType();
+ }
+
+ PipeTypeLoc NewTL = TLB.push<PipeTypeLoc>(Result);
+ NewTL.setKWLoc(TL.getKWLoc());
+
+ return Result;
+}
+
/// \brief Simple iterator that traverses the template arguments in a
/// container that provides a \c getArgLoc() member function.
///
@@ -6128,7 +6151,7 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
}
}
- Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.get()));
+ Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.get(), S->getIfLoc()));
if (!S->getConditionVariable() && S->getCond() && !FullCond.get())
return StmtError();
@@ -6223,7 +6246,8 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
}
}
- Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.get()));
+ Sema::FullExprArg FullCond(
+ getSema().MakeFullExpr(Cond.get(), S->getWhileLoc()));
if (!S->getConditionVariable() && S->getCond() && !FullCond.get())
return StmtError();
@@ -6307,7 +6331,8 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
}
}
- Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.get()));
+ Sema::FullExprArg FullCond(
+ getSema().MakeFullExpr(Cond.get(), S->getForLoc()));
if (!S->getConditionVariable() && S->getCond() && !FullCond.get())
return StmtError();
@@ -11348,6 +11373,12 @@ QualType TreeTransform<Derived>::RebuildAtomicType(QualType ValueType,
}
template<typename Derived>
+QualType TreeTransform<Derived>::RebuildPipeType(QualType ValueType,
+ SourceLocation KWLoc) {
+ return SemaRef.BuildPipeType(ValueType, KWLoc);
+}
+
+template<typename Derived>
TemplateName
TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS,
bool TemplateKW,
diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h
index e59bc891f9b9..64f583c98728 100644
--- a/lib/Serialization/ASTCommon.h
+++ b/lib/Serialization/ASTCommon.h
@@ -29,6 +29,7 @@ enum DeclUpdateKind {
UPD_CXX_ADDED_FUNCTION_DEFINITION,
UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER,
UPD_CXX_INSTANTIATED_CLASS_DEFINITION,
+ UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT,
UPD_CXX_RESOLVED_DTOR_DELETE,
UPD_CXX_RESOLVED_EXCEPTION_SPEC,
UPD_CXX_DEDUCED_RETURN_TYPE,
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index a279475eeafb..833ff57e4d0b 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -5640,6 +5640,17 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
QualType ValueType = readType(*Loc.F, Record, Idx);
return Context.getAtomicType(ValueType);
}
+
+ case TYPE_PIPE: {
+ if (Record.size() != 1) {
+ Error("Incorrect encoding of pipe type");
+ return QualType();
+ }
+
+ // Reading the pipe element type.
+ QualType ElementType = readType(*Loc.F, Record, Idx);
+ return Context.getPipeType(ElementType);
+ }
}
llvm_unreachable("Invalid TypeCode!");
}
@@ -5911,6 +5922,9 @@ void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
TL.setLParenLoc(ReadSourceLocation(Record, Idx));
TL.setRParenLoc(ReadSourceLocation(Record, Idx));
}
+void TypeLocReader::VisitPipeTypeLoc(PipeTypeLoc TL) {
+ TL.setKWLoc(ReadSourceLocation(Record, Idx));
+}
TypeSourceInfo *ASTReader::GetTypeSourceInfo(ModuleFile &F,
const RecordData &Record,
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 8fb110e4551d..5bf95f878d49 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -3626,6 +3626,21 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
Reader.ReadSourceLocation(ModuleFile, Record, Idx));
break;
+ case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT: {
+ auto Param = cast<ParmVarDecl>(D);
+
+ // We have to read the default argument regardless of whether we use it
+ // so that hypothetical further update records aren't messed up.
+ // TODO: Add a function to skip over the next expr record.
+ auto DefaultArg = Reader.ReadExpr(F);
+
+ // Only apply the update if the parameter still has an uninstantiated
+ // default argument.
+ if (Param->hasUninstantiatedDefaultArg())
+ Param->setDefaultArg(DefaultArg);
+ break;
+ }
+
case UPD_CXX_ADDED_FUNCTION_DEFINITION: {
FunctionDecl *FD = cast<FunctionDecl>(D);
if (Reader.PendingBodies[FD]) {
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index bc678aff7861..ad81ac844209 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -1364,10 +1364,7 @@ void ASTStmtReader::VisitCXXThrowExpr(CXXThrowExpr *E) {
void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
VisitExpr(E);
-
- assert((bool)Record[Idx] == E->Param.getInt() && "We messed up at creation ?");
- ++Idx; // HasOtherExprStored and SubExpr was handled during creation.
- E->Param.setPointer(ReadDeclAs<ParmVarDecl>(Record, Idx));
+ E->Param = ReadDeclAs<ParmVarDecl>(Record, Idx);
E->Loc = ReadSourceLocation(Record, Idx);
}
@@ -3205,16 +3202,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
case EXPR_CXX_THROW:
S = new (Context) CXXThrowExpr(Empty);
break;
- case EXPR_CXX_DEFAULT_ARG: {
- bool HasOtherExprStored = Record[ASTStmtReader::NumExprFields];
- if (HasOtherExprStored) {
- Expr *SubExpr = ReadSubExpr();
- S = CXXDefaultArgExpr::Create(Context, SourceLocation(), nullptr,
- SubExpr);
- } else
- S = new (Context) CXXDefaultArgExpr(Empty);
+ case EXPR_CXX_DEFAULT_ARG:
+ S = new (Context) CXXDefaultArgExpr(Empty);
break;
- }
case EXPR_CXX_DEFAULT_INIT:
S = new (Context) CXXDefaultInitExpr(Empty);
break;
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 0f50d7a42eab..ec04cd6c1fa9 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -446,6 +446,12 @@ ASTTypeWriter::VisitAtomicType(const AtomicType *T) {
Code = TYPE_ATOMIC;
}
+void
+ASTTypeWriter::VisitPipeType(const PipeType *T) {
+ Writer.AddTypeRef(T->getElementType(), Record);
+ Code = TYPE_PIPE;
+}
+
namespace {
class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> {
@@ -672,6 +678,9 @@ void TypeLocWriter::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
Writer.AddSourceLocation(TL.getLParenLoc(), Record);
Writer.AddSourceLocation(TL.getRParenLoc(), Record);
}
+void TypeLocWriter::VisitPipeTypeLoc(PipeTypeLoc TL) {
+ Writer.AddSourceLocation(TL.getKWLoc(), Record);
+}
void ASTWriter::WriteTypeAbbrevs() {
using namespace llvm;
@@ -4611,6 +4620,11 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
AddSourceLocation(Update.getLoc(), Record);
break;
+ case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT:
+ AddStmt(const_cast<Expr*>(
+ cast<ParmVarDecl>(Update.getDecl())->getDefaultArg()));
+ break;
+
case UPD_CXX_INSTANTIATED_CLASS_DEFINITION: {
auto *RD = cast<CXXRecordDecl>(D);
UpdatedDeclContexts.insert(RD->getPrimaryContext());
@@ -5779,6 +5793,15 @@ void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) {
D->getMemberSpecializationInfo()->getPointOfInstantiation()));
}
+void ASTWriter::DefaultArgumentInstantiated(const ParmVarDecl *D) {
+ assert(!WritingAST && "Already writing the AST!");
+ if (!D->isFromASTFile())
+ return;
+
+ DeclUpdates[D].push_back(
+ DeclUpdate(UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT, D));
+}
+
void ASTWriter::AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD,
const ObjCInterfaceDecl *IFD) {
assert(!WritingAST && "Already writing the AST!");
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 20ca6d6fd512..54bba282ab8d 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -2033,7 +2033,7 @@ void ASTWriter::WriteDeclAbbrevs() {
//Character Literal
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getValue
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // getKind
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // getKind
CharacterLiteralAbbrev = Stream.EmitAbbrev(Abv);
// Abbreviation for EXPR_IMPLICIT_CAST
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index e52ed052d3bc..000a2185f5f0 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -1336,15 +1336,8 @@ void ASTStmtWriter::VisitCXXThrowExpr(CXXThrowExpr *E) {
void ASTStmtWriter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
VisitExpr(E);
-
- bool HasOtherExprStored = E->Param.getInt();
- // Store these first, the reader reads them before creation.
- Record.push_back(HasOtherExprStored);
- if (HasOtherExprStored)
- Writer.AddStmt(E->getExpr());
Writer.AddDeclRef(E->getParam(), Record);
Writer.AddSourceLocation(E->getUsedLocation(), Record);
-
Code = serialization::EXPR_CXX_DEFAULT_ARG;
}
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 5d78d9b02e6b..17537445d66c 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -948,15 +948,15 @@ bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(MR);
switch (MR->getKind()) {
- case MemRegion::FunctionTextRegionKind: {
- const NamedDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
+ case MemRegion::FunctionCodeRegionKind: {
+ const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
if (FD)
os << "the address of the function '" << *FD << '\'';
else
os << "the address of a function";
return true;
}
- case MemRegion::BlockTextRegionKind:
+ case MemRegion::BlockCodeRegionKind:
os << "block text";
return true;
case MemRegion::BlockDataRegionKind:
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index ce2c19409dc1..fee030feb6d2 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1513,15 +1513,15 @@ bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
bool MallocChecker::SummarizeRegion(raw_ostream &os,
const MemRegion *MR) {
switch (MR->getKind()) {
- case MemRegion::FunctionTextRegionKind: {
- const NamedDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
+ case MemRegion::FunctionCodeRegionKind: {
+ const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
if (FD)
os << "the address of the function '" << *FD << '\'';
else
os << "the address of a function";
return true;
}
- case MemRegion::BlockTextRegionKind:
+ case MemRegion::BlockCodeRegionKind:
os << "block text";
return true;
case MemRegion::BlockDataRegionKind:
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index a5b58710b215..175225ba0de2 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -316,7 +316,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_ArrayToPointerDecay:
case CK_BitCast:
case CK_AddressSpaceConversion:
- case CK_IntegralCast:
+ case CK_BooleanToSignedIntegral:
case CK_NullToPointer:
case CK_IntegralToPointer:
case CK_PointerToIntegral:
@@ -345,6 +345,17 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
// Delegate to SValBuilder to process.
SVal V = state->getSVal(Ex, LCtx);
V = svalBuilder.evalCast(V, T, ExTy);
+ // Negate the result if we're treating the boolean as a signed i1
+ if (CastE->getCastKind() == CK_BooleanToSignedIntegral)
+ V = evalMinus(V);
+ state = state->BindExpr(CastE, LCtx, V);
+ Bldr.generateNode(CastE, Pred, state);
+ continue;
+ }
+ case CK_IntegralCast: {
+ // Delegate to SValBuilder to process.
+ SVal V = state->getSVal(Ex, LCtx);
+ V = svalBuilder.evalIntegralCast(state, V, T, ExTy);
state = state->BindExpr(CastE, LCtx, V);
Bldr.generateNode(CastE, Pred, state);
continue;
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index ad3f396e39a1..30052ccacee4 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -245,7 +245,7 @@ QualType CXXBaseObjectRegion::getValueType() const {
// FoldingSet profiling.
//===----------------------------------------------------------------------===//
-void MemSpaceRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+void MemSpaceRegion::Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger((unsigned)getKind());
}
@@ -357,31 +357,31 @@ void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const {
ElementRegion::ProfileRegion(ID, ElementType, Index, superRegion);
}
-void FunctionTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+void FunctionCodeRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const NamedDecl *FD,
const MemRegion*) {
- ID.AddInteger(MemRegion::FunctionTextRegionKind);
+ ID.AddInteger(MemRegion::FunctionCodeRegionKind);
ID.AddPointer(FD);
}
-void FunctionTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- FunctionTextRegion::ProfileRegion(ID, FD, superRegion);
+void FunctionCodeRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ FunctionCodeRegion::ProfileRegion(ID, FD, superRegion);
}
-void BlockTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+void BlockCodeRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const BlockDecl *BD, CanQualType,
const AnalysisDeclContext *AC,
const MemRegion*) {
- ID.AddInteger(MemRegion::BlockTextRegionKind);
+ ID.AddInteger(MemRegion::BlockCodeRegionKind);
ID.AddPointer(BD);
}
-void BlockTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- BlockTextRegion::ProfileRegion(ID, BD, locTy, AC, superRegion);
+void BlockCodeRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ BlockCodeRegion::ProfileRegion(ID, BD, locTy, AC, superRegion);
}
void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const BlockTextRegion *BC,
+ const BlockCodeRegion *BC,
const LocationContext *LC,
unsigned BlkCount,
const MemRegion *sReg) {
@@ -457,11 +457,11 @@ void AllocaRegion::dumpToStream(raw_ostream &os) const {
os << "alloca{" << (const void*) Ex << ',' << Cnt << '}';
}
-void FunctionTextRegion::dumpToStream(raw_ostream &os) const {
+void FunctionCodeRegion::dumpToStream(raw_ostream &os) const {
os << "code{" << getDecl()->getDeclName().getAsString() << '}';
}
-void BlockTextRegion::dumpToStream(raw_ostream &os) const {
+void BlockCodeRegion::dumpToStream(raw_ostream &os) const {
os << "block_code{" << (const void*) this << '}';
}
@@ -533,6 +533,10 @@ void RegionRawOffset::dumpToStream(raw_ostream &os) const {
os << "raw_offset{" << getRegion() << ',' << getOffset().getQuantity() << '}';
}
+void CodeSpaceRegion::dumpToStream(raw_ostream &os) const {
+ os << "CodeSpaceRegion";
+}
+
void StaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const {
os << "StaticGlobalsMemSpace{" << CR << '}';
}
@@ -711,11 +715,11 @@ const HeapSpaceRegion *MemRegionManager::getHeapRegion() {
return LazyAllocate(heap);
}
-const MemSpaceRegion *MemRegionManager::getUnknownRegion() {
+const UnknownSpaceRegion *MemRegionManager::getUnknownRegion() {
return LazyAllocate(unknown);
}
-const MemSpaceRegion *MemRegionManager::getCodeRegion() {
+const CodeSpaceRegion *MemRegionManager::getCodeRegion() {
return LazyAllocate(code);
}
@@ -815,11 +819,11 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
const Decl *STCD = STC->getDecl();
if (isa<FunctionDecl>(STCD) || isa<ObjCMethodDecl>(STCD))
sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
- getFunctionTextRegion(cast<NamedDecl>(STCD)));
+ getFunctionCodeRegion(cast<NamedDecl>(STCD)));
else if (const BlockDecl *BD = dyn_cast<BlockDecl>(STCD)) {
// FIXME: The fallback type here is totally bogus -- though it should
// never be queried, it will prevent uniquing with the real
- // BlockTextRegion. Ideally we'd fix the AST so that we always had a
+ // BlockCodeRegion. Ideally we'd fix the AST so that we always had a
// signature.
QualType T;
if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten())
@@ -830,8 +834,8 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
T = getContext().getFunctionNoProtoType(T);
T = getContext().getBlockPointerType(T);
- const BlockTextRegion *BTR =
- getBlockTextRegion(BD, C.getCanonicalType(T),
+ const BlockCodeRegion *BTR =
+ getBlockCodeRegion(BD, C.getCanonicalType(T),
STC->getAnalysisDeclContext());
sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind,
BTR);
@@ -852,7 +856,7 @@ const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D,
}
const BlockDataRegion *
-MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
+MemRegionManager::getBlockDataRegion(const BlockCodeRegion *BC,
const LocationContext *LC,
unsigned blockCount) {
const MemRegion *sReg = nullptr;
@@ -925,15 +929,15 @@ MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx,
return R;
}
-const FunctionTextRegion *
-MemRegionManager::getFunctionTextRegion(const NamedDecl *FD) {
- return getSubRegion<FunctionTextRegion>(FD, getCodeRegion());
+const FunctionCodeRegion *
+MemRegionManager::getFunctionCodeRegion(const NamedDecl *FD) {
+ return getSubRegion<FunctionCodeRegion>(FD, getCodeRegion());
}
-const BlockTextRegion *
-MemRegionManager::getBlockTextRegion(const BlockDecl *BD, CanQualType locTy,
+const BlockCodeRegion *
+MemRegionManager::getBlockCodeRegion(const BlockDecl *BD, CanQualType locTy,
AnalysisDeclContext *AC) {
- return getSubRegion<BlockTextRegion>(BD, locTy, AC, getCodeRegion());
+ return getSubRegion<BlockCodeRegion>(BD, locTy, AC, getCodeRegion());
}
@@ -1196,7 +1200,7 @@ RegionOffset MemRegion::getAsOffset() const {
while (1) {
switch (R->getKind()) {
- case GenericMemSpaceRegionKind:
+ case CodeSpaceRegionKind:
case StackLocalsSpaceRegionKind:
case StackArgumentsSpaceRegionKind:
case HeapSpaceRegionKind:
@@ -1209,8 +1213,8 @@ RegionOffset MemRegion::getAsOffset() const {
assert(Offset == 0 && !SymbolicOffsetBase);
goto Finish;
- case FunctionTextRegionKind:
- case BlockTextRegionKind:
+ case FunctionCodeRegionKind:
+ case BlockCodeRegionKind:
case BlockDataRegionKind:
// These will never have bindings, but may end up having values requested
// if the user does some strange casting.
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 4f9ad9ebccd9..100fa75c5f42 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -536,19 +536,19 @@ bool ScanReachableSymbols::scan(const SymExpr *sym) {
// TODO: should be rewritten using SymExpr::symbol_iterator.
switch (sym->getKind()) {
- case SymExpr::RegionValueKind:
- case SymExpr::ConjuredKind:
- case SymExpr::DerivedKind:
- case SymExpr::ExtentKind:
- case SymExpr::MetadataKind:
+ case SymExpr::SymbolRegionValueKind:
+ case SymExpr::SymbolConjuredKind:
+ case SymExpr::SymbolDerivedKind:
+ case SymExpr::SymbolExtentKind:
+ case SymExpr::SymbolMetadataKind:
break;
- case SymExpr::CastSymbolKind:
+ case SymExpr::SymbolCastKind:
return scan(cast<SymbolCast>(sym)->getOperand());
- case SymExpr::SymIntKind:
+ case SymExpr::SymIntExprKind:
return scan(cast<SymIntExpr>(sym)->getLHS());
- case SymExpr::IntSymKind:
+ case SymExpr::IntSymExprKind:
return scan(cast<IntSymExpr>(sym)->getRHS());
- case SymExpr::SymSymKind: {
+ case SymExpr::SymSymExprKind: {
const SymSymExpr *x = cast<SymSymExpr>(sym);
return scan(x->getLHS()) && scan(x->getRHS());
}
diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 0a2b2e64a142..77b0ad32b6b7 100644
--- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -171,7 +171,7 @@ private:
case APSIntType::RTR_Below:
// The entire range is outside the symbol's set of possible values.
// If this is a conventionally-ordered range, the state is infeasible.
- if (Lower < Upper)
+ if (Lower <= Upper)
return false;
// However, if the range wraps around, it spans all possible values.
@@ -222,7 +222,7 @@ private:
case APSIntType::RTR_Above:
// The entire range is outside the symbol's set of possible values.
// If this is a conventionally-ordered range, the state is infeasible.
- if (Lower < Upper)
+ if (Lower <= Upper)
return false;
// However, if the range wraps around, it spans all possible values.
diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp
index cdae04068e1d..18315225a99d 100644
--- a/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -214,15 +214,15 @@ SValBuilder::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
}
DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl *func) {
- return loc::MemRegionVal(MemMgr.getFunctionTextRegion(func));
+ return loc::MemRegionVal(MemMgr.getFunctionCodeRegion(func));
}
DefinedSVal SValBuilder::getBlockPointer(const BlockDecl *block,
CanQualType locTy,
const LocationContext *locContext,
unsigned blockCount) {
- const BlockTextRegion *BC =
- MemMgr.getBlockTextRegion(block, locTy, locContext->getAnalysisDeclContext());
+ const BlockCodeRegion *BC =
+ MemMgr.getBlockCodeRegion(block, locTy, locContext->getAnalysisDeclContext());
const BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, locContext,
blockCount);
return loc::MemRegionVal(BD);
@@ -423,6 +423,45 @@ static bool shouldBeModeledWithNoOp(ASTContext &Context, QualType ToTy,
return true;
}
+// Handles casts of type CK_IntegralCast.
+// At the moment, this function will redirect to evalCast, except when the range
+// of the original value is known to be greater than the max of the target type.
+SVal SValBuilder::evalIntegralCast(ProgramStateRef state, SVal val,
+ QualType castTy, QualType originalTy) {
+
+ // No truncations if target type is big enough.
+ if (getContext().getTypeSize(castTy) >= getContext().getTypeSize(originalTy))
+ return evalCast(val, castTy, originalTy);
+
+ const SymExpr *se = val.getAsSymbolicExpression();
+ if (!se) // Let evalCast handle non symbolic expressions.
+ return evalCast(val, castTy, originalTy);
+
+ // Find the maximum value of the target type.
+ APSIntType ToType(getContext().getTypeSize(castTy),
+ castTy->isUnsignedIntegerType());
+ llvm::APSInt ToTypeMax = ToType.getMaxValue();
+ NonLoc ToTypeMaxVal =
+ makeIntVal(ToTypeMax.isUnsigned() ? ToTypeMax.getZExtValue()
+ : ToTypeMax.getSExtValue(),
+ castTy)
+ .castAs<NonLoc>();
+ // Check the range of the symbol being casted against the maximum value of the
+ // target type.
+ NonLoc FromVal = val.castAs<NonLoc>();
+ QualType CmpTy = getConditionType();
+ NonLoc CompVal =
+ evalBinOpNN(state, BO_LT, FromVal, ToTypeMaxVal, CmpTy).castAs<NonLoc>();
+ ProgramStateRef IsNotTruncated, IsTruncated;
+ std::tie(IsNotTruncated, IsTruncated) = state->assume(CompVal);
+ if (!IsNotTruncated && IsTruncated) {
+ // Symbol is truncated so we evaluate it as a cast.
+ NonLoc CastVal = makeNonLoc(se, originalTy, castTy);
+ return CastVal;
+ }
+ return evalCast(val, castTy, originalTy);
+}
+
// FIXME: should rewrite according to the cast kind.
SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
castTy = Context.getCanonicalType(castTy);
diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp
index 8de939f47d86..dffee6c8c57b 100644
--- a/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/lib/StaticAnalyzer/Core/SVals.cpp
@@ -51,7 +51,7 @@ bool SVal::hasConjuredSymbol() const {
const FunctionDecl *SVal::getAsFunctionDecl() const {
if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) {
const MemRegion* R = X->getRegion();
- if (const FunctionTextRegion *CTR = R->getAs<FunctionTextRegion>())
+ if (const FunctionCodeRegion *CTR = R->getAs<FunctionCodeRegion>())
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CTR->getDecl()))
return FD;
}
@@ -240,7 +240,7 @@ void SVal::dump() const { dumpToStream(llvm::errs()); }
void SVal::dumpToStream(raw_ostream &os) const {
switch (getBaseKind()) {
- case UnknownKind:
+ case UnknownValKind:
os << "Unknown";
break;
case NonLocKind:
@@ -249,7 +249,7 @@ void SVal::dumpToStream(raw_ostream &os) const {
case LocKind:
castAs<Loc>().dumpToStream(os);
break;
- case UndefinedKind:
+ case UndefinedValKind:
os << "Undefined";
break;
}
@@ -313,7 +313,7 @@ void Loc::dumpToStream(raw_ostream &os) const {
case loc::GotoLabelKind:
os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName();
break;
- case loc::MemRegionKind:
+ case loc::MemRegionValKind:
os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString();
break;
default:
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index a704ce224554..72b852b2e21d 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -141,9 +141,9 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
// unless this is a weak function or a symbolic region.
if (castTy->isBooleanType()) {
switch (val.getSubKind()) {
- case loc::MemRegionKind: {
+ case loc::MemRegionValKind: {
const MemRegion *R = val.castAs<loc::MemRegionVal>().getRegion();
- if (const FunctionTextRegion *FTR = dyn_cast<FunctionTextRegion>(R))
+ if (const FunctionCodeRegion *FTR = dyn_cast<FunctionCodeRegion>(R))
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FTR->getDecl()))
if (FD->isWeak())
// FIXME: Currently we are using an extent symbol here,
@@ -689,7 +689,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
// completely unknowable.
return UnknownVal();
}
- case loc::MemRegionKind: {
+ case loc::MemRegionValKind: {
if (Optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) {
// If one of the operands is a symbol and the other is a constant,
// build an expression for use by the constraint manager.
@@ -718,7 +718,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
// Get both values as regions, if possible.
const MemRegion *LeftMR = lhs.getAsRegion();
- assert(LeftMR && "MemRegionKind SVal doesn't have a region!");
+ assert(LeftMR && "MemRegionValKind SVal doesn't have a region!");
const MemRegion *RightMR = rhs.getAsRegion();
if (!RightMR)
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index 7cdb55a59782..de29f0eedd12 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -100,7 +100,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
// Process region cast according to the kind of the region being cast.
switch (R->getKind()) {
case MemRegion::CXXThisRegionKind:
- case MemRegion::GenericMemSpaceRegionKind:
+ case MemRegion::CodeSpaceRegionKind:
case MemRegion::StackLocalsSpaceRegionKind:
case MemRegion::StackArgumentsSpaceRegionKind:
case MemRegion::HeapSpaceRegionKind:
@@ -112,8 +112,8 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
llvm_unreachable("Invalid region cast");
}
- case MemRegion::FunctionTextRegionKind:
- case MemRegion::BlockTextRegionKind:
+ case MemRegion::FunctionCodeRegionKind:
+ case MemRegion::BlockCodeRegionKind:
case MemRegion::BlockDataRegionKind:
case MemRegion::StringRegionKind:
// FIXME: Need to handle arbitrary downcasts.
@@ -393,7 +393,7 @@ SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) {
const MemRegion* BaseR = nullptr;
switch (BaseL.getSubKind()) {
- case loc::MemRegionKind:
+ case loc::MemRegionValKind:
BaseR = BaseL.castAs<loc::MemRegionVal>().getRegion();
break;
diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 99b2e147cb49..2dd252c223fd 100644
--- a/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -115,22 +115,22 @@ void SymExpr::symbol_iterator::expand() {
const SymExpr *SE = itr.pop_back_val();
switch (SE->getKind()) {
- case SymExpr::RegionValueKind:
- case SymExpr::ConjuredKind:
- case SymExpr::DerivedKind:
- case SymExpr::ExtentKind:
- case SymExpr::MetadataKind:
+ case SymExpr::SymbolRegionValueKind:
+ case SymExpr::SymbolConjuredKind:
+ case SymExpr::SymbolDerivedKind:
+ case SymExpr::SymbolExtentKind:
+ case SymExpr::SymbolMetadataKind:
return;
- case SymExpr::CastSymbolKind:
+ case SymExpr::SymbolCastKind:
itr.push_back(cast<SymbolCast>(SE)->getOperand());
return;
- case SymExpr::SymIntKind:
+ case SymExpr::SymIntExprKind:
itr.push_back(cast<SymIntExpr>(SE)->getLHS());
return;
- case SymExpr::IntSymKind:
+ case SymExpr::IntSymExprKind:
itr.push_back(cast<IntSymExpr>(SE)->getRHS());
return;
- case SymExpr::SymSymKind: {
+ case SymExpr::SymSymExprKind: {
const SymSymExpr *x = cast<SymSymExpr>(SE);
itr.push_back(x->getLHS());
itr.push_back(x->getRHS());
@@ -458,35 +458,35 @@ bool SymbolReaper::isLive(SymbolRef sym) {
bool KnownLive;
switch (sym->getKind()) {
- case SymExpr::RegionValueKind:
+ case SymExpr::SymbolRegionValueKind:
KnownLive = isLiveRegion(cast<SymbolRegionValue>(sym)->getRegion());
break;
- case SymExpr::ConjuredKind:
+ case SymExpr::SymbolConjuredKind:
KnownLive = false;
break;
- case SymExpr::DerivedKind:
+ case SymExpr::SymbolDerivedKind:
KnownLive = isLive(cast<SymbolDerived>(sym)->getParentSymbol());
break;
- case SymExpr::ExtentKind:
+ case SymExpr::SymbolExtentKind:
KnownLive = isLiveRegion(cast<SymbolExtent>(sym)->getRegion());
break;
- case SymExpr::MetadataKind:
+ case SymExpr::SymbolMetadataKind:
KnownLive = MetadataInUse.count(sym) &&
isLiveRegion(cast<SymbolMetadata>(sym)->getRegion());
if (KnownLive)
MetadataInUse.erase(sym);
break;
- case SymExpr::SymIntKind:
+ case SymExpr::SymIntExprKind:
KnownLive = isLive(cast<SymIntExpr>(sym)->getLHS());
break;
- case SymExpr::IntSymKind:
+ case SymExpr::IntSymExprKind:
KnownLive = isLive(cast<IntSymExpr>(sym)->getRHS());
break;
- case SymExpr::SymSymKind:
+ case SymExpr::SymSymExprKind:
KnownLive = isLive(cast<SymSymExpr>(sym)->getLHS()) &&
isLive(cast<SymSymExpr>(sym)->getRHS());
break;
- case SymExpr::CastSymbolKind:
+ case SymExpr::SymbolCastKind:
KnownLive = isLive(cast<SymbolCast>(sym)->getOperand());
break;
}
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index bf85c4ca0c60..d1446855e01f 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -496,10 +496,11 @@ void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
(Mgr->options.InliningMode == All ? nullptr : &VisitedCallees));
// Add the visited callees to the global visited set.
- for (SetOfConstDecls::iterator I = VisitedCallees.begin(),
- E = VisitedCallees.end(); I != E; ++I) {
- Visited.insert(*I);
- }
+ for (const Decl *Callee : VisitedCallees)
+ // Decls from CallGraph are already canonical. But Decls coming from
+ // CallExprs may be not. We should canonicalize them manually.
+ Visited.insert(isa<ObjCMethodDecl>(Callee) ? Callee
+ : Callee->getCanonicalDecl());
VisitedAsTopLevel.insert(D);
}
}
diff --git a/test/Analysis/inlining/analysis-order.c b/test/Analysis/inlining/analysis-order.c
new file mode 100644
index 000000000000..5149818c74fd
--- /dev/null
+++ b/test/Analysis/inlining/analysis-order.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core.builtin.NoReturnFunctions -analyzer-display-progress %s 2>&1 | FileCheck %s
+
+// Do not analyze test1() again because it was inlined
+void test1();
+
+void test2() {
+ test1();
+}
+
+void test1() {
+}
+
+// CHECK: analysis-order.c test2
+// CHECK-NEXT: analysis-order.c test1
+// CHECK-NEXT: analysis-order.c test2
diff --git a/test/Analysis/range_casts.c b/test/Analysis/range_casts.c
new file mode 100644
index 000000000000..682369cce66f
--- /dev/null
+++ b/test/Analysis/range_casts.c
@@ -0,0 +1,156 @@
+// This test checks that intersecting ranges does not cause 'system is over constrained' assertions in the case of eg: 32 bits unsigned integers getting their range from 64 bits signed integers.
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-store=region -verify %s
+
+void clang_analyzer_warnIfReached();
+
+void f1(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index + 1 == 0) // because of foo range, index is in range [0; UINT_MAX]
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f2(unsigned long foo)
+{
+ int index = -1;
+ if (index < foo) index = foo; // index equals ULONG_MAX
+ if (index + 1 == 0)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // no-warning
+}
+
+void f3(unsigned long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index + 1 == 0)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f4(long foo)
+{
+ int index = -1;
+ if (index < foo) index = foo;
+ if (index + 1 == 0)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f5(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index == -1)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f6(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index == -1)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f7(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index - 1 == 0) // Was not reached prior fix.
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f8(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index + 1L == 0L)
+ clang_analyzer_warnIfReached(); // no-warning
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f9(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index - 1L == 0L) // Was not reached prior fix.
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f10(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index + 1 == 0L)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f11(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index + 1UL == 0L)
+ clang_analyzer_warnIfReached(); // no-warning
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f12(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ if (index - 1UL == 0L) // Was not reached prior fix.
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f13(int foo)
+{
+ unsigned short index = -1;
+ if (index < foo) index = foo;
+ if (index + 1 == 0)
+ clang_analyzer_warnIfReached(); // no-warning
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f14(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ long bar = foo;
+ if (index + 1 == 0)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void f15(long foo)
+{
+ unsigned index = -1;
+ if (index < foo) index = foo;
+ unsigned int tmp = index + 1;
+ if (tmp == 0)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ else
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
diff --git a/test/CXX/class/class.mem/p13.cpp b/test/CXX/class/class.mem/p13.cpp
index 1d7b9bc81551..bc01fd4d30c5 100644
--- a/test/CXX/class/class.mem/p13.cpp
+++ b/test/CXX/class/class.mem/p13.cpp
@@ -58,12 +58,12 @@ struct X3a {
};
// - every member of every anonymous union that is a member of class T.
-struct X4 {
+struct X4 { // expected-note{{previous}}
union {
int X;
union {
float Y;
- unsigned X4; // expected-error{{member 'X4' has the same name as its class}}
+ unsigned X4; // expected-error{{redeclares 'X4'}}
};
};
};
diff --git a/test/CXX/class/class.union/class.union.anon/p1.cpp b/test/CXX/class/class.union/class.union.anon/p1.cpp
new file mode 100644
index 000000000000..31c9313cf53a
--- /dev/null
+++ b/test/CXX/class/class.union/class.union.anon/p1.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -verify %s
+
+struct X {
+ int a; // expected-note {{previous}}
+ void b(); // expected-note {{previous}}
+ struct c; // expected-note {{previous}}
+ typedef int d; // expected-note {{previous}}
+
+ union {
+ int a; // expected-error {{member of anonymous union redeclares}}
+ int b; // expected-error {{member of anonymous union redeclares}}
+ int c; // expected-error {{member of anonymous union redeclares}}
+ int d; // expected-error {{member of anonymous union redeclares}}
+ int e; // expected-note {{previous}}
+ int f; // expected-note {{previous}}
+ int g; // expected-note {{previous}}
+ int h; // expected-note {{previous}}
+ };
+
+ int e; // expected-error {{duplicate member}}
+ void f(); // expected-error {{redefinition}}
+ struct g; // expected-error {{redefinition}}
+ typedef int h; // expected-error {{redefinition}}
+};
diff --git a/test/CXX/class/class.union/p8.cpp b/test/CXX/class/class.union/class.union.anon/p4.cpp
index cc54ba406619..cc54ba406619 100644
--- a/test/CXX/class/class.union/p8.cpp
+++ b/test/CXX/class/class.union/class.union.anon/p4.cpp
diff --git a/test/CXX/temp/temp.res/temp.local/p6.cpp b/test/CXX/temp/temp.res/temp.local/p6.cpp
index 06eb1bef7fea..843b45543fcf 100644
--- a/test/CXX/temp/temp.res/temp.local/p6.cpp
+++ b/test/CXX/temp/temp.res/temp.local/p6.cpp
@@ -5,7 +5,7 @@ namespace N {}
template<typename T, // expected-note {{declared here}}
typename T> struct X {}; // expected-error {{declaration of 'T' shadows template parameter}}
-template<typename T> struct Y { // expected-note 16{{declared here}}
+template<typename T> struct Y { // expected-note 17{{declared here}}
template<typename T> struct A {}; // expected-error {{declaration of 'T' shadows template parameter}}
struct B {
@@ -56,9 +56,74 @@ template<typename T> struct Y { // expected-note 16{{declared here}}
namespace T = N; // expected-error {{declaration of 'T' shadows template parameter}}
}
+ // FIXME: These diagnostics are poorly worded. Lookup for the elaborated type
+ // specifier finds the template parameter in this case, which is ill-formed
+ // because it's not a struct.
+ void f() {
+ struct T *p; // expected-error {{declaration of 'T' shadows template parameter}}
+ }
friend struct T; // expected-error {{declaration of 'T' shadows template parameter}}
};
+template<int T> struct Z { // expected-note 15{{declared here}}
+ template<typename T> struct A {}; // expected-error {{declaration of 'T' shadows template parameter}}
+
+ struct B {
+ template<typename> struct T {}; // FIXME: desired-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct C {
+ template<typename> void T(); // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct D {
+ struct T {}; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct E {
+ typedef int T; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct F {
+ using T = int; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct G {
+ int T; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct H {
+ static int T; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct I {
+ void T(); // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct J {
+ enum T { e }; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+ struct K {
+ enum E { T }; // expected-error {{declaration of 'T' shadows template parameter}}
+ };
+
+ void a() {
+ extern int T; // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+ void b() {
+ int T; // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+ void c() {
+ try {}
+ catch (int T) {} // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+ void d() {
+ void T(); // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+ void e() {
+ namespace T = N; // expected-error {{declaration of 'T' shadows template parameter}}
+ }
+
+ // These cases are valid when 'T' is a non-type template parameter, as T
+ // names an injected struct ::T, which doesn't shadow the template parameter.
+ void f() {
+ struct T *p;
+ }
+ friend struct T;
+};
+
template<typename T> // expected-note {{declared here}}
void f(int T) {} // expected-error {{declaration of 'T' shadows template parameter}}
diff --git a/test/CodeGen/builtins-ppc-vsx.c b/test/CodeGen/builtins-ppc-vsx.c
index 9a40d3041db1..15f98b57a513 100644
--- a/test/CodeGen/builtins-ppc-vsx.c
+++ b/test/CodeGen/builtins-ppc-vsx.c
@@ -845,4 +845,51 @@ void test1() {
// CHECK: xor <2 x i64>
// CHECK-LE: xor <2 x i64>
+ res_vsll = vec_cts(vd, 0);
+// CHECK: fmul <2 x double>
+// CHECK: fptosi <2 x double> %{{.*}} to <2 x i64>
+// CHECK-LE: fmul <2 x double>
+// CHECK-LE: fptosi <2 x double> %{{.*}} to <2 x i64>
+
+ res_vsll = vec_cts(vd, 31);
+// CHECK: fmul <2 x double>
+// CHECK: fptosi <2 x double> %{{.*}} to <2 x i64>
+// CHECK-LE: fmul <2 x double>
+// CHECK-LE: fptosi <2 x double> %{{.*}} to <2 x i64>
+
+ res_vsll = vec_ctu(vd, 0);
+// CHECK: fmul <2 x double>
+// CHECK: fptoui <2 x double> %{{.*}} to <2 x i64>
+// CHECK-LE: fmul <2 x double>
+// CHECK-LE: fptoui <2 x double> %{{.*}} to <2 x i64>
+
+ res_vsll = vec_ctu(vd, 31);
+// CHECK: fmul <2 x double>
+// CHECK: fptoui <2 x double> %{{.*}} to <2 x i64>
+// CHECK-LE: fmul <2 x double>
+// CHECK-LE: fptoui <2 x double> %{{.*}} to <2 x i64>
+
+ res_vd = vec_ctf(vsll, 0);
+// CHECK: sitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK: fmul <2 x double>
+// CHECK-LE: sitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK-LE: fmul <2 x double>
+
+ res_vd = vec_ctf(vsll, 31);
+// CHECK: sitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK: fmul <2 x double>
+// CHECK-LE: sitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK-LE: fmul <2 x double>
+
+ res_vd = vec_ctf(vull, 0);
+// CHECK: uitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK: fmul <2 x double>
+// CHECK-LE: uitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK-LE: fmul <2 x double>
+
+ res_vd = vec_ctf(vull, 31);
+// CHECK: uitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK: fmul <2 x double>
+// CHECK-LE: uitofp <2 x i64> %{{.*}} to <2 x double>
+// CHECK-LE: fmul <2 x double>
}
diff --git a/test/CodeGen/target-data.c b/test/CodeGen/target-data.c
index 08265f9da365..2ed7f0916fce 100644
--- a/test/CodeGen/target-data.c
+++ b/test/CodeGen/target-data.c
@@ -80,11 +80,11 @@
// RUN: %clang_cc1 -triple wasm32-unknown-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=WEBASSEMBLY32
-// WEBASSEMBLY32: target datalayout = "e-p:32:32-i64:64-n32:64-S128"
+// WEBASSEMBLY32: target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
// RUN: %clang_cc1 -triple wasm64-unknown-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=WEBASSEMBLY64
-// WEBASSEMBLY64: target datalayout = "e-p:64:64-i64:64-n32:64-S128"
+// WEBASSEMBLY64: target datalayout = "e-m:e-p:64:64-i64:64-n32:64-S128"
// RUN: %clang_cc1 -triple powerpc-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=PPC
diff --git a/test/CodeGenCXX/builtins-systemz-zvector.cpp b/test/CodeGenCXX/builtins-systemz-zvector.cpp
new file mode 100644
index 000000000000..aedb30ffbb4c
--- /dev/null
+++ b/test/CodeGenCXX/builtins-systemz-zvector.cpp
@@ -0,0 +1,50 @@
+// REQUIRES: systemz-registered-target
+// RUN: %clang_cc1 -target-cpu z13 -triple s390x-linux-gnu \
+// RUN: -fzvector -fno-lax-vector-conversions -std=c++11 \
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+
+bool gb;
+
+// There was an issue where we weren't properly converting constexprs to
+// vectors with elements of the appropriate width. (e.g.
+// (vector signed short)0 would be lowered as [4 x i32] in some cases)
+
+// CHECK-LABEL: @_Z8testIntsDv4_i
+void testInts(vector int VI) {
+ constexpr vector int CI1 = (vector int)0LL;
+ // CHECK: icmp
+ gb = (VI == CI1)[0];
+
+ // Likewise for float inits.
+ constexpr vector int CI2 = (vector int)char(0);
+ // CHECK: icmp
+ gb = (VI == CI2)[0];
+
+ constexpr vector int CF1 = (vector int)0.0;
+ // CHECK: icmp
+ gb = (VI == CF1)[0];
+
+ constexpr vector int CF2 = (vector int)0.0f;
+ // CHECK: icmp
+ gb = (VI == CF2)[0];
+}
+
+// CHECK-LABEL: @_Z10testFloatsDv2_d
+void testFloats(vector double VD) {
+ constexpr vector double CI1 = (vector double)0LL;
+ // CHECK: fcmp
+ gb = (VD == CI1)[0];
+
+ // Likewise for float inits.
+ constexpr vector double CI2 = (vector double)char(0);
+ // CHECK: fcmp
+ gb = (VD == CI2)[0];
+
+ constexpr vector double CF1 = (vector double)0.0;
+ // CHECK: fcmp
+ gb = (VD == CF1)[0];
+
+ constexpr vector double CF2 = (vector double)0.0f;
+ // CHECK: fcmp
+ gb = (VD == CF2)[0];
+}
diff --git a/test/CodeGenCXX/mangle-ms.cpp b/test/CodeGenCXX/mangle-ms.cpp
index c2a311423a9d..c82fca49f613 100644
--- a/test/CodeGenCXX/mangle-ms.cpp
+++ b/test/CodeGenCXX/mangle-ms.cpp
@@ -454,3 +454,28 @@ namespace Complex {
// CHECK-DAG: define void @"\01?f@Complex@@YAXU?$_Complex@H@__clang@@@Z"(
void f(_Complex int) {}
}
+
+namespace PR26029 {
+template <class>
+struct L {
+ L() {}
+};
+template <class>
+class H;
+struct M : L<H<int *> > {};
+
+template <class>
+struct H {};
+
+template <class GT>
+void m_fn3() {
+ (H<GT *>());
+ M();
+}
+
+void runOnFunction() {
+ L<H<int *> > b;
+ m_fn3<int>();
+}
+// CHECK-DAG: call {{.*}} @"\01??0?$L@V?$H@PAH@PR26029@@@PR26029@@QAE@XZ"
+}
diff --git a/test/CodeGenCXX/pass-object-size.cpp b/test/CodeGenCXX/pass-object-size.cpp
index 254669b97627..2c7f9742a8e6 100644
--- a/test/CodeGenCXX/pass-object-size.cpp
+++ b/test/CodeGenCXX/pass-object-size.cpp
@@ -25,3 +25,21 @@ void Lambdas(char *ptr) {
// CHECK-DAG: define internal i64 @"_ZZN7lambdas7LambdasEPcENK3$_1clEPvU17pass_object_size0"
// CHECK-NOT: call i64 @llvm.objectsize
}
+
+// This is here instead of in Sema/ because we need to check to make sure the
+// proper function is called. If it's not, we'll end up with assertion errors.
+namespace addrof {
+void OvlFoo(void *const __attribute__((pass_object_size(0)))) {}
+void OvlFoo(int *const) {}
+
+// CHECK: define void @_ZN6addrof4TestEv
+void Test() {
+ // Treating parens-only calls as though they were direct is consistent with
+ // how we handle other implicitly unaddressable functions (e.g. builtins).
+ // CHECK: call void @_ZN6addrof6OvlFooEPvU17pass_object_size0
+ (OvlFoo)(nullptr);
+
+ // CHECK: call void @_ZN6addrof6OvlFooEPi
+ (&OvlFoo)(nullptr);
+}
+}
diff --git a/test/CodeGenCXX/vector-splat-conversion.cpp b/test/CodeGenCXX/vector-splat-conversion.cpp
index 410df3dd0cef..805f9f5bab15 100644
--- a/test/CodeGenCXX/vector-splat-conversion.cpp
+++ b/test/CodeGenCXX/vector-splat-conversion.cpp
@@ -1,19 +1,51 @@
// RUN: %clang_cc1 %s -triple arm64-apple-ios8.1.0 -std=c++11 -emit-llvm -o - | FileCheck %s
-// rdar://20000762
typedef __attribute__((__ext_vector_type__(8))) float vector_float8;
typedef vector_float8 float8;
-void MandelbrotPolyCalcSIMD8()
-{
- constexpr float8 v4 = 4.0; // value to compare against abs(z)^2, to see if bounded
- float8 vABS;
- auto vLT = vABS < v4;
+// rdar://20000762
+// CHECK-LABEL: define void @_Z23MandelbrotPolyCalcSIMD8v
+void MandelbrotPolyCalcSIMD8() {
+ constexpr float8 v4 = 4.0; // value to compare against abs(z)^2, to see if bounded
+ float8 vABS;
+ auto vLT = vABS < v4;
+ // CHECK: store <8 x float>
+ // CHECK: [[ZERO:%.*]] = load <8 x float>, <8 x float>* [[VARBS:%.*]]
+ // CHECK: [[CMP:%.*]] = fcmp olt <8 x float> [[ZERO]]
+ // CHECK: [[SEXT:%.*]] = sext <8 x i1> [[CMP]] to <8 x i32>
+ // CHECK: store <8 x i32> [[SEXT]], <8 x i32>* [[VLT:%.*]]
}
-// CHECK: store <8 x float>
-// CHECK: [[ZERO:%.*]] = load <8 x float>, <8 x float>* [[VARBS:%.*]]
-// CHECK: [[CMP:%.*]] = fcmp olt <8 x float> [[ZERO]]
-// CHECK: [[SEXT:%.*]] = sext <8 x i1> [[CMP]] to <8 x i32>
-// CHECK: store <8 x i32> [[SEXT]], <8 x i32>* [[VLT:%.*]]
+typedef __attribute__((__ext_vector_type__(4))) int int4;
+typedef __attribute__((__ext_vector_type__(4))) float float4;
+typedef __attribute__((__ext_vector_type__(4))) __int128 bigint4;
+
+// CHECK-LABEL: define void @_Z14BoolConversionv
+void BoolConversion() {
+ // CHECK: store <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>
+ int4 intsT = (int4)true;
+ // CHECK: store <4 x i32> zeroinitializer
+ int4 intsF = (int4)false;
+ // CHECK: store <4 x float> <float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float -1.000000e+00>
+ float4 floatsT = (float4)true;
+ // CHECK: store <4 x float> zeroinitializer
+ float4 floatsF = (float4)false;
+ // CHECK: store <4 x i128> <i128 -1, i128 -1, i128 -1, i128 -1>
+ bigint4 bigintsT = (bigint4)true;
+ // CHECK: store <4 x i128> zeroinitializer
+ bigint4 bigintsF = (bigint4)false;
+
+ // CHECK: store <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>
+ constexpr int4 cIntsT = (int4)true;
+ // CHECK: store <4 x i32> zeroinitializer
+ constexpr int4 cIntsF = (int4)false;
+ // CHECK: store <4 x float> <float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float -1.000000e+00>
+ constexpr float4 cFloatsT = (float4)true;
+ // CHECK: store <4 x float> zeroinitializer
+ constexpr float4 cFloatsF = (float4)false;
+ // CHECK: store <4 x i128> <i128 -1, i128 -1, i128 -1, i128 -1>
+ constexpr bigint4 cBigintsT = (bigint4)true;
+ // CHECK: store <4 x i128> zeroinitializer
+ constexpr bigint4 cBigintsF = (bigint4)false;
+}
diff --git a/test/CodeGenOpenCL/bool_cast.cl b/test/CodeGenOpenCL/bool_cast.cl
index d63431b1b7ca..8c86b06577d6 100644
--- a/test/CodeGenOpenCL/bool_cast.cl
+++ b/test/CodeGenOpenCL/bool_cast.cl
@@ -2,7 +2,9 @@
typedef unsigned char uchar4 __attribute((ext_vector_type(4)));
typedef unsigned int int4 __attribute((ext_vector_type(4)));
+typedef float float4 __attribute((ext_vector_type(4)));
+// CHECK-LABEL: define void @ker()
void kernel ker() {
bool t = true;
int4 vec4 = (int4)t;
@@ -24,4 +26,8 @@ void kernel ker() {
unsigned char c;
c = (unsigned char)true;
// CHECK: store i8 1, i8* %c, align 1
+
+ float4 vf;
+ vf = (float4)true;
+// CHECK: store <4 x float> <float -1.000000e+00, float -1.000000e+00, float -1.000000e+00, float -1.000000e+00>
}
diff --git a/test/CodeGenOpenCL/pipe_types.cl b/test/CodeGenOpenCL/pipe_types.cl
new file mode 100644
index 000000000000..547071cf85a3
--- /dev/null
+++ b/test/CodeGenOpenCL/pipe_types.cl
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -emit-llvm -O0 -cl-std=CL2.0 -o - %s | FileCheck %s
+
+// CHECK: %opencl.pipe_t = type opaque
+typedef unsigned char __attribute__((ext_vector_type(3))) uchar3;
+typedef int __attribute__((ext_vector_type(4))) int4;
+
+void test1(read_only pipe int p) {
+// CHECK: define void @test1(%opencl.pipe_t* %p)
+ reserve_id_t rid;
+// CHECK: %rid = alloca %opencl.reserve_id_t
+}
+
+void test2(write_only pipe float p) {
+// CHECK: define void @test2(%opencl.pipe_t* %p)
+}
+
+void test3(read_only pipe const int p) {
+// CHECK: define void @test3(%opencl.pipe_t* %p)
+}
+
+void test4(read_only pipe uchar3 p) {
+// CHECK: define void @test4(%opencl.pipe_t* %p)
+}
+
+void test5(read_only pipe int4 p) {
+// CHECK: define void @test5(%opencl.pipe_t* %p)
+}
diff --git a/test/Driver/amdgpu-toolchain.c b/test/Driver/amdgpu-toolchain.c
index 41cef7f4c323..c84a154c7c18 100644
--- a/test/Driver/amdgpu-toolchain.c
+++ b/test/Driver/amdgpu-toolchain.c
@@ -1,3 +1,3 @@
// RUN: %clang -### -target amdgcn--amdhsa -x assembler -mcpu=kaveri %s 2>&1 | FileCheck -check-prefix=AS_LINK %s
// AS_LINK: clang{{.*}} "-cc1as"
-// AS_LINK: lld{{.*}} "-flavor" "old-gnu" "-target" "amdgcn--amdhsa"
+// AS_LINK: ld.lld{{.*}}
diff --git a/test/Driver/appletvos-version-min.c b/test/Driver/appletvos-version-min.c
index 9ff8297fe9eb..7cbb2001a3ec 100644
--- a/test/Driver/appletvos-version-min.c
+++ b/test/Driver/appletvos-version-min.c
@@ -2,6 +2,7 @@
// REQUIRES: aarch64-registered-target
// RUN: %clang -target i386-apple-darwin10 -mappletvsimulator-version-min=9.0 -arch x86_64 -S -o - %s | FileCheck %s
// RUN: %clang -target armv7s-apple-darwin10 -mappletvos-version-min=9.0 -arch arm64 -S -o - %s | FileCheck %s
+// RUN: env TVOS_DEPLOYMENT_TARGET=9.0 %clang -isysroot SDKs/MacOSX10.9.sdk -target i386-apple-darwin10 -arch x86_64 -S -o - %s | FileCheck %s
int main() { return 0; }
// CHECK: .tvos_version_min 9, 0
diff --git a/test/Driver/arm-xscale.c b/test/Driver/arm-xscale.c
new file mode 100644
index 000000000000..9b00b832095d
--- /dev/null
+++ b/test/Driver/arm-xscale.c
@@ -0,0 +1,3 @@
+// RUN: %clang -target arm-freebsd -mcpu=xscale -### -c %s 2>&1 | FileCheck %s
+// CHECK-NOT: error: the clang compiler does not support '-mcpu=xscale'
+// CHECK: "-cc1"{{.*}} "-target-cpu" "xscale"{{.*}}
diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c
index c23aefea146d..c5985a9c2b24 100644
--- a/test/Driver/cl-options.c
+++ b/test/Driver/cl-options.c
@@ -14,9 +14,14 @@
// C_P: "-E"
// C_P: "-C"
-// RUN: %clang_cl /Dfoo=bar -### -- %s 2>&1 | FileCheck -check-prefix=D %s
-// RUN: %clang_cl /D foo=bar -### -- %s 2>&1 | FileCheck -check-prefix=D %s
+// RUN: %clang_cl /Dfoo=bar /D bar=baz /DMYDEF#value /DMYDEF2=foo#bar /DMYDEF3#a=b /DMYDEF4# \
+// RUN: -### -- %s 2>&1 | FileCheck -check-prefix=D %s
// D: "-D" "foo=bar"
+// D: "-D" "bar=baz"
+// D: "-D" "MYDEF=value"
+// D: "-D" "MYDEF2=foo#bar"
+// D: "-D" "MYDEF3=a=b"
+// D: "-D" "MYDEF4="
// RUN: %clang_cl /E -### -- %s 2>&1 | FileCheck -check-prefix=E %s
// E: "-E"
diff --git a/test/Driver/cuda-bad-arch.cu b/test/Driver/cuda-bad-arch.cu
new file mode 100644
index 000000000000..f92bdcebd0d5
--- /dev/null
+++ b/test/Driver/cuda-bad-arch.cu
@@ -0,0 +1,22 @@
+// Checks errors generated by passing a bad value for --cuda-gpu-arch.
+// REQUIRES: clang-driver
+// REQUIRES: x86-registered-target
+// REQUIRES: nvptx-registered-target
+
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-gpu-arch=compute_20 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix BAD %s
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-gpu-arch=sm20 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix BAD %s
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-gpu-arch=sm_19 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix BAD %s
+
+// BAD: error: Unsupported CUDA gpu architecture
+
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-gpu-arch=sm_20 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix OK %s
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-gpu-arch=sm_52 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix OK %s
+// RUN: %clang -### -target x86_64-linux-gnu -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix OK %s
+
+// OK-NOT: error: Unsupported CUDA gpu architecture
diff --git a/test/Driver/cuda-options.cu b/test/Driver/cuda-options.cu
index 21625259d3ef..bf71633a4cf9 100644
--- a/test/Driver/cuda-options.cu
+++ b/test/Driver/cuda-options.cu
@@ -3,193 +3,140 @@
// REQUIRES: x86-registered-target
// REQUIRES: nvptx-registered-target
-// Simple compilation case:
+// Simple compilation case. Compile device-side to PTX assembly and make sure
+// we use it on the host side.
// RUN: %clang -### -target x86_64-linux-gnu -c %s 2>&1 \
-// Compile device-side to PTX assembly and make sure we use it on the host side.
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1NS\
-// Then compile host side and incorporate device code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-I1 \
-// Make sure we don't link anything.
-// RUN: -check-prefix CUDA-NL %s
-
-// Typical compilation + link case:
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-NOSAVE \
+// RUN: -check-prefix HOST -check-prefix INCLUDES-DEVICE \
+// RUN: -check-prefix NOLINK %s
+
+// Typical compilation + link case.
// RUN: %clang -### -target x86_64-linux-gnu %s 2>&1 \
-// Compile device-side to PTX assembly and make sure we use it on the host side
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1NS\
-// Then compile host side and incorporate device code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-I1 \
-// Then link things.
-// RUN: -check-prefix CUDA-L %s
-
-// Verify that --cuda-host-only disables device-side compilation and linking
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-NOSAVE \
+// RUN: -check-prefix HOST -check-prefix INCLUDES-DEVICE \
+// RUN: -check-prefix LINK %s
+
+// Verify that --cuda-host-only disables device-side compilation, but doesn't
+// disable host-side compilation/linking.
// RUN: %clang -### -target x86_64-linux-gnu --cuda-host-only %s 2>&1 \
-// Make sure we didn't run device-side compilation.
-// RUN: | FileCheck -check-prefix CUDA-ND \
-// Then compile host side and make sure we don't attempt to incorporate GPU code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-NI \
-// Linking is allowed to happen, even if we're missing GPU code.
-// RUN: -check-prefix CUDA-L %s
-
-// Same test as above, but with preceeding --cuda-device-only to make
-// sure only last option has effect.
+// RUN: | FileCheck -check-prefix NODEVICE -check-prefix HOST \
+// RUN: -check-prefix NOINCLUDES-DEVICE -check-prefix LINK %s
+
+// Same test as above, but with preceeding --cuda-device-only to make sure only
+// the last option has an effect.
// RUN: %clang -### -target x86_64-linux-gnu --cuda-device-only --cuda-host-only %s 2>&1 \
-// Make sure we didn't run device-side compilation.
-// RUN: | FileCheck -check-prefix CUDA-ND \
-// Then compile host side and make sure we don't attempt to incorporate GPU code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-NI \
-// Linking is allowed to happen, even if we're missing GPU code.
-// RUN: -check-prefix CUDA-L %s
-
-// Verify that --cuda-device-only disables host-side compilation and linking
+// RUN: | FileCheck -check-prefix NODEVICE -check-prefix HOST \
+// RUN: -check-prefix NOINCLUDES-DEVICE -check-prefix LINK %s
+
+// Verify that --cuda-device-only disables host-side compilation and linking.
// RUN: %clang -### -target x86_64-linux-gnu --cuda-device-only %s 2>&1 \
-// Compile device-side to PTX assembly
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1NS\
-// Make sure there are no host cmpilation or linking.
-// RUN: -check-prefix CUDA-NH -check-prefix CUDA-NL %s
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-NOSAVE \
+// RUN: -check-prefix NOHOST -check-prefix NOLINK %s
-// Same test as above, but with preceeding --cuda-host-only to make
-// sure only last option has effect.
+// Same test as above, but with preceeding --cuda-host-only to make sure only
+// the last option has an effect.
// RUN: %clang -### -target x86_64-linux-gnu --cuda-host-only --cuda-device-only %s 2>&1 \
-// Compile device-side to PTX assembly
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1NS\
-// Make sure there are no host cmpilation or linking.
-// RUN: -check-prefix CUDA-NH -check-prefix CUDA-NL %s
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-NOSAVE \
+// RUN: -check-prefix NOHOST -check-prefix NOLINK %s
-// Verify that with -S we compile host and device sides to assembly
-// and incorporate device code on the host side.
+// Verify that with -S we compile host and device sides to assembly and
+// incorporate device code into the host side.
// RUN: %clang -### -target x86_64-linux-gnu -S -c %s 2>&1 \
-// Compile device-side to PTX assembly
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1NS\
-// Then compile host side and incorporate GPU code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-I1 \
-// Make sure we don't link anything.
-// RUN: -check-prefix CUDA-NL %s
-
-// Verify that --cuda-gpu-arch option passes correct GPU
-// archtecture info to device compilation.
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-NOSAVE \
+// RUN: -check-prefix HOST -check-prefix INCLUDES-DEVICE \
+// RUN: -check-prefix NOLINK %s
+
+// Verify that --cuda-gpu-arch option passes the correct GPU archtecture to
+// device compilation.
// RUN: %clang -### -target x86_64-linux-gnu --cuda-gpu-arch=sm_35 -c %s 2>&1 \
-// Compile device-side to PTX assembly.
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1NS \
-// RUN: -check-prefix CUDA-D1-SM35 \
-// Then compile host side and incorporate GPU code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-H-I1 \
-// Make sure we don't link anything.
-// RUN: -check-prefix CUDA-NL %s
-
-// Verify that there is device-side compilation per --cuda-gpu-arch args
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-NOSAVE \
+// RUN: -check-prefix DEVICE-SM35 -check-prefix HOST \
+// RUN: -check-prefix INCLUDES-DEVICE -check-prefix NOLINK %s
+
+// Verify that there is one device-side compilation per --cuda-gpu-arch args
// and that all results are included on the host side.
// RUN: %clang -### -target x86_64-linux-gnu \
-// RUN: --cuda-gpu-arch=sm_35 --cuda-gpu-arch=sm_30 -c %s 2>&1 \
-// Compile both device-sides to PTX assembly
-// RUN: | FileCheck \
-// RUN: -check-prefix CUDA-D1 -check-prefix CUDA-D1NS -check-prefix CUDA-D1-SM35 \
-// RUN: -check-prefix CUDA-D2 -check-prefix CUDA-D2-SM30 \
-// Then compile host side and incorporate both device-side outputs
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-HNS \
-// RUN: -check-prefix CUDA-H-I1 -check-prefix CUDA-H-I2 \
-// Make sure we don't link anything.
-// RUN: -check-prefix CUDA-NL %s
-
-// Verify that device-side results are passed to correct tool when
-// -save-temps is used
+// RUN: --cuda-gpu-arch=sm_35 --cuda-gpu-arch=sm_30 -c %s 2>&1 \
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-NOSAVE \
+// RUN: -check-prefix DEVICE2 -check-prefix DEVICE-SM35 \
+// RUN: -check-prefix DEVICE2-SM30 -check-prefix HOST \
+// RUN: -check-prefix HOST-NOSAVE -check-prefix INCLUDES-DEVICE \
+// RUN: -check-prefix INCLUDES-DEVICE2 -check-prefix NOLINK %s
+
+// Verify that device-side results are passed to the correct tool when
+// -save-temps is used.
// RUN: %clang -### -target x86_64-linux-gnu -save-temps -c %s 2>&1 \
-// Compile device-side to PTX assembly and make sure we use it on the host side.
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1S \
-// Then compile host side and incorporate device code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-HS -check-prefix CUDA-HS-I1 \
-// Make sure we don't link anything.
-// RUN: -check-prefix CUDA-NL %s
-
-// Verify that device-side results are passed to correct tool when
-// -fno-integrated-as is used
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-SAVE \
+// RUN: -check-prefix HOST -check-prefix HOST-SAVE -check-prefix NOLINK %s
+
+// Verify that device-side results are passed to the correct tool when
+// -fno-integrated-as is used.
// RUN: %clang -### -target x86_64-linux-gnu -fno-integrated-as -c %s 2>&1 \
-// Compile device-side to PTX assembly and make sure we use it on the host side.
-// RUN: | FileCheck -check-prefix CUDA-D1 -check-prefix CUDA-D1NS \
-// Then compile host side and incorporate device code.
-// RUN: -check-prefix CUDA-H -check-prefix CUDA-HNS -check-prefix CUDA-HS-I1 \
-// RUN: -check-prefix CUDA-H-AS \
-// Make sure we don't link anything.
-// RUN: -check-prefix CUDA-NL %s
-
-// --cuda-host-only should never trigger unused arg warning.
-// RUN: %clang -### -target x86_64-linux-gnu --cuda-host-only -c %s 2>&1 | \
-// RUN: FileCheck -check-prefix CUDA-NO-UNUSED-CHO %s
-// RUN: %clang -### -target x86_64-linux-gnu --cuda-host-only -x c -c %s 2>&1 | \
-// RUN: FileCheck -check-prefix CUDA-NO-UNUSED-CHO %s
-
-// --cuda-device-only should not produce warning compiling CUDA files
-// RUN: %clang -### -target x86_64-linux-gnu --cuda-device-only -c %s 2>&1 | \
-// RUN: FileCheck -check-prefix CUDA-NO-UNUSED-CDO %s
-
-// --cuda-device-only should warn during non-CUDA compilation.
-// RUN: %clang -### -target x86_64-linux-gnu --cuda-device-only -x c -c %s 2>&1 | \
-// RUN: FileCheck -check-prefix CUDA-UNUSED-CDO %s
-
-// Match device-side preprocessor, and compiler phases with -save-temps
-// CUDA-D1S: "-cc1" "-triple" "nvptx64-nvidia-cuda"
-// CUDA-D1S-SAME: "-aux-triple" "x86_64--linux-gnu"
-// CUDA-D1S-SAME: "-fcuda-is-device"
-// CUDA-D1S-SAME: "-x" "cuda"
-
-// CUDA-D1S: "-cc1" "-triple" "nvptx64-nvidia-cuda"
-// CUDA-D1S-SAME: "-aux-triple" "x86_64--linux-gnu"
-// CUDA-D1S-SAME: "-fcuda-is-device"
-// CUDA-D1S-SAME: "-x" "cuda-cpp-output"
-
-// Match the job that produces PTX assembly
-// CUDA-D1: "-cc1" "-triple" "nvptx64-nvidia-cuda"
-// CUDA-D1NS-SAME: "-aux-triple" "x86_64--linux-gnu"
-// CUDA-D1-SAME: "-fcuda-is-device"
-// CUDA-D1-SM35-SAME: "-target-cpu" "sm_35"
-// CUDA-D1-SAME: "-o" "[[GPUBINARY1:[^"]*]]"
-// CUDA-D1NS-SAME: "-x" "cuda"
-// CUDA-D1S-SAME: "-x" "ir"
-
-// Match another device-side compilation
-// CUDA-D2: "-cc1" "-triple" "nvptx64-nvidia-cuda"
-// CUDA-D2-SAME: "-aux-triple" "x86_64--linux-gnu"
-// CUDA-D2-SAME: "-fcuda-is-device"
-// CUDA-D2-SM30-SAME: "-target-cpu" "sm_30"
-// CUDA-D2-SAME: "-o" "[[GPUBINARY2:[^"]*]]"
-// CUDA-D2-SAME: "-x" "cuda"
-
-// Match no device-side compilation
-// CUDA-ND-NOT: "-cc1" "-triple" "nvptx64-nvidia-cuda"
-// CUDA-ND-SAME-NOT: "-fcuda-is-device"
-
-// Match host-side preprocessor job with -save-temps
-// CUDA-HS: "-cc1" "-triple" "x86_64--linux-gnu"
-// CUDA-HS-SAME: "-aux-triple" "nvptx64-nvidia-cuda"
-// CUDA-HS-SAME-NOT: "-fcuda-is-device"
-// CUDA-HS-SAME: "-x" "cuda"
-
-// Match host-side compilation
-// CUDA-H: "-cc1" "-triple" "x86_64--linux-gnu"
-// CUDA-H-SAME: "-aux-triple" "nvptx64-nvidia-cuda"
-// CUDA-H-SAME-NOT: "-fcuda-is-device"
-// CUDA-H-SAME: "-o" "[[HOSTOUTPUT:[^"]*]]"
-// CUDA-HNS-SAME: "-x" "cuda"
-// CUDA-HS-SAME: "-x" "cuda-cpp-output"
-// CUDA-H-I1-SAME: "-fcuda-include-gpubinary" "[[GPUBINARY1]]"
-// CUDA-H-I2-SAME: "-fcuda-include-gpubinary" "[[GPUBINARY2]]"
-
-// Match external assembler that uses compilation output
-// CUDA-H-AS: "-o" "{{.*}}.o" "[[HOSTOUTPUT]]"
+// RUN: | FileCheck -check-prefix DEVICE -check-prefix DEVICE-NOSAVE \
+// RUN: -check-prefix HOST -check-prefix HOST-NOSAVE \
+// RUN: -check-prefix HOST-AS -check-prefix NOLINK %s
+
+// Match device-side preprocessor and compiler phases with -save-temps.
+// DEVICE-SAVE: "-cc1" "-triple" "nvptx64-nvidia-cuda"
+// DEVICE-SAVE-SAME: "-aux-triple" "x86_64--linux-gnu"
+// DEVICE-SAVE-SAME: "-fcuda-is-device"
+// DEVICE-SAVE-SAME: "-x" "cuda"
+
+// DEVICE-SAVE: "-cc1" "-triple" "nvptx64-nvidia-cuda"
+// DEVICE-SAVE-SAME: "-aux-triple" "x86_64--linux-gnu"
+// DEVICE-SAVE-SAME: "-fcuda-is-device"
+// DEVICE-SAVE-SAME: "-x" "cuda-cpp-output"
+
+// Match the job that produces PTX assembly.
+// DEVICE: "-cc1" "-triple" "nvptx64-nvidia-cuda"
+// DEVICE-NOSAVE-SAME: "-aux-triple" "x86_64--linux-gnu"
+// DEVICE-SAME: "-fcuda-is-device"
+// DEVICE-SM35-SAME: "-target-cpu" "sm_35"
+// DEVICE-SAME: "-o" "[[GPUBINARY1:[^"]*]]"
+// DEVICE-NOSAVE-SAME: "-x" "cuda"
+// DEVICE-SAVE-SAME: "-x" "ir"
+
+// Match another device-side compilation.
+// DEVICE2: "-cc1" "-triple" "nvptx64-nvidia-cuda"
+// DEVICE2-SAME: "-aux-triple" "x86_64--linux-gnu"
+// DEVICE2-SAME: "-fcuda-is-device"
+// DEVICE2-SM30-SAME: "-target-cpu" "sm_30"
+// DEVICE2-SAME: "-o" "[[GPUBINARY2:[^"]*]]"
+// DEVICE2-SAME: "-x" "cuda"
+
+// Match no device-side compilation.
+// NODEVICE-NOT: "-cc1" "-triple" "nvptx64-nvidia-cuda"
+// NODEVICE-SAME-NOT: "-fcuda-is-device"
+
+// Match host-side preprocessor job with -save-temps.
+// HOST-SAVE: "-cc1" "-triple" "x86_64--linux-gnu"
+// HOST-SAVE-SAME: "-aux-triple" "nvptx64-nvidia-cuda"
+// HOST-SAVE-SAME-NOT: "-fcuda-is-device"
+// HOST-SAVE-SAME: "-x" "cuda"
+
+// Match host-side compilation.
+// HOST: "-cc1" "-triple" "x86_64--linux-gnu"
+// HOST-SAME: "-aux-triple" "nvptx64-nvidia-cuda"
+// HOST-SAME-NOT: "-fcuda-is-device"
+// HOST-SAME: "-o" "[[HOSTOUTPUT:[^"]*]]"
+// HOST-NOSAVE-SAME: "-x" "cuda"
+// HOST-SAVE-SAME: "-x" "cuda-cpp-output"
+// INCLUDES-DEVICE-SAME: "-fcuda-include-gpubinary" "[[GPUBINARY1]]"
+// INCLUDES-DEVICE2-SAME: "-fcuda-include-gpubinary" "[[GPUBINARY2]]"
+
+// Match external assembler that uses compilation output.
+// HOST-AS: "-o" "{{.*}}.o" "[[HOSTOUTPUT]]"
// Match no GPU code inclusion.
-// CUDA-H-NI-NOT: "-fcuda-include-gpubinary"
-
-// Match no CUDA compilation
-// CUDA-NH-NOT: "-cc1" "-triple"
-// CUDA-NH-SAME-NOT: "-x" "cuda"
+// NOINCLUDES-DEVICE-NOT: "-fcuda-include-gpubinary"
-// Match linker
-// CUDA-L: "{{.*}}{{ld|link}}{{(.exe)?}}"
-// CUDA-L-SAME: "[[HOSTOUTPUT]]"
+// Match no host compilation.
+// NOHOST-NOT: "-cc1" "-triple"
+// NOHOST-SAME-NOT: "-x" "cuda"
-// Match no linker
-// CUDA-NL-NOT: "{{.*}}{{ld|link}}{{(.exe)?}}"
+// Match linker.
+// LINK: "{{.*}}{{ld|link}}{{(.exe)?}}"
+// LINK-SAME: "[[HOSTOUTPUT]]"
-// CUDA-NO-UNUSED-CHO-NOT: warning: argument unused during compilation: '--cuda-host-only'
-// CUDA-UNUSED-CDO: warning: argument unused during compilation: '--cuda-device-only'
-// CUDA-NO-UNUSED-CDO-NOT: warning: argument unused during compilation: '--cuda-device-only'
+// Match no linker.
+// NOLINK-NOT: "{{.*}}{{ld|link}}{{(.exe)?}}"
diff --git a/test/Driver/cuda-unused-arg-warning.cu b/test/Driver/cuda-unused-arg-warning.cu
new file mode 100644
index 000000000000..e8daad6cdaf6
--- /dev/null
+++ b/test/Driver/cuda-unused-arg-warning.cu
@@ -0,0 +1,23 @@
+// Tests that we trigger unused-arg warnings on CUDA flags appropriately.
+
+// REQUIRES: clang-driver
+// REQUIRES: x86-registered-target
+// REQUIRES: nvptx-registered-target
+
+// --cuda-host-only should never trigger unused arg warning.
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-host-only -c %s 2>&1 | \
+// RUN: FileCheck %s
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-host-only -x c -c %s 2>&1 | \
+// RUN: FileCheck %s
+
+// --cuda-device-only should warn during non-CUDA compilation.
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-device-only -x c -c %s 2>&1 | \
+// RUN: FileCheck -check-prefix UNUSED-WARNING %s
+
+// --cuda-device-only should not produce warning compiling CUDA files
+// RUN: %clang -### -target x86_64-linux-gnu --cuda-device-only -c %s 2>&1 | \
+// RUN: FileCheck -check-prefix NO-UNUSED-WARNING %s
+
+// CHECK-NOT: warning: argument unused during compilation: '--cuda-host-only'
+// UNUSED-WARNING: warning: argument unused during compilation: '--cuda-device-only'
+// NO-UNUSED-WARNING-NOT: warning: argument unused during compilation: '--cuda-device-only'
diff --git a/test/Driver/debug-options.c b/test/Driver/debug-options.c
index 72d0136a8c40..0ccacd0fc6c7 100644
--- a/test/Driver/debug-options.c
+++ b/test/Driver/debug-options.c
@@ -32,7 +32,7 @@
// RUN: | FileCheck -check-prefix=G_DARWIN %s
// RUN: %clang -### -c -g %s -target x86_64-pc-freebsd10.0 2>&1 \
-// RUN: | FileCheck -check-prefix=G_LLDB %s
+// RUN: | FileCheck -check-prefix=G_GDB %s
// On the PS4, -g defaults to -gno-column-info, and we always generate the
// arange section.
diff --git a/test/Driver/fortran.f95 b/test/Driver/fortran.f95
index 982f4eb5e6df..47c6e7b50c95 100644
--- a/test/Driver/fortran.f95
+++ b/test/Driver/fortran.f95
@@ -13,3 +13,9 @@
// CHECK-ASM: "-S"
// CHECK-ASM: "-x" "f95"
// CHECK-ASM-NOT: cc1
+
+// RUN: %clang -Wall -target x86_64-unknown-linux-gnu -integrated-as %s -o %t -### 2>&1 | FileCheck --check-prefix=CHECK-WARN %s
+// CHECK-WARN: gcc
+// CHECK-WARN-NOT: "-Wall"
+// CHECK-WARN: ld
+// CHECK-WARN-NOT: "-Wall"
diff --git a/test/Driver/gcc_forward.c b/test/Driver/gcc_forward.c
index 4892bd92ac69..d28e432b1e17 100644
--- a/test/Driver/gcc_forward.c
+++ b/test/Driver/gcc_forward.c
@@ -5,15 +5,16 @@
// RUN: %s \
// RUN: -Wall -Wdocumentation \
// RUN: -Xclang foo-bar \
-// RUN: -march=x86_64 \
+// RUN: -march=x86-64 \
// RUN: -mlinker-version=10 -### 2> %t
// RUN: FileCheck < %t %s
//
-// clang-cc1
+// clang -cc1
+// CHECK: clang
// CHECK: "-Wall" "-Wdocumentation"
// CHECK: "-o" "{{[^"]+}}.o"
//
-// gcc-ld
+// gcc as ld.
// CHECK: gcc{{[^"]*}}"
// CHECK-NOT: "-mlinker-version=10"
// CHECK-NOT: "-Xclang"
@@ -27,3 +28,9 @@
// CHECK-NOT: "-Wall"
// CHECK-NOT: "-Wdocumentation"
// CHECK: "-o" "a.out"
+
+// Check that we're not forwarding -g options to the assembler
+// RUN: %clang -g -target x86_64-unknown-linux-gnu -no-integrated-as -c %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ASM %s
+// CHECK-ASM: as
+// CHECK-ASM-NOT: "-g"
diff --git a/test/Driver/pic.c b/test/Driver/pic.c
index 06b4204e60da..aeb2ee33114c 100644
--- a/test/Driver/pic.c
+++ b/test/Driver/pic.c
@@ -218,6 +218,8 @@
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
// RUN: %clang -c %s -target armv7-apple-ios -fapple-kext -miphoneos-version-min=6.0.0 -static -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
+// RUN: %clang -c %s -target armv7-apple-unknown-macho -static -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
//
// On OpenBSD, PIE is enabled by default, but can be disabled.
// RUN: %clang -c %s -target amd64-pc-openbsd -### 2>&1 \
diff --git a/test/Driver/wasm-toolchain.c b/test/Driver/wasm-toolchain.c
index 4d707a0f6c8f..b9685b160192 100644
--- a/test/Driver/wasm-toolchain.c
+++ b/test/Driver/wasm-toolchain.c
@@ -1,3 +1,44 @@
-// RUN: %clang -### -no-canonical-prefixes -target wasm32-unknown-unknown -x assembler %s 2>&1 | FileCheck -check-prefix=AS_LINK %s
-// AS_LINK: clang{{.*}}" "-cc1as" {{.*}} "-o" "[[temp:[^"]*]]"
-// AS_LINK: lld{{.*}}" "-flavor" "ld" "[[temp]]" "-o" "a.out"
+// A basic clang -cc1 command-line. WebAssembly is somewhat special in
+// enabling -ffunction-sections, -fdata-sections, and -fvisibility=hidden by
+// default.
+
+// RUN: %clang %s -### -no-canonical-prefixes -target wasm32-unknown-unknown 2>&1 | FileCheck -check-prefix=CC1 %s
+// CC1: clang{{.*}} "-cc1" "-triple" "wasm32-unknown-unknown" {{.*}} "-fvisibility" "hidden" {{.*}} "-ffunction-sections" "-fdata-sections"
+
+// Ditto, but ensure that a user -fno-function-sections disables the
+// default -ffunction-sections.
+
+// RUN: %clang %s -### -target wasm32-unknown-unknown -fno-function-sections 2>&1 | FileCheck -check-prefix=NO_FUNCTION_SECTIONS %s
+// NO_FUNCTION_SECTIONS-NOT: function-sections
+
+// Ditto, but ensure that a user -fno-data-sections disables the
+// default -fdata-sections.
+
+// RUN: %clang %s -### -target wasm32-unknown-unknown -fno-data-sections 2>&1 | FileCheck -check-prefix=NO_DATA_SECTIONS %s
+// NO_DATA_SECTIONS-NOT: data-sections
+
+// Ditto, but ensure that a user -fvisibility=default disables the default
+// -fvisibility=hidden.
+
+// RUN: %clang %s -### -target wasm32-unknown-unknown -fvisibility=default 2>&1 | FileCheck -check-prefix=FVISIBILITY_DEFAULT %s
+// FVISIBILITY_DEFAULT-NOT: hidden
+
+// A basic C link command-line.
+
+// RUN: %clang -### -no-canonical-prefixes -target wasm32-unknown-unknown %s 2>&1 | FileCheck -check-prefix=LINK %s
+// LINK: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]"
+// LINK: lld{{.*}}" "-flavor" "ld" "[[temp]]" "-o" "a.out"
+
+// A basic C link command-line with optimization. WebAssembly is somewhat
+// special in enabling --gc-sections by default.
+
+// RUN: %clang -### -O2 -no-canonical-prefixes -target wasm32-unknown-unknown %s 2>&1 | FileCheck -check-prefix=LINK_OPT %s
+// LINK_OPT: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]"
+// LINK_OPT: lld{{.*}}" "-flavor" "ld" "--gc-sections" "[[temp]]" "-o" "a.out"
+
+// Ditto, but ensure that a user --no-gc-sections comes after the
+// default --gc-sections.
+
+// RUN: %clang -### -O2 -no-canonical-prefixes -target wasm32-unknown-unknown -Wl,--no-gc-sections %s 2>&1 | FileCheck -check-prefix=NO_GC_SECTIONS %s
+// NO_GC_SECTIONS: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]"
+// NO_GC_SECTIONS: lld{{.*}}" "-flavor" "ld" "--gc-sections" "--no-gc-sections" "[[temp]]" "-o" "a.out"
diff --git a/test/Driver/wasm32-unknown-unknown.cpp b/test/Driver/wasm32-unknown-unknown.cpp
index c47428796dc9..3f44d93df570 100644
--- a/test/Driver/wasm32-unknown-unknown.cpp
+++ b/test/Driver/wasm32-unknown-unknown.cpp
@@ -13,34 +13,34 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t;
extern "C" {
-// CHECK: @align_c = global i32 1
+// CHECK: @align_c = hidden global i32 1
int align_c = __alignof(char);
-// CHECK: @align_s = global i32 2
+// CHECK: @align_s = hidden global i32 2
int align_s = __alignof(short);
-// CHECK: @align_i = global i32 4
+// CHECK: @align_i = hidden global i32 4
int align_i = __alignof(int);
-// CHECK: @align_l = global i32 4
+// CHECK: @align_l = hidden global i32 4
int align_l = __alignof(long);
-// CHECK: @align_ll = global i32 8
+// CHECK: @align_ll = hidden global i32 8
int align_ll = __alignof(long long);
-// CHECK: @align_p = global i32 4
+// CHECK: @align_p = hidden global i32 4
int align_p = __alignof(void*);
-// CHECK: @align_f = global i32 4
+// CHECK: @align_f = hidden global i32 4
int align_f = __alignof(float);
-// CHECK: @align_d = global i32 8
+// CHECK: @align_d = hidden global i32 8
int align_d = __alignof(double);
-// CHECK: @align_ld = global i32 16
+// CHECK: @align_ld = hidden global i32 16
int align_ld = __alignof(long double);
-// CHECK: @align_vl = global i32 4
+// CHECK: @align_vl = hidden global i32 4
int align_vl = __alignof(va_list);
// CHECK: _GNU_SOURCEdefined
diff --git a/test/Driver/wasm64-unknown-unknown.cpp b/test/Driver/wasm64-unknown-unknown.cpp
index c33f4e56a65f..6162759884a8 100644
--- a/test/Driver/wasm64-unknown-unknown.cpp
+++ b/test/Driver/wasm64-unknown-unknown.cpp
@@ -13,34 +13,34 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t;
extern "C" {
-// CHECK: @align_c = global i32 1
+// CHECK: @align_c = hidden global i32 1
int align_c = __alignof(char);
-// CHECK: @align_s = global i32 2
+// CHECK: @align_s = hidden global i32 2
int align_s = __alignof(short);
-// CHECK: @align_i = global i32 4
+// CHECK: @align_i = hidden global i32 4
int align_i = __alignof(int);
-// CHECK: @align_l = global i32 8
+// CHECK: @align_l = hidden global i32 8
int align_l = __alignof(long);
-// CHECK: @align_ll = global i32 8
+// CHECK: @align_ll = hidden global i32 8
int align_ll = __alignof(long long);
-// CHECK: @align_p = global i32 8
+// CHECK: @align_p = hidden global i32 8
int align_p = __alignof(void*);
-// CHECK: @align_f = global i32 4
+// CHECK: @align_f = hidden global i32 4
int align_f = __alignof(float);
-// CHECK: @align_d = global i32 8
+// CHECK: @align_d = hidden global i32 8
int align_d = __alignof(double);
-// CHECK: @align_ld = global i32 16
+// CHECK: @align_ld = hidden global i32 16
int align_ld = __alignof(long double);
-// CHECK: @align_vl = global i32 8
+// CHECK: @align_vl = hidden global i32 8
int align_vl = __alignof(va_list);
// CHECK: _GNU_SOURCEdefined
diff --git a/test/Index/print-type-declaration.cpp b/test/Index/print-type-declaration.cpp
new file mode 100644
index 000000000000..31c0a73fcd06
--- /dev/null
+++ b/test/Index/print-type-declaration.cpp
@@ -0,0 +1,12 @@
+
+class Test{};
+
+int main()
+{
+ auto a = Test();
+ auto b = a;
+}
+
+// RUN: c-index-test -test-print-type-declaration -std=c++11 %s | FileCheck %s
+// CHECK: VarDecl=a:6:8 (Definition) [typedeclaration=Test] [typekind=Record]
+// CHECK: VarDecl=b:7:8 (Definition) [typedeclaration=Test] [typekind=Record]
diff --git a/test/Misc/ast-dump-lookups.cpp b/test/Misc/ast-dump-lookups.cpp
index 5c6da48b3afb..2d235010cb73 100644
--- a/test/Misc/ast-dump-lookups.cpp
+++ b/test/Misc/ast-dump-lookups.cpp
@@ -1,16 +1,31 @@
// RUN: %clang_cc1 -std=c++11 -ast-dump -ast-dump-filter Test %s | FileCheck -check-prefix DECLS %s
// RUN: %clang_cc1 -std=c++11 -ast-dump-lookups -ast-dump-filter Test %s | FileCheck -check-prefix LOOKUPS %s
// RUN: %clang_cc1 -std=c++11 -ast-dump -ast-dump-lookups -ast-dump-filter Test %s | FileCheck -check-prefix DECLS-LOOKUPS %s
+// RUN: %clang_cc1 -std=c++11 -DPRAGMA -fsyntax-only %s 2>&1 | FileCheck -check-prefix PRAGMA %s
namespace Test {
+ typedef int T;
extern int a;
int a = 0;
}
+#ifdef PRAGMA
+#pragma clang __debug dump Test
+// PRAGMA: lookup results for Test:
+// PRAGMA-NEXT: NamespaceDecl {{.*}} Test
+// PRAGMA-NEXT: |-TypedefDecl {{.*}} T 'int'
+// PRAGMA-NEXT: | `-BuiltinType {{.*}} 'int'
+// PRAGMA-NEXT: |-VarDecl [[EXTERN_A:0x[^ ]*]] {{.*}} a 'int' extern
+// PRAGMA-NEXT: `-VarDecl {{.*}} prev [[EXTERN_A]] {{.*}} a 'int' cinit
+// PRAGMA-NEXT: `-IntegerLiteral {{.*}} 'int' 0
+#endif
+
namespace Test { }
// DECLS: Dumping Test:
// DECLS-NEXT: NamespaceDecl {{.*}} Test
+// DECLS-NEXT: |-TypedefDecl {{.*}} T 'int'
+// DECLS-NEXT: | `-BuiltinType {{.*}} 'int'
// DECLS-NEXT: |-VarDecl [[EXTERN_A:0x[^ ]*]] {{.*}} a 'int' extern
// DECLS-NEXT: `-VarDecl {{.*}} prev [[EXTERN_A]] {{.*}} a 'int' cinit
// DECLS-NEXT: `-IntegerLiteral {{.*}} 'int' 0
@@ -20,15 +35,15 @@ namespace Test { }
// LOOKUPS: Dumping Test:
// LOOKUPS-NEXT: StoredDeclsMap Namespace {{.*}} 'Test'
-// LOOKUPS-NEXT: `-DeclarationName 'a'
-// LOOKUPS-NEXT: `-Var {{.*}} 'a' 'int'
+// LOOKUPS: DeclarationName 'a'
+// LOOKUPS-NEXT: `-Var {{.*}} 'a' 'int'
//
// LOOKUPS: Dumping Test:
// LOOKUPS-NEXT: Lookup map is in primary DeclContext
// DECLS-LOOKUPS: Dumping Test:
// DECLS-LOOKUPS-NEXT: StoredDeclsMap Namespace {{.*}} 'Test'
-// DECLS-LOOKUPS-NEXT: `-DeclarationName 'a'
+// DECLS-LOOKUPS: -DeclarationName 'a'
// DECLS-LOOKUPS-NEXT: `-Var [[A:[^ ]*]] 'a' 'int'
// DECLS-LOOKUPS-NEXT: |-VarDecl [[EXTERN_A:0x[^ ]*]] {{.*}} a 'int' extern
// DECLS-LOOKUPS-NEXT: `-VarDecl [[A]] prev [[EXTERN_A]] {{.*}} a 'int' cinit
diff --git a/test/Misc/ast-print-char-literal.cpp b/test/Misc/ast-print-char-literal.cpp
new file mode 100644
index 000000000000..bb5daa2444da
--- /dev/null
+++ b/test/Misc/ast-print-char-literal.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -ast-print -std=c++1z %s -o - | FileCheck %s
+
+char c = u8'1';
+char d = '1';
+char e = U'1';
+char f = L'1';
+char g = u'1';
+
+template <char c = u8'1'>
+void h();
+
+void i() {
+ h<u8'2'>();
+}
+
+// CHECK: char c = u8'1';
+// CHECK-NEXT: char d = '1';
+// CHECK-NEXT: char e = U'1';
+// CHECK-NEXT: char f = L'1';
+// CHECK-NEXT: char g = u'1';
+
+// CHECK: template <char c = u8'1'>
+
+// CHECK: h<u8'2'>();
diff --git a/test/Modules/Inputs/DebugCXX.h b/test/Modules/Inputs/DebugCXX.h
index 6ef4445cb971..b6a52579fc3a 100644
--- a/test/Modules/Inputs/DebugCXX.h
+++ b/test/Modules/Inputs/DebugCXX.h
@@ -17,7 +17,7 @@ namespace DebugCXX {
e2 = '2'
};
- // Templates (instatiations).
+ // Templates (instantiations).
template<typename T> struct traits {};
template<typename T,
typename Traits = traits<T>
@@ -50,3 +50,11 @@ namespace DebugCXX {
typedef A<void> B;
void foo(B) {}
}
+
+// Virtual class with a forward declaration.
+class FwdVirtual;
+class FwdVirtual {
+ virtual ~FwdVirtual() {}
+};
+
+struct PureForwardDecl;
diff --git a/test/Modules/Inputs/dummy.h b/test/Modules/Inputs/dummy.h
index 6e1ac74e44fb..cad83154dc2e 100644
--- a/test/Modules/Inputs/dummy.h
+++ b/test/Modules/Inputs/dummy.h
@@ -1,3 +1,5 @@
// This module only exists to make local decl IDs and global decl IDs different.
-
+#ifndef DUMMY_H
+#define DUMMY_H
struct Dummy {} extern *dummy1, *dummy2, *dummy3;
+#endif
diff --git a/test/Modules/Inputs/using-decl-redecl/a.h b/test/Modules/Inputs/using-decl-redecl/a.h
index 477546945c09..eaa1876aac68 100644
--- a/test/Modules/Inputs/using-decl-redecl/a.h
+++ b/test/Modules/Inputs/using-decl-redecl/a.h
@@ -1,2 +1,3 @@
struct string {};
-namespace N { typedef ::string clstring; }
+const int n = 0;
+namespace N { typedef ::string clstring; using ::n; }
diff --git a/test/Modules/Inputs/using-decl-redecl/d.h b/test/Modules/Inputs/using-decl-redecl/d.h
new file mode 100644
index 000000000000..2243de1baf9a
--- /dev/null
+++ b/test/Modules/Inputs/using-decl-redecl/d.h
@@ -0,0 +1 @@
+#include "a.h"
diff --git a/test/Modules/Inputs/using-decl-redecl/module.modulemap b/test/Modules/Inputs/using-decl-redecl/module.modulemap
index bd6ea830c2d4..a2ebc1767645 100644
--- a/test/Modules/Inputs/using-decl-redecl/module.modulemap
+++ b/test/Modules/Inputs/using-decl-redecl/module.modulemap
@@ -1,3 +1,4 @@
module a { header "a.h" }
-module b { header "b.h" export * }
-module c { header "c.h" export * }
+module b { header "b.h" export a }
+module c { header "c.h" export a export b }
+module d { header "d.h" }
diff --git a/test/Modules/ModuleDebugInfo.cpp b/test/Modules/ModuleDebugInfo.cpp
index 82500f0d162d..bbe36cb225d0 100644
--- a/test/Modules/ModuleDebugInfo.cpp
+++ b/test/Modules/ModuleDebugInfo.cpp
@@ -23,22 +23,34 @@
// CHECK-SAME: isOptimized: false,
// CHECK-SAME-NOT: splitDebugFilename:
// CHECK-DWO: dwoId:
+
// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum"
// CHECK-SAME: identifier: "_ZTSN8DebugCXX4EnumE")
// CHECK: !DINamespace(name: "DebugCXX"
+
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Struct"
// CHECK-SAME: identifier: "_ZTSN8DebugCXX6StructE")
+
// CHECK: !DICompositeType(tag: DW_TAG_class_type,
// CHECK-SAME: name: "Template<int, DebugCXX::traits<int> >"
// CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIiNS_6traitsIiEEEE")
+
+// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "A<void>"
+// CHECK-SAME: identifier: "_ZTSN8DebugCXX1AIJvEEE")
+
// CHECK: !DICompositeType(tag: DW_TAG_class_type,
// CHECK-SAME: name: "Template<float, DebugCXX::traits<float> >"
// CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIfNS_6traitsIfEEEE")
-// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "A<void>"
-// CHECK-SAME: identifier: "_ZTSN8DebugCXX1AIJvEEE")
+
+// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "FwdVirtual"
+// CHECK-SAME: elements:
+// CHECK-SAME: identifier: "_ZTS10FwdVirtual")
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "_vptr$FwdVirtual"
+
// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "FloatInstatiation"
// no mangled name here yet.
+
// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "B",
// no mangled name here yet.
-// CHECK-NEG-NOT: "_ZTSN8DebugCXX8TemplateIlNS_6traitsIlEEEE"
+// CHECK-NEG-NOT: !DICompositeType(tag: DW_TAG_structure_type, name: "PureForwardDecl"
diff --git a/test/Modules/modular_maps.cpp b/test/Modules/modular_maps.cpp
index 3b6afc7552d6..fc44131d4587 100644
--- a/test/Modules/modular_maps.cpp
+++ b/test/Modules/modular_maps.cpp
@@ -16,4 +16,4 @@
#include "b.h" // expected-error {{private header}}
@import C;
const int v = a + c + x;
-const int val = a + b + c + x; // expected-error {{undeclared identifier}}
+const int val = a + b + c + x;
diff --git a/test/Modules/separate_map_tree.cpp b/test/Modules/separate_map_tree.cpp
index 5a1fff4efc70..a5cb9888a600 100644
--- a/test/Modules/separate_map_tree.cpp
+++ b/test/Modules/separate_map_tree.cpp
@@ -5,4 +5,4 @@
#include "public-in-b.h" // expected-error {{private header}}
#include "public-in-c.h"
#include "private-in-c.h" // expected-error {{private header}}
-const int val = common + b + c + c_; // expected-error {{undeclared identifier}}
+const int val = common + b + c + c_;
diff --git a/test/Modules/tag-injection.c b/test/Modules/tag-injection.c
new file mode 100644
index 000000000000..5bb15477e2e2
--- /dev/null
+++ b/test/Modules/tag-injection.c
@@ -0,0 +1,18 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo 'struct a;' > %t/a.h
+// RUN: echo 'struct b {}; void foo(struct b*);' > %t/b.h
+// RUN: echo 'module X { module a { header "a.h" } module b { header "b.h" } }' > %t/x.modulemap
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodule-map-file=%t/x.modulemap %s -I%t -verify
+
+#include "a.h"
+
+void f(struct a *p);
+
+// FIXME: We should warn that 'b' will not be visible outside of this function,
+// but we merge this 'b' with X.b's 'b' because we don't yet implement C's
+// "compatible types" rule.
+void g(struct b *p);
+
+struct b b; // expected-error {{definition of 'b' must be imported from module 'X.b' before it is required}}
+// expected-note@b.h:1 {{here}}
diff --git a/test/Modules/tag-injection.cpp b/test/Modules/tag-injection.cpp
index 75c8b5fecdb4..e55598b06202 100644
--- a/test/Modules/tag-injection.cpp
+++ b/test/Modules/tag-injection.cpp
@@ -1,12 +1,15 @@
// RUN: rm -rf %t
// RUN: mkdir %t
-// RUN: touch %t/a.h
-// RUN: echo 'struct X {};' > %t/b.h
+// RUN: echo 'struct tm;' > %t/a.h
+// RUN: echo 'struct X {}; void foo(struct tm*);' > %t/b.h
// RUN: echo 'module X { module a { header "a.h" } module b { header "b.h" } }' > %t/x.modulemap
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x c++ -fmodule-map-file=%t/x.modulemap %s -I%t -verify -std=c++11
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x c++ -fmodule-map-file=%t/x.modulemap %s -I%t -verify -fmodules-local-submodule-visibility -std=c++11
#include "a.h"
+using ::tm;
+
struct A {
// This use of 'struct X' makes the declaration (but not definition) of X visible.
virtual void f(struct X *p);
diff --git a/test/Modules/using-decl-redecl.cpp b/test/Modules/using-decl-redecl.cpp
index 0e78cec1188f..0524052fce5b 100644
--- a/test/Modules/using-decl-redecl.cpp
+++ b/test/Modules/using-decl-redecl.cpp
@@ -2,10 +2,20 @@
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t \
// RUN: -fmodule-map-file=%S/Inputs/using-decl-redecl/module.modulemap \
// RUN: -I%S/Inputs/using-decl-redecl \
+// RUN: -Wno-modules-ambiguous-internal-linkage \
// RUN: -verify %s
+
+#include "d.h"
+
+const int n = 0;
+namespace M { using ::n; }
+
#include "c.h"
+
N::clstring y = b;
// Use a typo to trigger import of all declarations in N.
N::clstrinh s; // expected-error {{did you mean 'clstring'}}
-// expected-note@a.h:2 {{here}}
+// expected-note@a.h:3 {{here}}
+
+namespace M { using N::n; }
diff --git a/test/OpenMP/barrier_ast_print.cpp b/test/OpenMP/barrier_ast_print.cpp
index fbb478bfb6b7..062df80a226e 100644
--- a/test/OpenMP/barrier_ast_print.cpp
+++ b/test/OpenMP/barrier_ast_print.cpp
@@ -12,6 +12,15 @@ template <class T>
T tmain(T argc) {
static T a;
#pragma omp barrier
+ switch (argc) {
+ case 0:
+#pragma omp barrier
+ break;
+ default:
+#pragma omp barrier
+#pragma omp barrier
+ break;
+ }
return a + argc;
}
// CHECK: static int a;
@@ -20,12 +29,39 @@ T tmain(T argc) {
// CHECK-NEXT: #pragma omp barrier
// CHECK: static T a;
// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: switch (argc) {
+// CHECK-NEXT: case 0:
+// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: break;
+// CHECK-NEXT: default:
+// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: break;
+// CHECK-NEXT: }
int main(int argc, char **argv) {
static int a;
// CHECK: static int a;
#pragma omp barrier
// CHECK-NEXT: #pragma omp barrier
+ switch (argc) {
+ case 0:
+#pragma omp barrier
+#pragma omp barrier
+ break;
+ default:
+#pragma omp barrier
+ break;
+ }
+// CHECK-NEXT: switch (argc) {
+// CHECK-NEXT: case 0:
+// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: break;
+// CHECK-NEXT: default:
+// CHECK-NEXT: #pragma omp barrier
+// CHECK-NEXT: break;
+// CHECK-NEXT: }
return tmain(argc) + tmain(argv[0][0]) + a;
}
diff --git a/test/OpenMP/barrier_messages.cpp b/test/OpenMP/barrier_messages.cpp
index 4dc6480a57e2..7d79445d2857 100644
--- a/test/OpenMP/barrier_messages.cpp
+++ b/test/OpenMP/barrier_messages.cpp
@@ -27,7 +27,7 @@ T tmain(T argc) {
#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
+#pragma omp barrier
switch (argc)
case 1: {
#pragma omp barrier
@@ -35,7 +35,7 @@ T tmain(T argc) {
switch (argc) {
#pragma omp barrier
case 1:
-#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
+#pragma omp barrier
break;
default: {
#pragma omp barrier
@@ -81,7 +81,7 @@ int main(int argc, char **argv) {
#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
+#pragma omp barrier
switch (argc)
case 1: {
#pragma omp barrier
@@ -89,7 +89,7 @@ int main(int argc, char **argv) {
switch (argc) {
#pragma omp barrier
case 1:
-#pragma omp barrier // expected-error {{'#pragma omp barrier' cannot be an immediate substatement}}
+#pragma omp barrier
break;
default: {
#pragma omp barrier
diff --git a/test/OpenMP/cancel_messages.cpp b/test/OpenMP/cancel_messages.cpp
index 07088387cb4f..e23b5c337bc8 100644
--- a/test/OpenMP/cancel_messages.cpp
+++ b/test/OpenMP/cancel_messages.cpp
@@ -53,7 +53,7 @@ int main(int argc, char **argv) {
#pragma omp cancel parallel // expected-error {{'#pragma omp cancel' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp cancel sections // expected-error {{'#pragma omp cancel' cannot be an immediate substatement}}
+#pragma omp cancel sections
switch (argc)
case 1: {
#pragma omp cancel for
@@ -61,7 +61,7 @@ int main(int argc, char **argv) {
switch (argc) {
#pragma omp cancel taskgroup
case 1:
-#pragma omp cancel parallel // expected-error {{'#pragma omp cancel' cannot be an immediate substatement}}
+#pragma omp cancel parallel
break;
default: {
#pragma omp cancel sections
diff --git a/test/OpenMP/cancellation_point_messages.cpp b/test/OpenMP/cancellation_point_messages.cpp
index d25cb6113d16..2324915e83f8 100644
--- a/test/OpenMP/cancellation_point_messages.cpp
+++ b/test/OpenMP/cancellation_point_messages.cpp
@@ -53,7 +53,7 @@ int main(int argc, char **argv) {
#pragma omp cancellation point parallel // expected-error {{'#pragma omp cancellation point' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp cancellation point sections // expected-error {{'#pragma omp cancellation point' cannot be an immediate substatement}}
+#pragma omp cancellation point sections
switch (argc)
case 1: {
#pragma omp cancellation point for
@@ -61,7 +61,7 @@ int main(int argc, char **argv) {
switch (argc) {
#pragma omp cancellation point taskgroup
case 1:
-#pragma omp cancellation point parallel // expected-error {{'#pragma omp cancellation point' cannot be an immediate substatement}}
+#pragma omp cancellation point parallel
break;
default: {
#pragma omp cancellation point sections
diff --git a/test/OpenMP/flush_messages.cpp b/test/OpenMP/flush_messages.cpp
index 2f87a2938476..1c086a3f3fa4 100644
--- a/test/OpenMP/flush_messages.cpp
+++ b/test/OpenMP/flush_messages.cpp
@@ -31,7 +31,7 @@ T tmain(T argc) {
#pragma omp flush // expected-error {{'#pragma omp flush' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp flush // expected-error {{'#pragma omp flush' cannot be an immediate substatement}}
+#pragma omp flush
switch (argc)
case 1: {
#pragma omp flush
@@ -39,7 +39,7 @@ T tmain(T argc) {
switch (argc) {
#pragma omp flush
case 1:
-#pragma omp flush // expected-error {{'#pragma omp flush' cannot be an immediate substatement}}
+#pragma omp flush
break;
default: {
#pragma omp flush
@@ -95,7 +95,7 @@ int main(int argc, char **argv) {
#pragma omp flush // expected-error {{'#pragma omp flush' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp flush // expected-error {{'#pragma omp flush' cannot be an immediate substatement}}
+#pragma omp flush
switch (argc)
case 1: {
#pragma omp flush
@@ -103,7 +103,7 @@ int main(int argc, char **argv) {
switch (argc) {
#pragma omp flush
case 1:
-#pragma omp flush // expected-error {{'#pragma omp flush' cannot be an immediate substatement}}
+#pragma omp flush
break;
default: {
#pragma omp flush
diff --git a/test/OpenMP/target_codegen_registration.cpp b/test/OpenMP/target_codegen_registration.cpp
index 0c9bba6df8bd..7d515bb64d90 100644
--- a/test/OpenMP/target_codegen_registration.cpp
+++ b/test/OpenMP/target_codegen_registration.cpp
@@ -407,31 +407,31 @@ int bar(int a){
// Check metadata is properly generated:
// CHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
-// CHECK-DAG = !{i32 0, i32 [[DEVID:[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 160, i32 13, i32 {{[0-9]}}+}
-// CHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2SDD2Ev", i32 210, i32 13, i32 {{[0-9]}}+}
-// CHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2SEC2Ev", i32 226, i32 13, i32 {{[0-9]}}+}
-// CHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2SED2Ev", i32 232, i32 13, i32 {{[0-9]}}+}
-// CHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2STILi1000EE3fooEv", i32 243, i32 13, i32 {{[0-9]}}+}
-// CHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2STILi100EEC2Ev", i32 249, i32 13, i32 {{[0-9]}}+}
-// CHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_Z3bari", i32 352, i32 11, i32 {{[0-9]}}+}
-// CHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2STILi100EED2Ev", i32 255, i32 13, i32 {{[0-9]}}+}
-// CHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2STILi1000EEC2Ev", i32 249, i32 13, i32 {{[0-9]}}+}
-// CHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2STILi1000EED2Ev", i32 255, i32 13, i32 {{[0-9]}}+}
-// CHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2STILi100EE3fooEv", i32 243, i32 13, i32 {{[0-9]}}+}
-// CHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2SCC2Ev", i32 185, i32 13, i32 {{[0-9]}}+}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID:-?[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 193, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SDD1Ev", i32 243, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SEC1Ev", i32 259, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SED1Ev", i32 265, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EE3fooEv", i32 276, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EEC1Ev", i32 282, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_Z3bari", i32 402, i32 11, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EED1Ev", i32 288, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EEC1Ev", i32 282, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EED1Ev", i32 288, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EE3fooEv", i32 276, i32 13, i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SCC1Ev", i32 218, i32 13, i32 {{[0-9]+}}}
// TCHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
-// TCHECK-DAG = !{i32 0, i32 [[DEVID:[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 160, i32 13, i32 {{[0-9]}}+}
-// TCHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2SDD2Ev", i32 210, i32 13, i32 {{[0-9]}}+}
-// TCHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2SEC2Ev", i32 226, i32 13, i32 {{[0-9]}}+}
-// TCHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2SED2Ev", i32 232, i32 13, i32 {{[0-9]}}+}
-// TCHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2STILi1000EE3fooEv", i32 243, i32 13, i32 {{[0-9]}}+}
-// TCHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2STILi100EEC2Ev", i32 249, i32 13, i32 {{[0-9]}}+}
-// TCHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_Z3bari", i32 352, i32 11, i32 {{[0-9]}}+}
-// TCHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2STILi100EED2Ev", i32 255, i32 13, i32 {{[0-9]}}+}
-// TCHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2STILi1000EEC2Ev", i32 249, i32 13, i32 {{[0-9]}}+}
-// TCHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2STILi1000EED2Ev", i32 255, i32 13, i32 {{[0-9]}}+}
-// TCHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2STILi100EE3fooEv", i32 243, i32 13, i32 {{[0-9]}}+}
-// TCHECK-DAG = !{i32 0, i32 [[DEVID]], i32 [[FILEID]] !"_ZN2SCC2Ev", i32 185, i32 13, i32 {{[0-9]}}+}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID:-?[0-9]+]], i32 [[FILEID:-?[0-9]+]], !"_ZN2SB3fooEv", i32 193, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SDD1Ev", i32 243, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SEC1Ev", i32 259, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SED1Ev", i32 265, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EE3fooEv", i32 276, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EEC1Ev", i32 282, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_Z3bari", i32 402, i32 11, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EED1Ev", i32 288, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EEC1Ev", i32 282, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi1000EED1Ev", i32 288, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2STILi100EE3fooEv", i32 276, i32 13, i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 [[DEVID]], i32 [[FILEID]], !"_ZN2SCC1Ev", i32 218, i32 13, i32 {{[0-9]+}}}
#endif
diff --git a/test/OpenMP/target_codegen_registration_naming.cpp b/test/OpenMP/target_codegen_registration_naming.cpp
index 6ab9bf1aa94e..ab7a469aba4d 100644
--- a/test/OpenMP/target_codegen_registration_naming.cpp
+++ b/test/OpenMP/target_codegen_registration_naming.cpp
@@ -57,10 +57,10 @@ int nested(int a){
// Check metadata is properly generated:
// CHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}}
-// CHECK-DAG: = !{i32 0, i32 {{[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T1L]], i32 [[T1C]], i32 {{[0-9]+}}}
-// CHECK-DAG: = !{i32 0, i32 {{[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T2L]], i32 [[T2C]], i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T1L]], i32 [[T1C]], i32 {{[0-9]+}}}
+// CHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T2L]], i32 [[T2C]], i32 {{[0-9]+}}}
// TCHECK: !omp_offload.info = !{!{{[0-9]+}}, !{{[0-9]+}}}
-// TCHECK-DAG: = !{i32 0, i32 {{[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T1L]], i32 [[T1C]], i32 {{[0-9]+}}}
-// TCHECK-DAG: = !{i32 0, i32 {{[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T2L]], i32 [[T2C]], i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T1L]], i32 [[T1C]], i32 {{[0-9]+}}}
+// TCHECK-DAG: = !{i32 0, i32 {{-?[0-9]+}}, i32 {{-?[0-9]+}}, !"[[NNAME]]", i32 [[T2L]], i32 [[T2C]], i32 {{[0-9]+}}}
#endif
diff --git a/test/OpenMP/taskwait_messages.cpp b/test/OpenMP/taskwait_messages.cpp
index 084051354045..06e8e6b8bdf2 100644
--- a/test/OpenMP/taskwait_messages.cpp
+++ b/test/OpenMP/taskwait_messages.cpp
@@ -27,7 +27,7 @@ T tmain(T argc) {
#pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be an immediate substatement}}
+#pragma omp taskwait
switch (argc)
case 1: {
#pragma omp taskwait
@@ -35,7 +35,7 @@ T tmain(T argc) {
switch (argc) {
#pragma omp taskwait
case 1:
-#pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be an immediate substatement}}
+#pragma omp taskwait
break;
default: {
#pragma omp taskwait
@@ -81,7 +81,7 @@ int main(int argc, char **argv) {
#pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be an immediate substatement}}
+#pragma omp taskwait
switch (argc)
case 1: {
#pragma omp taskwait
@@ -89,7 +89,7 @@ int main(int argc, char **argv) {
switch (argc) {
#pragma omp taskwait
case 1:
-#pragma omp taskwait // expected-error {{'#pragma omp taskwait' cannot be an immediate substatement}}
+#pragma omp taskwait
break;
default: {
#pragma omp taskwait
diff --git a/test/OpenMP/taskyield_messages.cpp b/test/OpenMP/taskyield_messages.cpp
index 23c0b5339012..cfeaa63815b3 100644
--- a/test/OpenMP/taskyield_messages.cpp
+++ b/test/OpenMP/taskyield_messages.cpp
@@ -27,7 +27,7 @@ T tmain(T argc) {
#pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be an immediate substatement}}
+#pragma omp taskyield
switch (argc)
case 1: {
#pragma omp taskyield
@@ -35,7 +35,7 @@ T tmain(T argc) {
switch (argc) {
#pragma omp taskyield
case 1:
-#pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be an immediate substatement}}
+#pragma omp taskyield
break;
default: {
#pragma omp taskyield
@@ -81,7 +81,7 @@ int main(int argc, char **argv) {
#pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be an immediate substatement}}
switch (argc)
case 1:
-#pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be an immediate substatement}}
+#pragma omp taskyield
switch (argc)
case 1: {
#pragma omp taskyield
@@ -89,7 +89,7 @@ int main(int argc, char **argv) {
switch (argc) {
#pragma omp taskyield
case 1:
-#pragma omp taskyield // expected-error {{'#pragma omp taskyield' cannot be an immediate substatement}}
+#pragma omp taskyield
break;
default: {
#pragma omp taskyield
diff --git a/test/OpenMP/threadprivate_messages.cpp b/test/OpenMP/threadprivate_messages.cpp
index f71d58bc52a4..8c442f47ad5e 100644
--- a/test/OpenMP/threadprivate_messages.cpp
+++ b/test/OpenMP/threadprivate_messages.cpp
@@ -118,6 +118,7 @@ int main(int argc, char **argv) { // expected-note {{'argc' defined here}}
static double d1;
static double d2;
static double d3; // expected-note {{'d3' defined here}}
+ static double d4;
static TestClass LocalClass(y); // expected-error {{variable with local storage in initial value of threadprivate variable}}
#pragma omp threadprivate(LocalClass)
@@ -133,6 +134,8 @@ int main(int argc, char **argv) { // expected-note {{'argc' defined here}}
#pragma omp threadprivate(d3) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'd3' variable declaration}}
}
#pragma omp threadprivate(d3)
+label:
+#pragma omp threadprivate(d4) // expected-error {{'#pragma omp threadprivate' cannot be an immediate substatement}}
#pragma omp threadprivate(a) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'a' variable declaration}}
return (y);
diff --git a/test/PCH/chain-default-argument-instantiation.cpp b/test/PCH/chain-default-argument-instantiation.cpp
new file mode 100644
index 000000000000..0accd544a384
--- /dev/null
+++ b/test/PCH/chain-default-argument-instantiation.cpp
@@ -0,0 +1,50 @@
+// Test default argument instantiation in chained PCH.
+
+// Without PCH
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -include %s -include %s %s
+
+// With PCH
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -chain-include %s -chain-include %s
+
+// With modules
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fmodules %s -chain-include %s -chain-include %s
+
+// expected-no-diagnostics
+
+#ifndef HEADER1
+#define HEADER1
+//===----------------------------------------------------------------------===//
+// Primary header.
+
+namespace rdar23810407 {
+ template<typename T> int f(T t) {
+ extern T rdar23810407_variable;
+ return 0;
+ }
+ template<typename T> int g(int a = f([] {}));
+}
+
+//===----------------------------------------------------------------------===//
+#elif not defined(HEADER2)
+#define HEADER2
+#if !defined(HEADER1)
+#error Header inclusion order messed up
+#endif
+
+//===----------------------------------------------------------------------===//
+// Dependent header.
+
+inline void instantiate_once() {
+ rdar23810407::g<int>();
+}
+
+//===----------------------------------------------------------------------===//
+#else
+//===----------------------------------------------------------------------===//
+
+void test() {
+ rdar23810407::g<int>();
+}
+
+//===----------------------------------------------------------------------===//
+#endif
diff --git a/test/PCH/cxx-char-literal.cpp b/test/PCH/cxx-char-literal.cpp
new file mode 100644
index 000000000000..0990517c55be
--- /dev/null
+++ b/test/PCH/cxx-char-literal.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -emit-pch -std=c++1z -o %t %s
+// RUN: %clang_cc1 -std=c++1z -x ast -ast-print %t | FileCheck %s
+
+// Ensure that character literals are properly surfaced through PCH.
+
+char a = '0';
+// CHECK: char a = '0';
+
+char b = L'1';
+// CHECK: char b = L'1';
+
+char c = u8'2';
+// CHECK: char c = u8'2';
+
+char d = U'3';
+// CHECK: char d = U'3';
+
+char e = u'4';
+// CHECK: char e = u'4';
diff --git a/test/PCH/ocl_types.cl b/test/PCH/ocl_types.cl
index d788a3262143..21097c481182 100644
--- a/test/PCH/ocl_types.cl
+++ b/test/PCH/ocl_types.cl
@@ -1,9 +1,9 @@
// Test this without pch.
-// RUN: %clang_cc1 -include %S/ocl_types.h -fsyntax-only %s
+// RUN: %clang_cc1 -include %S/ocl_types.h -fsyntax-only %s -cl-std=CL2.0 -D__OPENCL_VERSION__=200
// Test with pch.
-// RUN: %clang_cc1 -x cl -emit-pch -o %t %S/ocl_types.h
-// RUN: %clang_cc1 -include-pch %t -fsyntax-only %s -ast-print
+// RUN: %clang_cc1 -x cl -emit-pch -o %t %S/ocl_types.h -cl-std=CL2.0 -D__OPENCL_VERSION__=200
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only %s -ast-print -cl-std=CL2.0 -D__OPENCL_VERSION__=200
void foo1(img1d_t img);
@@ -24,3 +24,15 @@ void foo7(smp_t smp) {
void foo8(evt_t evt) {
evt_t loc_evt;
}
+
+#if __OPENCL_VERSION__ >= 200
+
+void foo9(pipe int P) {
+ int_pipe_function(P);
+}
+
+void foo10(pipe Person P) {
+ person_pipe_function(P);
+}
+
+#endif
diff --git a/test/PCH/ocl_types.h b/test/PCH/ocl_types.h
index 93cf4f66442b..bdc4bb11c1b2 100644
--- a/test/PCH/ocl_types.h
+++ b/test/PCH/ocl_types.h
@@ -44,6 +44,7 @@ typedef image2d_depth_t img2ddep_t;
// image2d_array_depth_t
typedef image2d_array_depth_t img2darr_dep_t;
+#pragma OPENCL EXTENSION cl_khr_gl_msaa_sharing : enable
// image2d_msaa_t
typedef image2d_msaa_t img2dmsaa_t;
@@ -56,4 +57,14 @@ typedef image2d_msaa_depth_t img2dmsaadep_t;
// image2d_array_msaa_depth_t
typedef image2d_array_msaa_depth_t img2darrmsaadep_t;
+// pipe specifier
+
+typedef struct _person {
+ int id;
+ const char *name;
+} Person;
+
+void int_pipe_function(pipe int);
+
+void person_pipe_function(pipe Person);
#endif
diff --git a/test/Sema/bitfield-layout.c b/test/Sema/bitfield-layout.c
index 2abd139d238f..b96b38686417 100644
--- a/test/Sema/bitfield-layout.c
+++ b/test/Sema/bitfield-layout.c
@@ -1,13 +1,25 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=i686-apple-darwin9
+// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=arm-linux-gnueabihf
+// RUN: %clang_cc1 %s -fsyntax-only -verify -triple=aarch64-linux-gnu
// expected-no-diagnostics
+#include <stddef.h>
-#define CHECK_SIZE(kind, name, size) extern int name##1[sizeof(kind name) == size ? 1 : -1];
-#define CHECK_ALIGN(kind, name, size) extern int name##2[__alignof(kind name) == size ? 1 : -1];
+#define CHECK_SIZE(kind, name, size) \
+ extern int name##_1[sizeof(kind name) == size ? 1 : -1];
+#define CHECK_ALIGN(kind, name, size) \
+ extern int name##_2[__alignof(kind name) == size ? 1 : -1];
+#define CHECK_OFFSET(kind, name, member, offset) \
+ extern int name##_3[offsetof(kind name, member) == offset ? 1 : -1];
// Zero-width bit-fields
struct a {char x; int : 0; char y;};
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(struct, a, 8)
+CHECK_ALIGN(struct, a, 4)
+#else
CHECK_SIZE(struct, a, 5)
CHECK_ALIGN(struct, a, 1)
+#endif
// Zero-width bit-fields with packed
struct __attribute__((packed)) a2 { short x : 9; char : 0; int y : 17; };
@@ -16,8 +28,13 @@ CHECK_ALIGN(struct, a2, 1)
// Zero-width bit-fields at the end of packed struct
struct __attribute__((packed)) a3 { short x : 9; int : 0; };
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(struct, a3, 4)
+CHECK_ALIGN(struct, a3, 4)
+#else
CHECK_SIZE(struct, a3, 4)
CHECK_ALIGN(struct, a3, 1)
+#endif
// For comparison, non-zero-width bit-fields at the end of packed struct
struct __attribute__((packed)) a4 { short x : 9; int : 1; };
@@ -25,17 +42,32 @@ CHECK_SIZE(struct, a4, 2)
CHECK_ALIGN(struct, a4, 1)
union b {char x; int : 0; char y;};
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(union, b, 4)
+CHECK_ALIGN(union, b, 4)
+#else
CHECK_SIZE(union, b, 1)
CHECK_ALIGN(union, b, 1)
+#endif
// Unnamed bit-field align
struct c {char x; int : 20;};
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(struct, c, 4)
+CHECK_ALIGN(struct, c, 4)
+#else
CHECK_SIZE(struct, c, 4)
CHECK_ALIGN(struct, c, 1)
+#endif
union d {char x; int : 20;};
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(union, d, 4)
+CHECK_ALIGN(union, d, 4)
+#else
CHECK_SIZE(union, d, 3)
CHECK_ALIGN(union, d, 1)
+#endif
// Bit-field packing
struct __attribute__((packed)) e {int x : 4, y : 30, z : 30;};
@@ -56,3 +88,153 @@ struct s0 {
CHECK_SIZE(struct, s0, 0x32100008)
CHECK_ALIGN(struct, s0, 4)
+// Bit-field with explicit align bigger than normal.
+struct g0 {
+ char a;
+ __attribute__((aligned(16))) int b : 1;
+ char c;
+};
+
+CHECK_SIZE(struct, g0, 32);
+CHECK_ALIGN(struct, g0, 16);
+CHECK_OFFSET(struct, g0, c, 17);
+
+// Bit-field with explicit align smaller than normal.
+struct g1 {
+ char a;
+ __attribute__((aligned(2))) int b : 1;
+ char c;
+};
+
+CHECK_SIZE(struct, g1, 4);
+CHECK_ALIGN(struct, g1, 4);
+CHECK_OFFSET(struct, g1, c, 3);
+
+// Same as above but without explicit align.
+struct g2 {
+ char a;
+ int b : 1;
+ char c;
+};
+
+CHECK_SIZE(struct, g2, 4);
+CHECK_ALIGN(struct, g2, 4);
+CHECK_OFFSET(struct, g2, c, 2);
+
+// Explicit attribute align on bit-field has precedence over packed attribute
+// applied too the struct.
+struct __attribute__((packed)) g3 {
+ char a;
+ __attribute__((aligned(16))) int b : 1;
+ char c;
+};
+
+CHECK_SIZE(struct, g3, 32);
+CHECK_ALIGN(struct, g3, 16);
+CHECK_OFFSET(struct, g3, c, 17);
+
+struct __attribute__((packed)) g4 {
+ char a;
+ __attribute__((aligned(2))) int b : 1;
+ char c;
+};
+
+CHECK_SIZE(struct, g4, 4);
+CHECK_ALIGN(struct, g4, 2);
+CHECK_OFFSET(struct, g4, c, 3);
+
+struct g5 {
+ char : 1;
+ __attribute__((aligned(1))) int n : 24;
+};
+CHECK_SIZE(struct, g5, 4);
+CHECK_ALIGN(struct, g5, 4);
+
+struct __attribute__((packed)) g6 {
+ char : 1;
+ __attribute__((aligned(1))) int n : 24;
+};
+CHECK_SIZE(struct, g6, 4);
+CHECK_ALIGN(struct, g6, 1);
+
+struct g7 {
+ char : 1;
+ __attribute__((aligned(1))) int n : 25;
+};
+CHECK_SIZE(struct, g7, 8);
+CHECK_ALIGN(struct, g7, 4);
+
+struct __attribute__((packed)) g8 {
+ char : 1;
+ __attribute__((aligned(1))) int n : 25;
+};
+CHECK_SIZE(struct, g8, 5);
+CHECK_ALIGN(struct, g8, 1);
+
+struct g9 {
+ __attribute__((aligned(1))) char a : 2, b : 2, c : 2, d : 2, e : 2;
+ int i;
+};
+CHECK_SIZE(struct, g9, 12);
+CHECK_ALIGN(struct, g9, 4);
+
+struct __attribute__((packed)) g10 {
+ __attribute__((aligned(1))) char a : 2, b : 2, c : 2, d : 2, e : 2;
+ int i;
+};
+CHECK_SIZE(struct, g10, 9);
+CHECK_ALIGN(struct, g10, 1);
+
+struct g11 {
+ char a;
+ __attribute__((aligned(1))) long long b : 62;
+ char c;
+};
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(struct, g11, 24);
+CHECK_ALIGN(struct, g11, 8);
+CHECK_OFFSET(struct, g11, c, 16);
+#else
+CHECK_SIZE(struct, g11, 16);
+CHECK_ALIGN(struct, g11, 4);
+CHECK_OFFSET(struct, g11, c, 12);
+#endif
+
+struct __attribute__((packed)) g12 {
+ char a;
+ __attribute__((aligned(1))) long long b : 62;
+ char c;
+};
+CHECK_SIZE(struct, g12, 10);
+CHECK_ALIGN(struct, g12, 1);
+CHECK_OFFSET(struct, g12, c, 9);
+
+struct g13 {
+ char a;
+ __attribute__((aligned(1))) long long : 0;
+ char c;
+};
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(struct, g13, 16);
+CHECK_ALIGN(struct, g13, 8);
+CHECK_OFFSET(struct, g13, c, 8);
+#else
+CHECK_SIZE(struct, g13, 5);
+CHECK_ALIGN(struct, g13, 1);
+CHECK_OFFSET(struct, g13, c, 4);
+#endif
+
+struct __attribute__((packed)) g14 {
+ char a;
+ __attribute__((aligned(1))) long long : 0;
+ char c;
+};
+#if defined(__arm__) || defined(__aarch64__)
+CHECK_SIZE(struct, g14, 16);
+CHECK_ALIGN(struct, g14, 8);
+CHECK_OFFSET(struct, g14, c, 8);
+#else
+CHECK_SIZE(struct, g14, 5);
+CHECK_ALIGN(struct, g14, 1);
+CHECK_OFFSET(struct, g14, c, 4);
+#endif
diff --git a/test/Sema/darwin-tls.c b/test/Sema/darwin-tls.c
new file mode 100644
index 000000000000..0fcf096d92ba
--- /dev/null
+++ b/test/Sema/darwin-tls.c
@@ -0,0 +1,17 @@
+// RUN: not %clang_cc1 -fsyntax-only -triple x86_64-apple-macosx10.6 %s 2>&1 | FileCheck %s --check-prefix NO-TLS
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-macosx10.7 %s 2>&1 | FileCheck %s --check-prefix TLS
+// RUN: not %clang_cc1 -fsyntax-only -triple arm64-apple-ios7.1 %s 2>&1 | FileCheck %s --check-prefix NO-TLS
+// RUN: %clang_cc1 -fsyntax-only -triple arm64-apple-ios8.0 %s 2>&1 | FileCheck %s --check-prefix TLS
+// RUN: not %clang_cc1 -fsyntax-only -triple thumbv7s-apple-ios8.3 %s 2>&1 | FileCheck %s --check-prefix NO-TLS
+// RUN: %clang_cc1 -fsyntax-only -triple thumbv7s-apple-ios9.0 %s 2>&1 | FileCheck %s --check-prefix TLS
+// RUN: %clang_cc1 -fsyntax-only -triple armv7-apple-ios9.0 %s 2>&1 | FileCheck %s --check-prefix TLS
+// RUN: not %clang_cc1 -fsyntax-only -triple thumbv7k-apple-watchos1.0 %s 2>&1 | FileCheck %s --check-prefix NO-TLS
+// RUN: %clang_cc1 -fsyntax-only -triple thumbv7k-apple-watchos2.0 %s 2>&1 | FileCheck %s --check-prefix TLS
+
+
+__thread int a;
+
+// NO-TLS: thread-local storage is not supported for the current target
+// TLS-NOT: thread-local storage is not supported for the current target
+
+wibble;
diff --git a/test/Sema/decl-in-prototype.c b/test/Sema/decl-in-prototype.c
index 4f581aa54e53..3b8a3b860371 100644
--- a/test/Sema/decl-in-prototype.c
+++ b/test/Sema/decl-in-prototype.c
@@ -35,3 +35,6 @@ void f6(struct z {int b;} c) { // expected-warning {{declaration of 'struct z' w
void pr19018_1 (enum e19018 { qq } x); // expected-warning{{declaration of 'enum e19018' will not be visible outside of this function}}
enum e19018 qq; //expected-error{{tentative definition has type 'enum e19018' that is never completed}} \
//expected-note{{forward declaration of 'enum e19018'}}
+
+// Only warn once, even if we create two declarations.
+void f(struct q *, struct __attribute__((aligned(4))) q *); // expected-warning {{will not be visible outside}}
diff --git a/test/Sema/integer-overflow.c b/test/Sema/integer-overflow.c
index 44fbcd4c818e..db5c1f4c7118 100644
--- a/test/Sema/integer-overflow.c
+++ b/test/Sema/integer-overflow.c
@@ -145,3 +145,11 @@ uint64_t check_integer_overflows(int i) {
// expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}}
return ((4608 * 1024 * 1024) + ((uint64_t)(4608 * 1024 * 1024)));
}
+
+struct s {
+ unsigned x;
+ unsigned y;
+} s = {
+ .y = 5,
+ .x = 4 * 1024 * 1024 * 1024 // expected-warning {{overflow in expression; result is 0 with type 'int'}}
+};
diff --git a/test/Sema/pass-object-size.c b/test/Sema/pass-object-size.c
index e4f460b1785f..6f375c0e94d5 100644
--- a/test/Sema/pass-object-size.c
+++ b/test/Sema/pass-object-size.c
@@ -33,7 +33,7 @@ void TakeFnOvl(void (*)(int *)) overloaded;
void NotOverloaded(void *p PS(0));
void IsOverloaded(void *p PS(0)) overloaded;
-void IsOverloaded(char *p) overloaded;
+void IsOverloaded(char *p) overloaded; // char* inestead of void* is intentional
void FunctionPtrs() {
void (*p)(void *) = NotOverloaded; //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
void (*p2)(void *) = &NotOverloaded; //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
@@ -49,4 +49,8 @@ void FunctionPtrs() {
TakeFnOvl(NotOverloaded); //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
TakeFnOvl(&NotOverloaded); //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
+
+ int P;
+ (&NotOverloaded)(&P); //expected-error{{cannot take address of function 'NotOverloaded' because parameter 1 has pass_object_size attribute}}
+ (&IsOverloaded)(&P); //expected-error{{no matching function}} expected-note@35{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@36{{candidate function not viable: no known conversion from 'int *' to 'char *' for 1st argument}}
}
diff --git a/test/SemaCUDA/Inputs/cuda.h b/test/SemaCUDA/Inputs/cuda.h
index a9a4595a14a9..18cafdf96af8 100644
--- a/test/SemaCUDA/Inputs/cuda.h
+++ b/test/SemaCUDA/Inputs/cuda.h
@@ -2,6 +2,9 @@
#include <stddef.h>
+// Make this file work with nvcc, for testing compatibility.
+
+#ifndef __NVCC__
#define __constant__ __attribute__((constant))
#define __device__ __attribute__((device))
#define __global__ __attribute__((global))
@@ -18,3 +21,4 @@ typedef struct cudaStream *cudaStream_t;
int cudaConfigureCall(dim3 gridSize, dim3 blockSize, size_t sharedSize = 0,
cudaStream_t stream = 0);
+#endif // !__NVCC__
diff --git a/test/SemaCUDA/attributes.cu b/test/SemaCUDA/attributes-on-non-cuda.cu
index ce4dc925a3f3..e9e32ce658cb 100644
--- a/test/SemaCUDA/attributes.cu
+++ b/test/SemaCUDA/attributes-on-non-cuda.cu
@@ -1,4 +1,5 @@
-// Tests handling of CUDA attributes.
+// Tests that CUDA attributes are warnings when compiling C files, but not when
+// compiling CUDA files.
//
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -fsyntax-only -fcuda-is-device -verify %s
diff --git a/test/SemaCUDA/bad-attributes.cu b/test/SemaCUDA/bad-attributes.cu
new file mode 100644
index 000000000000..7e01e141de1d
--- /dev/null
+++ b/test/SemaCUDA/bad-attributes.cu
@@ -0,0 +1,49 @@
+// Tests handling of CUDA attributes that are bad either because they're
+// applied to the wrong sort of thing, or because they're given in illegal
+// combinations.
+//
+// You should be able to run this file through nvcc for compatibility testing.
+//
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fcuda-is-device -fsyntax-only -verify %s
+
+#include "Inputs/cuda.h"
+
+// Try applying attributes to functions and variables. Some should generate
+// warnings; others not.
+__device__ int a1;
+__device__ void a2();
+__host__ int b1; // expected-warning {{attribute only applies to functions}}
+__host__ void b2();
+__constant__ int c1;
+__constant__ void c2(); // expected-warning {{attribute only applies to variables}}
+__shared__ int d1;
+__shared__ void d2(); // expected-warning {{attribute only applies to variables}}
+__global__ int e1; // expected-warning {{attribute only applies to functions}}
+__global__ void e2();
+
+// Try all pairs of attributes which can be present on a function or a
+// variable. Check both orderings of the attributes, as that can matter in
+// clang.
+__device__ __host__ void z1();
+__device__ __constant__ int z2;
+__device__ __shared__ int z3;
+__device__ __global__ void z4(); // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
+
+__host__ __device__ void z5();
+__host__ __global__ void z6(); // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
+
+__constant__ __device__ int z7;
+__constant__ __shared__ int z8; // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
+
+__shared__ __device__ int z9;
+__shared__ __constant__ int z10; // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
+
+__global__ __device__ void z11(); // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
+__global__ __host__ void z12(); // expected-error {{attributes are not compatible}}
+// expected-note@-1 {{conflicting attribute is here}}
diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp
index 3520245a03a8..0b654266f75f 100644
--- a/test/SemaCXX/anonymous-union.cpp
+++ b/test/SemaCXX/anonymous-union.cpp
@@ -62,11 +62,11 @@ void test_unqual_references(X x, const X xc) {
struct Redecl {
int x; // expected-note{{previous declaration is here}}
- class y { };
+ class y { }; // expected-note{{previous declaration is here}}
union {
int x; // expected-error{{member of anonymous union redeclares 'x'}}
- float y;
+ float y; // expected-error{{member of anonymous union redeclares 'y'}}
double z; // expected-note{{previous declaration is here}}
double zz; // expected-note{{previous definition is here}}
};
diff --git a/test/SemaCXX/conversion.cpp b/test/SemaCXX/conversion.cpp
index b8f0e076a2bc..4c4089c6aae7 100644
--- a/test/SemaCXX/conversion.cpp
+++ b/test/SemaCXX/conversion.cpp
@@ -77,30 +77,8 @@ void test3() {
// CHECK: note: expanded from macro 'FINIT'
#define FINIT int a3 = NULL;
FINIT // expected-warning {{implicit conversion of NULL constant to 'int'}}
-
- // we don't catch the case of #define FOO NULL ... int i = FOO; but that seems a bit narrow anyway
- // and avoiding that helps us skip these cases:
-#define NULL_COND(cond) ((cond) ? &a : NULL)
- bool bl2 = NULL_COND(true); // don't warn on NULL conversion through the conditional operator across a macro boundary
- if (NULL_COND(true))
- ;
- while (NULL_COND(true))
- ;
- for (; NULL_COND(true); )
- ;
- do ;
- while(NULL_COND(true));
-
-#define NULL_WRAPPER NULL_COND(false)
- if (NULL_WRAPPER)
- ;
- while (NULL_WRAPPER)
- ;
- for (; NULL_WRAPPER;)
- ;
- do
- ;
- while (NULL_WRAPPER);
+ // we don't catch the case of #define FOO NULL ... int i = FOO; but that
+ // seems a bit narrow anyway and avoiding that helps us skip other cases.
int *ip = NULL;
int (*fp)() = NULL;
@@ -116,9 +94,9 @@ namespace test4 {
// FIXME: We should warn for non-dependent args (only when the param type is also non-dependent) only once
// not once for the template + once for every instantiation
template<typename T>
- void tmpl(char c = NULL, // expected-warning 4 {{implicit conversion of NULL constant to 'char'}}
+ void tmpl(char c = NULL, // expected-warning 3 {{implicit conversion of NULL constant to 'char'}}
T a = NULL, // expected-warning {{implicit conversion of NULL constant to 'char'}} \
- expected-warning 2 {{implicit conversion of NULL constant to 'int'}}
+ expected-warning {{implicit conversion of NULL constant to 'int'}}
T b = 1024) { // expected-warning {{implicit conversion from 'int' to 'char' changes value from 1024 to 0}}
}
@@ -129,8 +107,7 @@ namespace test4 {
void func() {
tmpl<char>(); // expected-note 2 {{in instantiation of default function argument expression for 'tmpl<char>' required here}}
tmpl<int>(); // expected-note 2 {{in instantiation of default function argument expression for 'tmpl<int>' required here}}
- // FIXME: We should warn only once for each template instantiation - not once for each call
- tmpl<int>(); // expected-note 2 {{in instantiation of default function argument expression for 'tmpl<int>' required here}}
+ tmpl<int>();
tmpl2<int*>();
}
}
@@ -157,3 +134,97 @@ namespace test7 {
return nullptr; // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
}
}
+
+namespace test8 {
+ #define NULL_COND(cond) ((cond) ? &num : NULL)
+ #define NULL_WRAPPER NULL_COND(false)
+
+ // don't warn on NULL conversion through the conditional operator across a
+ // macro boundary
+ void macro() {
+ int num;
+ bool b = NULL_COND(true);
+ if (NULL_COND(true)) {}
+ while (NULL_COND(true)) {}
+ for (;NULL_COND(true);) {}
+ do {} while (NULL_COND(true));
+
+ if (NULL_WRAPPER) {}
+ while (NULL_WRAPPER) {}
+ for (;NULL_WRAPPER;) {}
+ do {} while (NULL_WRAPPER);
+ }
+
+ // Identical to the previous function except with a template argument.
+ // This ensures that template instantiation does not introduce any new
+ // warnings.
+ template <typename X>
+ void template_and_macro() {
+ int num;
+ bool b = NULL_COND(true);
+ if (NULL_COND(true)) {}
+ while (NULL_COND(true)) {}
+ for (;NULL_COND(true);) {}
+ do {} while (NULL_COND(true));
+
+ if (NULL_WRAPPER) {}
+ while (NULL_WRAPPER) {}
+ for (;NULL_WRAPPER;) {}
+ do {} while (NULL_WRAPPER);
+ }
+
+ // Identical to the previous function except the template argument affects
+ // the conditional statement.
+ template <typename X>
+ void template_and_macro2() {
+ X num;
+ bool b = NULL_COND(true);
+ if (NULL_COND(true)) {}
+ while (NULL_COND(true)) {}
+ for (;NULL_COND(true);) {}
+ do {} while (NULL_COND(true));
+
+ if (NULL_WRAPPER) {}
+ while (NULL_WRAPPER) {}
+ for (;NULL_WRAPPER;) {}
+ do {} while (NULL_WRAPPER);
+ }
+
+ void run() {
+ template_and_macro<int>();
+ template_and_macro<double>();
+ template_and_macro2<int>();
+ template_and_macro2<double>();
+ }
+}
+
+// Don't warn on a nullptr to bool conversion when the nullptr is the return
+// type of a function.
+namespace test9 {
+ typedef decltype(nullptr) nullptr_t;
+ nullptr_t EXIT();
+
+ bool test() {
+ return EXIT();
+ }
+}
+
+// Test NULL macro inside a macro has same warnings nullptr inside a macro.
+namespace test10 {
+#define test1(cond) \
+ ((cond) ? nullptr : NULL)
+#define test2(cond) \
+ ((cond) ? NULL : nullptr)
+
+#define assert(cond) \
+ ((cond) ? foo() : bar())
+ void foo();
+ void bar();
+
+ void run(int x) {
+ if (test1(x)) {}
+ if (test2(x)) {}
+ assert(test1(x));
+ assert(test2(x));
+ }
+}
diff --git a/test/SemaCXX/linkage-invalid-decl.cpp b/test/SemaCXX/linkage-invalid-decl.cpp
new file mode 100644
index 000000000000..0a991baf9d7d
--- /dev/null
+++ b/test/SemaCXX/linkage-invalid-decl.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// This invalid declaration used to call infinite recursion in linkage
+// calculation for enum as a function argument.
+inline foo(A)(enum E;
+// expected-error@-1 {{unknown type name 'foo'}}
+// expected-error@-2 {{ISO C++ forbids forward references to 'enum' types}}
+// expected-error@-3 {{expected ')'}}
+// expected-note@-4 {{to match this '('}}
diff --git a/test/SemaCXX/pass-object-size.cpp b/test/SemaCXX/pass-object-size.cpp
index bec0c1c55f29..94c9cc9c8aa0 100644
--- a/test/SemaCXX/pass-object-size.cpp
+++ b/test/SemaCXX/pass-object-size.cpp
@@ -120,3 +120,17 @@ void Bar() {
(void)+[](void *const p __attribute__((pass_object_size(0)))) {}; //expected-error-re{{invalid argument type '(lambda at {{.*}})' to unary expression}}
}
}
+
+namespace ovlbug {
+// Directly calling an address-of function expression (e.g. in (&foo)(args...))
+// doesn't go through regular address-of-overload logic. This caused the above
+// code to generate an ICE.
+void DirectAddrOf(void *__attribute__((pass_object_size(0))));
+void DirectAddrOfOvl(void *__attribute__((pass_object_size(0))));
+void DirectAddrOfOvl(int *);
+
+void Test() {
+ (&DirectAddrOf)(nullptr); //expected-error{{cannot take address of function 'DirectAddrOf' because parameter 1 has pass_object_size attribute}}
+ (&DirectAddrOfOvl)((char*)nullptr); //expected-error{{no matching function}} expected-note@129{{candidate address cannot be taken because parameter 1 has pass_object_size attribute}} expected-note@130{{candidate function not viable: no known conversion from 'char *' to 'int *' for 1st argument}}
+}
+}
diff --git a/test/SemaOpenCL/invalid-pipes-cl2.0.cl b/test/SemaOpenCL/invalid-pipes-cl2.0.cl
new file mode 100644
index 000000000000..ee36892b93d4
--- /dev/null
+++ b/test/SemaOpenCL/invalid-pipes-cl2.0.cl
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL2.0
+
+void test1(pipe int *p){// expected-error {{pipes packet types cannot be of reference type}}
+}
+void test2(pipe p){// expected-error {{missing actual type specifier for pipe}}
+}
+void test3(int pipe p){// expected-error {{cannot combine with previous 'int' declaration specifier}}
+}
diff --git a/test/SemaOpenCL/pipes-1.2-negative.cl b/test/SemaOpenCL/pipes-1.2-negative.cl
new file mode 100644
index 000000000000..441a24cf8522
--- /dev/null
+++ b/test/SemaOpenCL/pipes-1.2-negative.cl
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL1.2
+
+void foo(read_only pipe int p); // expected-error {{expected parameter declarator}} expected-error {{expected ')'}} expected-note {{to match this '('}}
diff --git a/test/SemaTemplate/default-arguments-cxx0x.cpp b/test/SemaTemplate/default-arguments-cxx0x.cpp
index 4cfd7a5843f0..0c97c2056b75 100644
--- a/test/SemaTemplate/default-arguments-cxx0x.cpp
+++ b/test/SemaTemplate/default-arguments-cxx0x.cpp
@@ -56,3 +56,22 @@ namespace PR16975 {
baz data{0};
}
+
+// rdar://23810407
+// An IRGen failure due to a symbol collision due to a default argument
+// being instantiated twice. Credit goes to Richard Smith for this
+// reduction to a -fsyntax-only failure.
+namespace rdar23810407 {
+ // Instantiating the default argument multiple times will produce two
+ // different lambda types and thus instantiate this function multiple
+ // times, which will produce conflicting extern variable declarations.
+ template<typename T> int f(T t) {
+ extern T rdar23810407_variable;
+ return 0;
+ }
+ template<typename T> int g(int a = f([] {}));
+ void test() {
+ g<int>();
+ g<int>();
+ }
+}
diff --git a/test/SemaTemplate/temp_arg_template.cpp b/test/SemaTemplate/temp_arg_template.cpp
index 4a0ed05d8799..6d93f1504a46 100644
--- a/test/SemaTemplate/temp_arg_template.cpp
+++ b/test/SemaTemplate/temp_arg_template.cpp
@@ -75,7 +75,11 @@ template <template <typename> class... Templates>
// expected-warning@-2 {{variadic templates are a C++11 extension}}
#endif
-struct template_tuple {};
+struct template_tuple {
+#if __cplusplus >= 201103L
+ static constexpr int N = sizeof...(Templates);
+#endif
+};
template <typename T>
struct identity {};
template <template <typename> class... Templates>
@@ -85,6 +89,12 @@ template <template <typename> class... Templates>
template_tuple<Templates...> f7() {}
+#if __cplusplus >= 201103L
+struct S : public template_tuple<identity, identity> {
+ static_assert(N == 2, "Number of template arguments incorrect");
+};
+#endif
+
void foo() {
f7<identity>();
}
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index dba676a1f756..510bc44f40cb 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -5,8 +5,6 @@ add_clang_subdirectory(driver)
add_clang_subdirectory(clang-format)
add_clang_subdirectory(clang-format-vs)
add_clang_subdirectory(clang-fuzzer)
-add_clang_subdirectory(scan-build)
-add_clang_subdirectory(scan-view)
add_clang_subdirectory(c-index-test)
add_clang_subdirectory(libclang)
@@ -18,6 +16,8 @@ endif()
if(CLANG_ENABLE_STATIC_ANALYZER)
add_clang_subdirectory(clang-check)
+ add_clang_subdirectory(scan-build)
+ add_clang_subdirectory(scan-view)
endif()
# We support checking out the clang-tools-extra repository into the 'extra'
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 8336491c0158..2a6002537ec5 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -1508,6 +1508,22 @@ static enum CXChildVisitResult PrintBitWidth(CXCursor cursor, CXCursor p,
}
/******************************************************************************/
+/* Type declaration testing */
+/******************************************************************************/
+
+static enum CXChildVisitResult PrintTypeDeclaration(CXCursor cursor, CXCursor p,
+ CXClientData d) {
+ CXCursor typeDeclaration = clang_getTypeDeclaration(clang_getCursorType(cursor));
+
+ if (clang_isDeclaration(typeDeclaration.kind)) {
+ PrintCursor(cursor, NULL);
+ PrintTypeAndTypeKind(clang_getCursorType(typeDeclaration), " [typedeclaration=%s] [typekind=%s]\n");
+ }
+
+ return CXChildVisit_Recurse;
+}
+
+/******************************************************************************/
/* Loading ASTs/source. */
/******************************************************************************/
@@ -4137,6 +4153,7 @@ static void print_usage(void) {
" c-index-test -test-print-type {<args>}*\n"
" c-index-test -test-print-type-size {<args>}*\n"
" c-index-test -test-print-bitwidth {<args>}*\n"
+ " c-index-test -test-print-type-declaration {<args>}*\n"
" c-index-test -print-usr [<CursorKind> {<args>}]*\n"
" c-index-test -print-usr-file <file>\n"
" c-index-test -write-pch <file> <compiler arguments>\n");
@@ -4230,6 +4247,9 @@ int cindextest_main(int argc, const char **argv) {
else if (argc > 2 && strcmp(argv[1], "-test-print-type-size") == 0)
return perform_test_load_source(argc - 2, argv + 2, "all",
PrintTypeSize, 0);
+ else if (argc > 2 && strcmp(argv[1], "-test-print-type-declaration") == 0)
+ return perform_test_load_source(argc - 2, argv + 2, "all",
+ PrintTypeDeclaration, 0);
else if (argc > 2 && strcmp(argv[1], "-test-print-bitwidth") == 0)
return perform_test_load_source(argc - 2, argv + 2, "all",
PrintBitWidth, 0);
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index dbda13c23532..9086c60e18be 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -1686,6 +1686,10 @@ bool CursorVisitor::VisitAtomicTypeLoc(AtomicTypeLoc TL) {
return Visit(TL.getValueLoc());
}
+bool CursorVisitor::VisitPipeTypeLoc(PipeTypeLoc TL) {
+ return Visit(TL.getValueLoc());
+}
+
#define DEFAULT_TYPELOC_IMPL(CLASS, PARENT) \
bool CursorVisitor::Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { \
return Visit##PARENT##Loc(TL); \
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 72c12cd16b97..44bb631f7866 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -412,6 +412,12 @@ try_again:
.getAsTemplateDecl();
break;
+ case Type::Auto:
+ TP = cast<AutoType>(TP)->getDeducedType().getTypePtrOrNull();
+ if (TP)
+ goto try_again;
+ break;
+
case Type::InjectedClassName:
D = cast<InjectedClassNameType>(TP)->getDecl();
break;
diff --git a/tools/scan-build-py/README.md b/tools/scan-build-py/README.md
new file mode 100644
index 000000000000..54bfc37ff76d
--- /dev/null
+++ b/tools/scan-build-py/README.md
@@ -0,0 +1,120 @@
+scan-build
+==========
+
+A package designed to wrap a build so that all calls to gcc/clang are
+intercepted and logged into a [compilation database][1] and/or piped to
+the clang static analyzer. Includes intercept-build tool, which logs
+the build, as well as scan-build tool, which logs the build and runs
+the clang static analyzer on it.
+
+Portability
+-----------
+
+Should be working on UNIX operating systems.
+
+- It has been tested on FreeBSD, GNU/Linux and OS X.
+- Prepared to work on windows, but need help to make it.
+
+
+Prerequisites
+-------------
+
+1. **python** interpreter (version 2.7, 3.2, 3.3, 3.4, 3.5).
+
+
+How to use
+----------
+
+To run the Clang static analyzer against a project goes like this:
+
+ $ scan-build <your build command>
+
+To generate a compilation database file goes like this:
+
+ $ intercept-build <your build command>
+
+To run the Clang static analyzer against a project with compilation database
+goes like this:
+
+ $ analyze-build
+
+Use `--help` to know more about the commands.
+
+
+Limitations
+-----------
+
+Generally speaking, the `intercept-build` and `analyze-build` tools together
+does the same job as `scan-build` does. So, you can expect the same output
+from this line as simple `scan-build` would do:
+
+ $ intercept-build <your build command> && analyze-build
+
+The major difference is how and when the analyzer is run. The `scan-build`
+tool has three distinct model to run the analyzer:
+
+1. Use compiler wrappers to make actions.
+ The compiler wrappers does run the real compiler and the analyzer.
+ This is the default behaviour, can be enforced with `--override-compiler`
+ flag.
+
+2. Use special library to intercept compiler calls durring the build process.
+ The analyzer run against each modules after the build finished.
+ Use `--intercept-first` flag to get this model.
+
+3. Use compiler wrappers to intercept compiler calls durring the build process.
+ The analyzer run against each modules after the build finished.
+ Use `--intercept-first` and `--override-compiler` flags together to get
+ this model.
+
+The 1. and 3. are using compiler wrappers, which works only if the build
+process respects the `CC` and `CXX` environment variables. (Some build
+process can override these variable as command line parameter only. This case
+you need to pass the compiler wrappers manually. eg.: `intercept-build
+--override-compiler make CC=intercept-cc CXX=intercept-c++ all` where the
+original build command would have been `make all` only.)
+
+The 1. runs the analyzer right after the real compilation. So, if the build
+process removes removes intermediate modules (generated sources) the analyzer
+output still kept.
+
+The 2. and 3. generate the compilation database first, and filters out those
+modules which are not exists. So, it's suitable for incremental analysis durring
+the development.
+
+The 2. mode is available only on FreeBSD and Linux. Where library preload
+is available from the dynamic loader. Not supported on OS X (unless System
+Integrity Protection feature is turned off).
+
+`intercept-build` command uses only the 2. and 3. mode to generate the
+compilation database. `analyze-build` does only run the analyzer against the
+captured compiler calls.
+
+
+Known problems
+--------------
+
+Because it uses `LD_PRELOAD` or `DYLD_INSERT_LIBRARIES` environment variables,
+it does not append to it, but overrides it. So builds which are using these
+variables might not work. (I don't know any build tool which does that, but
+please let me know if you do.)
+
+
+Problem reports
+---------------
+
+If you find a bug in this documentation or elsewhere in the program or would
+like to propose an improvement, please use the project's [issue tracker][3].
+Please describing the bug and where you found it. If you have a suggestion
+how to fix it, include that as well. Patches are also welcome.
+
+
+License
+-------
+
+The project is licensed under University of Illinois/NCSA Open Source License.
+See LICENSE.TXT for details.
+
+ [1]: http://clang.llvm.org/docs/JSONCompilationDatabase.html
+ [2]: https://pypi.python.org/pypi/scan-build
+ [3]: https://llvm.org/bugs/enter_bug.cgi?product=clang
diff --git a/tools/scan-build-py/bin/analyze-build b/tools/scan-build-py/bin/analyze-build
new file mode 100644
index 000000000000..2cc9676fd546
--- /dev/null
+++ b/tools/scan-build-py/bin/analyze-build
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import multiprocessing
+multiprocessing.freeze_support()
+
+import sys
+import os.path
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.dirname(this_dir))
+
+from libscanbuild.analyze import analyze_build_main
+sys.exit(analyze_build_main(this_dir, False))
diff --git a/tools/scan-build-py/bin/analyze-c++ b/tools/scan-build-py/bin/analyze-c++
new file mode 100644
index 000000000000..15186d89aa3f
--- /dev/null
+++ b/tools/scan-build-py/bin/analyze-c++
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import sys
+import os.path
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.dirname(this_dir))
+
+from libscanbuild.analyze import analyze_build_wrapper
+sys.exit(analyze_build_wrapper(True))
diff --git a/tools/scan-build-py/bin/analyze-cc b/tools/scan-build-py/bin/analyze-cc
new file mode 100644
index 000000000000..55519fb7b11d
--- /dev/null
+++ b/tools/scan-build-py/bin/analyze-cc
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import sys
+import os.path
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.dirname(this_dir))
+
+from libscanbuild.analyze import analyze_build_wrapper
+sys.exit(analyze_build_wrapper(False))
diff --git a/tools/scan-build-py/bin/intercept-build b/tools/scan-build-py/bin/intercept-build
new file mode 100644
index 000000000000..164f2e68be93
--- /dev/null
+++ b/tools/scan-build-py/bin/intercept-build
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import multiprocessing
+multiprocessing.freeze_support()
+
+import sys
+import os.path
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.dirname(this_dir))
+
+from libscanbuild.intercept import intercept_build_main
+sys.exit(intercept_build_main(this_dir))
diff --git a/tools/scan-build-py/bin/intercept-c++ b/tools/scan-build-py/bin/intercept-c++
new file mode 100644
index 000000000000..fc422287f84b
--- /dev/null
+++ b/tools/scan-build-py/bin/intercept-c++
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import sys
+import os.path
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.dirname(this_dir))
+
+from libscanbuild.intercept import intercept_build_wrapper
+sys.exit(intercept_build_wrapper(True))
diff --git a/tools/scan-build-py/bin/intercept-cc b/tools/scan-build-py/bin/intercept-cc
new file mode 100644
index 000000000000..69d57aaae107
--- /dev/null
+++ b/tools/scan-build-py/bin/intercept-cc
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import sys
+import os.path
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.dirname(this_dir))
+
+from libscanbuild.intercept import intercept_build_wrapper
+sys.exit(intercept_build_wrapper(False))
diff --git a/tools/scan-build-py/bin/scan-build b/tools/scan-build-py/bin/scan-build
new file mode 100644
index 000000000000..601fe89fc30d
--- /dev/null
+++ b/tools/scan-build-py/bin/scan-build
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import multiprocessing
+multiprocessing.freeze_support()
+
+import sys
+import os.path
+this_dir = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.dirname(this_dir))
+
+from libscanbuild.analyze import analyze_build_main
+sys.exit(analyze_build_main(this_dir, True))
diff --git a/tools/scan-build-py/libear/__init__.py b/tools/scan-build-py/libear/__init__.py
new file mode 100644
index 000000000000..3e1c13cf2bfe
--- /dev/null
+++ b/tools/scan-build-py/libear/__init__.py
@@ -0,0 +1,260 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module compiles the intercept library. """
+
+import sys
+import os
+import os.path
+import re
+import tempfile
+import shutil
+import contextlib
+import logging
+
+__all__ = ['build_libear']
+
+
+def build_libear(compiler, dst_dir):
+ """ Returns the full path to the 'libear' library. """
+
+ try:
+ src_dir = os.path.dirname(os.path.realpath(__file__))
+ toolset = make_toolset(src_dir)
+ toolset.set_compiler(compiler)
+ toolset.set_language_standard('c99')
+ toolset.add_definitions(['-D_GNU_SOURCE'])
+
+ configure = do_configure(toolset)
+ configure.check_function_exists('execve', 'HAVE_EXECVE')
+ configure.check_function_exists('execv', 'HAVE_EXECV')
+ configure.check_function_exists('execvpe', 'HAVE_EXECVPE')
+ configure.check_function_exists('execvp', 'HAVE_EXECVP')
+ configure.check_function_exists('execvP', 'HAVE_EXECVP2')
+ configure.check_function_exists('exect', 'HAVE_EXECT')
+ configure.check_function_exists('execl', 'HAVE_EXECL')
+ configure.check_function_exists('execlp', 'HAVE_EXECLP')
+ configure.check_function_exists('execle', 'HAVE_EXECLE')
+ configure.check_function_exists('posix_spawn', 'HAVE_POSIX_SPAWN')
+ configure.check_function_exists('posix_spawnp', 'HAVE_POSIX_SPAWNP')
+ configure.check_symbol_exists('_NSGetEnviron', 'crt_externs.h',
+ 'HAVE_NSGETENVIRON')
+ configure.write_by_template(
+ os.path.join(src_dir, 'config.h.in'),
+ os.path.join(dst_dir, 'config.h'))
+
+ target = create_shared_library('ear', toolset)
+ target.add_include(dst_dir)
+ target.add_sources('ear.c')
+ target.link_against(toolset.dl_libraries())
+ target.link_against(['pthread'])
+ target.build_release(dst_dir)
+
+ return os.path.join(dst_dir, target.name)
+
+ except Exception:
+ logging.info("Could not build interception library.", exc_info=True)
+ return None
+
+
+def execute(cmd, *args, **kwargs):
+ """ Make subprocess execution silent. """
+
+ import subprocess
+ kwargs.update({'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT})
+ return subprocess.check_call(cmd, *args, **kwargs)
+
+
+@contextlib.contextmanager
+def TemporaryDirectory(**kwargs):
+ name = tempfile.mkdtemp(**kwargs)
+ try:
+ yield name
+ finally:
+ shutil.rmtree(name)
+
+
+class Toolset(object):
+ """ Abstract class to represent different toolset. """
+
+ def __init__(self, src_dir):
+ self.src_dir = src_dir
+ self.compiler = None
+ self.c_flags = []
+
+ def set_compiler(self, compiler):
+ """ part of public interface """
+ self.compiler = compiler
+
+ def set_language_standard(self, standard):
+ """ part of public interface """
+ self.c_flags.append('-std=' + standard)
+
+ def add_definitions(self, defines):
+ """ part of public interface """
+ self.c_flags.extend(defines)
+
+ def dl_libraries(self):
+ raise NotImplementedError()
+
+ def shared_library_name(self, name):
+ raise NotImplementedError()
+
+ def shared_library_c_flags(self, release):
+ extra = ['-DNDEBUG', '-O3'] if release else []
+ return extra + ['-fPIC'] + self.c_flags
+
+ def shared_library_ld_flags(self, release, name):
+ raise NotImplementedError()
+
+
+class DarwinToolset(Toolset):
+ def __init__(self, src_dir):
+ Toolset.__init__(self, src_dir)
+
+ def dl_libraries(self):
+ return []
+
+ def shared_library_name(self, name):
+ return 'lib' + name + '.dylib'
+
+ def shared_library_ld_flags(self, release, name):
+ extra = ['-dead_strip'] if release else []
+ return extra + ['-dynamiclib', '-install_name', '@rpath/' + name]
+
+
+class UnixToolset(Toolset):
+ def __init__(self, src_dir):
+ Toolset.__init__(self, src_dir)
+
+ def dl_libraries(self):
+ return []
+
+ def shared_library_name(self, name):
+ return 'lib' + name + '.so'
+
+ def shared_library_ld_flags(self, release, name):
+ extra = [] if release else []
+ return extra + ['-shared', '-Wl,-soname,' + name]
+
+
+class LinuxToolset(UnixToolset):
+ def __init__(self, src_dir):
+ UnixToolset.__init__(self, src_dir)
+
+ def dl_libraries(self):
+ return ['dl']
+
+
+def make_toolset(src_dir):
+ platform = sys.platform
+ if platform in {'win32', 'cygwin'}:
+ raise RuntimeError('not implemented on this platform')
+ elif platform == 'darwin':
+ return DarwinToolset(src_dir)
+ elif platform in {'linux', 'linux2'}:
+ return LinuxToolset(src_dir)
+ else:
+ return UnixToolset(src_dir)
+
+
+class Configure(object):
+ def __init__(self, toolset):
+ self.ctx = toolset
+ self.results = {'APPLE': sys.platform == 'darwin'}
+
+ def _try_to_compile_and_link(self, source):
+ try:
+ with TemporaryDirectory() as work_dir:
+ src_file = 'check.c'
+ with open(os.path.join(work_dir, src_file), 'w') as handle:
+ handle.write(source)
+
+ execute([self.ctx.compiler, src_file] + self.ctx.c_flags,
+ cwd=work_dir)
+ return True
+ except Exception:
+ return False
+
+ def check_function_exists(self, function, name):
+ template = "int FUNCTION(); int main() { return FUNCTION(); }"
+ source = template.replace("FUNCTION", function)
+
+ logging.debug('Checking function %s', function)
+ found = self._try_to_compile_and_link(source)
+ logging.debug('Checking function %s -- %s', function,
+ 'found' if found else 'not found')
+ self.results.update({name: found})
+
+ def check_symbol_exists(self, symbol, include, name):
+ template = """#include <INCLUDE>
+ int main() { return ((int*)(&SYMBOL))[0]; }"""
+ source = template.replace('INCLUDE', include).replace("SYMBOL", symbol)
+
+ logging.debug('Checking symbol %s', symbol)
+ found = self._try_to_compile_and_link(source)
+ logging.debug('Checking symbol %s -- %s', symbol,
+ 'found' if found else 'not found')
+ self.results.update({name: found})
+
+ def write_by_template(self, template, output):
+ def transform(line, definitions):
+
+ pattern = re.compile(r'^#cmakedefine\s+(\S+)')
+ m = pattern.match(line)
+ if m:
+ key = m.group(1)
+ if key not in definitions or not definitions[key]:
+ return '/* #undef {} */\n'.format(key)
+ else:
+ return '#define {}\n'.format(key)
+ return line
+
+ with open(template, 'r') as src_handle:
+ logging.debug('Writing config to %s', output)
+ with open(output, 'w') as dst_handle:
+ for line in src_handle:
+ dst_handle.write(transform(line, self.results))
+
+
+def do_configure(toolset):
+ return Configure(toolset)
+
+
+class SharedLibrary(object):
+ def __init__(self, name, toolset):
+ self.name = toolset.shared_library_name(name)
+ self.ctx = toolset
+ self.inc = []
+ self.src = []
+ self.lib = []
+
+ def add_include(self, directory):
+ self.inc.extend(['-I', directory])
+
+ def add_sources(self, source):
+ self.src.append(source)
+
+ def link_against(self, libraries):
+ self.lib.extend(['-l' + lib for lib in libraries])
+
+ def build_release(self, directory):
+ for src in self.src:
+ logging.debug('Compiling %s', src)
+ execute(
+ [self.ctx.compiler, '-c', os.path.join(self.ctx.src_dir, src),
+ '-o', src + '.o'] + self.inc +
+ self.ctx.shared_library_c_flags(True),
+ cwd=directory)
+ logging.debug('Linking %s', self.name)
+ execute(
+ [self.ctx.compiler] + [src + '.o' for src in self.src] +
+ ['-o', self.name] + self.lib +
+ self.ctx.shared_library_ld_flags(True, self.name),
+ cwd=directory)
+
+
+def create_shared_library(name, toolset):
+ return SharedLibrary(name, toolset)
diff --git a/tools/scan-build-py/libear/config.h.in b/tools/scan-build-py/libear/config.h.in
new file mode 100644
index 000000000000..6643d8995c88
--- /dev/null
+++ b/tools/scan-build-py/libear/config.h.in
@@ -0,0 +1,23 @@
+/* -*- coding: utf-8 -*-
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+*/
+
+#pragma once
+
+#cmakedefine HAVE_EXECVE
+#cmakedefine HAVE_EXECV
+#cmakedefine HAVE_EXECVPE
+#cmakedefine HAVE_EXECVP
+#cmakedefine HAVE_EXECVP2
+#cmakedefine HAVE_EXECT
+#cmakedefine HAVE_EXECL
+#cmakedefine HAVE_EXECLP
+#cmakedefine HAVE_EXECLE
+#cmakedefine HAVE_POSIX_SPAWN
+#cmakedefine HAVE_POSIX_SPAWNP
+#cmakedefine HAVE_NSGETENVIRON
+
+#cmakedefine APPLE
diff --git a/tools/scan-build-py/libear/ear.c b/tools/scan-build-py/libear/ear.c
new file mode 100644
index 000000000000..0e7093af75a5
--- /dev/null
+++ b/tools/scan-build-py/libear/ear.c
@@ -0,0 +1,605 @@
+/* -*- coding: utf-8 -*-
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+*/
+
+/**
+ * This file implements a shared library. This library can be pre-loaded by
+ * the dynamic linker of the Operating System (OS). It implements a few function
+ * related to process creation. By pre-load this library the executed process
+ * uses these functions instead of those from the standard library.
+ *
+ * The idea here is to inject a logic before call the real methods. The logic is
+ * to dump the call into a file. To call the real method this library is doing
+ * the job of the dynamic linker.
+ *
+ * The only input for the log writing is about the destination directory.
+ * This is passed as environment variable.
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <pthread.h>
+
+#if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP
+#include <spawn.h>
+#endif
+
+#if defined HAVE_NSGETENVIRON
+# include <crt_externs.h>
+#else
+extern char **environ;
+#endif
+
+#define ENV_OUTPUT "INTERCEPT_BUILD_TARGET_DIR"
+#ifdef APPLE
+# define ENV_FLAT "DYLD_FORCE_FLAT_NAMESPACE"
+# define ENV_PRELOAD "DYLD_INSERT_LIBRARIES"
+# define ENV_SIZE 3
+#else
+# define ENV_PRELOAD "LD_PRELOAD"
+# define ENV_SIZE 2
+#endif
+
+#define DLSYM(TYPE_, VAR_, SYMBOL_) \
+ union { \
+ void *from; \
+ TYPE_ to; \
+ } cast; \
+ if (0 == (cast.from = dlsym(RTLD_NEXT, SYMBOL_))) { \
+ perror("bear: dlsym"); \
+ exit(EXIT_FAILURE); \
+ } \
+ TYPE_ const VAR_ = cast.to;
+
+
+typedef char const * bear_env_t[ENV_SIZE];
+
+static int bear_capture_env_t(bear_env_t *env);
+static int bear_reset_env_t(bear_env_t *env);
+static void bear_release_env_t(bear_env_t *env);
+static char const **bear_update_environment(char *const envp[], bear_env_t *env);
+static char const **bear_update_environ(char const **in, char const *key, char const *value);
+static char **bear_get_environment();
+static void bear_report_call(char const *fun, char const *const argv[]);
+static char const **bear_strings_build(char const *arg, va_list *ap);
+static char const **bear_strings_copy(char const **const in);
+static char const **bear_strings_append(char const **in, char const *e);
+static size_t bear_strings_length(char const *const *in);
+static void bear_strings_release(char const **);
+
+
+static bear_env_t env_names =
+ { ENV_OUTPUT
+ , ENV_PRELOAD
+#ifdef ENV_FLAT
+ , ENV_FLAT
+#endif
+ };
+
+static bear_env_t initial_env =
+ { 0
+ , 0
+#ifdef ENV_FLAT
+ , 0
+#endif
+ };
+
+static int initialized = 0;
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void on_load(void) __attribute__((constructor));
+static void on_unload(void) __attribute__((destructor));
+
+
+#ifdef HAVE_EXECVE
+static int call_execve(const char *path, char *const argv[],
+ char *const envp[]);
+#endif
+#ifdef HAVE_EXECVP
+static int call_execvp(const char *file, char *const argv[]);
+#endif
+#ifdef HAVE_EXECVPE
+static int call_execvpe(const char *file, char *const argv[],
+ char *const envp[]);
+#endif
+#ifdef HAVE_EXECVP2
+static int call_execvP(const char *file, const char *search_path,
+ char *const argv[]);
+#endif
+#ifdef HAVE_EXECT
+static int call_exect(const char *path, char *const argv[],
+ char *const envp[]);
+#endif
+#ifdef HAVE_POSIX_SPAWN
+static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict],
+ char *const envp[restrict]);
+#endif
+#ifdef HAVE_POSIX_SPAWNP
+static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict],
+ char *const envp[restrict]);
+#endif
+
+
+/* Initialization method to Captures the relevant environment variables.
+ */
+
+static void on_load(void) {
+ pthread_mutex_lock(&mutex);
+ if (!initialized)
+ initialized = bear_capture_env_t(&initial_env);
+ pthread_mutex_unlock(&mutex);
+}
+
+static void on_unload(void) {
+ pthread_mutex_lock(&mutex);
+ bear_release_env_t(&initial_env);
+ initialized = 0;
+ pthread_mutex_unlock(&mutex);
+}
+
+
+/* These are the methods we are try to hijack.
+ */
+
+#ifdef HAVE_EXECVE
+int execve(const char *path, char *const argv[], char *const envp[]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ return call_execve(path, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECV
+#ifndef HAVE_EXECVE
+#error can not implement execv without execve
+#endif
+int execv(const char *path, char *const argv[]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ char * const * envp = bear_get_environment();
+ return call_execve(path, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECVPE
+int execvpe(const char *file, char *const argv[], char *const envp[]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ return call_execvpe(file, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECVP
+int execvp(const char *file, char *const argv[]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ return call_execvp(file, argv);
+}
+#endif
+
+#ifdef HAVE_EXECVP2
+int execvP(const char *file, const char *search_path, char *const argv[]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ return call_execvP(file, search_path, argv);
+}
+#endif
+
+#ifdef HAVE_EXECT
+int exect(const char *path, char *const argv[], char *const envp[]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ return call_exect(path, argv, envp);
+}
+#endif
+
+#ifdef HAVE_EXECL
+# ifndef HAVE_EXECVE
+# error can not implement execl without execve
+# endif
+int execl(const char *path, const char *arg, ...) {
+ va_list args;
+ va_start(args, arg);
+ char const **argv = bear_strings_build(arg, &args);
+ va_end(args);
+
+ bear_report_call(__func__, (char const *const *)argv);
+ char * const * envp = bear_get_environment();
+ int const result = call_execve(path, (char *const *)argv, envp);
+
+ bear_strings_release(argv);
+ return result;
+}
+#endif
+
+#ifdef HAVE_EXECLP
+# ifndef HAVE_EXECVP
+# error can not implement execlp without execvp
+# endif
+int execlp(const char *file, const char *arg, ...) {
+ va_list args;
+ va_start(args, arg);
+ char const **argv = bear_strings_build(arg, &args);
+ va_end(args);
+
+ bear_report_call(__func__, (char const *const *)argv);
+ int const result = call_execvp(file, (char *const *)argv);
+
+ bear_strings_release(argv);
+ return result;
+}
+#endif
+
+#ifdef HAVE_EXECLE
+# ifndef HAVE_EXECVE
+# error can not implement execle without execve
+# endif
+// int execle(const char *path, const char *arg, ..., char * const envp[]);
+int execle(const char *path, const char *arg, ...) {
+ va_list args;
+ va_start(args, arg);
+ char const **argv = bear_strings_build(arg, &args);
+ char const **envp = va_arg(args, char const **);
+ va_end(args);
+
+ bear_report_call(__func__, (char const *const *)argv);
+ int const result =
+ call_execve(path, (char *const *)argv, (char *const *)envp);
+
+ bear_strings_release(argv);
+ return result;
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWN
+int posix_spawn(pid_t *restrict pid, const char *restrict path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict], char *const envp[restrict]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ return call_posix_spawn(pid, path, file_actions, attrp, argv, envp);
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWNP
+int posix_spawnp(pid_t *restrict pid, const char *restrict file,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict], char *const envp[restrict]) {
+ bear_report_call(__func__, (char const *const *)argv);
+ return call_posix_spawnp(pid, file, file_actions, attrp, argv, envp);
+}
+#endif
+
+/* These are the methods which forward the call to the standard implementation.
+ */
+
+#ifdef HAVE_EXECVE
+static int call_execve(const char *path, char *const argv[],
+ char *const envp[]) {
+ typedef int (*func)(const char *, char *const *, char *const *);
+
+ DLSYM(func, fp, "execve");
+
+ char const **const menvp = bear_update_environment(envp, &initial_env);
+ int const result = (*fp)(path, argv, (char *const *)menvp);
+ bear_strings_release(menvp);
+ return result;
+}
+#endif
+
+#ifdef HAVE_EXECVPE
+static int call_execvpe(const char *file, char *const argv[],
+ char *const envp[]) {
+ typedef int (*func)(const char *, char *const *, char *const *);
+
+ DLSYM(func, fp, "execvpe");
+
+ char const **const menvp = bear_update_environment(envp, &initial_env);
+ int const result = (*fp)(file, argv, (char *const *)menvp);
+ bear_strings_release(menvp);
+ return result;
+}
+#endif
+
+#ifdef HAVE_EXECVP
+static int call_execvp(const char *file, char *const argv[]) {
+ typedef int (*func)(const char *file, char *const argv[]);
+
+ DLSYM(func, fp, "execvp");
+
+ bear_env_t current_env;
+ bear_capture_env_t(&current_env);
+ bear_reset_env_t(&initial_env);
+ int const result = (*fp)(file, argv);
+ bear_reset_env_t(&current_env);
+ bear_release_env_t(&current_env);
+
+ return result;
+}
+#endif
+
+#ifdef HAVE_EXECVP2
+static int call_execvP(const char *file, const char *search_path,
+ char *const argv[]) {
+ typedef int (*func)(const char *, const char *, char *const *);
+
+ DLSYM(func, fp, "execvP");
+
+ bear_env_t current_env;
+ bear_capture_env_t(&current_env);
+ bear_reset_env_t(&initial_env);
+ int const result = (*fp)(file, search_path, argv);
+ bear_reset_env_t(&current_env);
+ bear_release_env_t(&current_env);
+
+ return result;
+}
+#endif
+
+#ifdef HAVE_EXECT
+static int call_exect(const char *path, char *const argv[],
+ char *const envp[]) {
+ typedef int (*func)(const char *, char *const *, char *const *);
+
+ DLSYM(func, fp, "exect");
+
+ char const **const menvp = bear_update_environment(envp, &initial_env);
+ int const result = (*fp)(path, argv, (char *const *)menvp);
+ bear_strings_release(menvp);
+ return result;
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWN
+static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict],
+ char *const envp[restrict]) {
+ typedef int (*func)(pid_t *restrict, const char *restrict,
+ const posix_spawn_file_actions_t *,
+ const posix_spawnattr_t *restrict,
+ char *const *restrict, char *const *restrict);
+
+ DLSYM(func, fp, "posix_spawn");
+
+ char const **const menvp = bear_update_environment(envp, &initial_env);
+ int const result =
+ (*fp)(pid, path, file_actions, attrp, argv, (char *const *restrict)menvp);
+ bear_strings_release(menvp);
+ return result;
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWNP
+static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *restrict attrp,
+ char *const argv[restrict],
+ char *const envp[restrict]) {
+ typedef int (*func)(pid_t *restrict, const char *restrict,
+ const posix_spawn_file_actions_t *,
+ const posix_spawnattr_t *restrict,
+ char *const *restrict, char *const *restrict);
+
+ DLSYM(func, fp, "posix_spawnp");
+
+ char const **const menvp = bear_update_environment(envp, &initial_env);
+ int const result =
+ (*fp)(pid, file, file_actions, attrp, argv, (char *const *restrict)menvp);
+ bear_strings_release(menvp);
+ return result;
+}
+#endif
+
+/* this method is to write log about the process creation. */
+
+static void bear_report_call(char const *fun, char const *const argv[]) {
+ static int const GS = 0x1d;
+ static int const RS = 0x1e;
+ static int const US = 0x1f;
+
+ if (!initialized)
+ return;
+
+ pthread_mutex_lock(&mutex);
+ const char *cwd = getcwd(NULL, 0);
+ if (0 == cwd) {
+ perror("bear: getcwd");
+ exit(EXIT_FAILURE);
+ }
+ char const * const out_dir = initial_env[0];
+ size_t const path_max_length = strlen(out_dir) + 32;
+ char filename[path_max_length];
+ if (-1 == snprintf(filename, path_max_length, "%s/%d.cmd", out_dir, getpid())) {
+ perror("bear: snprintf");
+ exit(EXIT_FAILURE);
+ }
+ FILE * fd = fopen(filename, "a+");
+ if (0 == fd) {
+ perror("bear: fopen");
+ exit(EXIT_FAILURE);
+ }
+ fprintf(fd, "%d%c", getpid(), RS);
+ fprintf(fd, "%d%c", getppid(), RS);
+ fprintf(fd, "%s%c", fun, RS);
+ fprintf(fd, "%s%c", cwd, RS);
+ size_t const argc = bear_strings_length(argv);
+ for (size_t it = 0; it < argc; ++it) {
+ fprintf(fd, "%s%c", argv[it], US);
+ }
+ fprintf(fd, "%c", GS);
+ if (fclose(fd)) {
+ perror("bear: fclose");
+ exit(EXIT_FAILURE);
+ }
+ free((void *)cwd);
+ pthread_mutex_unlock(&mutex);
+}
+
+/* update environment assure that chilren processes will copy the desired
+ * behaviour */
+
+static int bear_capture_env_t(bear_env_t *env) {
+ int status = 1;
+ for (size_t it = 0; it < ENV_SIZE; ++it) {
+ char const * const env_value = getenv(env_names[it]);
+ char const * const env_copy = (env_value) ? strdup(env_value) : env_value;
+ (*env)[it] = env_copy;
+ status &= (env_copy) ? 1 : 0;
+ }
+ return status;
+}
+
+static int bear_reset_env_t(bear_env_t *env) {
+ int status = 1;
+ for (size_t it = 0; it < ENV_SIZE; ++it) {
+ if ((*env)[it]) {
+ setenv(env_names[it], (*env)[it], 1);
+ } else {
+ unsetenv(env_names[it]);
+ }
+ }
+ return status;
+}
+
+static void bear_release_env_t(bear_env_t *env) {
+ for (size_t it = 0; it < ENV_SIZE; ++it) {
+ free((void *)(*env)[it]);
+ (*env)[it] = 0;
+ }
+}
+
+static char const **bear_update_environment(char *const envp[], bear_env_t *env) {
+ char const **result = bear_strings_copy((char const **)envp);
+ for (size_t it = 0; it < ENV_SIZE && (*env)[it]; ++it)
+ result = bear_update_environ(result, env_names[it], (*env)[it]);
+ return result;
+}
+
+static char const **bear_update_environ(char const *envs[], char const *key, char const * const value) {
+ // find the key if it's there
+ size_t const key_length = strlen(key);
+ char const **it = envs;
+ for (; (it) && (*it); ++it) {
+ if ((0 == strncmp(*it, key, key_length)) &&
+ (strlen(*it) > key_length) && ('=' == (*it)[key_length]))
+ break;
+ }
+ // allocate a environment entry
+ size_t const value_length = strlen(value);
+ size_t const env_length = key_length + value_length + 2;
+ char *env = malloc(env_length);
+ if (0 == env) {
+ perror("bear: malloc [in env_update]");
+ exit(EXIT_FAILURE);
+ }
+ if (-1 == snprintf(env, env_length, "%s=%s", key, value)) {
+ perror("bear: snprintf");
+ exit(EXIT_FAILURE);
+ }
+ // replace or append the environment entry
+ if (it && *it) {
+ free((void *)*it);
+ *it = env;
+ return envs;
+ }
+ return bear_strings_append(envs, env);
+}
+
+static char **bear_get_environment() {
+#if defined HAVE_NSGETENVIRON
+ return *_NSGetEnviron();
+#else
+ return environ;
+#endif
+}
+
+/* util methods to deal with string arrays. environment and process arguments
+ * are both represented as string arrays. */
+
+static char const **bear_strings_build(char const *const arg, va_list *args) {
+ char const **result = 0;
+ size_t size = 0;
+ for (char const *it = arg; it; it = va_arg(*args, char const *)) {
+ result = realloc(result, (size + 1) * sizeof(char const *));
+ if (0 == result) {
+ perror("bear: realloc");
+ exit(EXIT_FAILURE);
+ }
+ char const *copy = strdup(it);
+ if (0 == copy) {
+ perror("bear: strdup");
+ exit(EXIT_FAILURE);
+ }
+ result[size++] = copy;
+ }
+ result = realloc(result, (size + 1) * sizeof(char const *));
+ if (0 == result) {
+ perror("bear: realloc");
+ exit(EXIT_FAILURE);
+ }
+ result[size++] = 0;
+
+ return result;
+}
+
+static char const **bear_strings_copy(char const **const in) {
+ size_t const size = bear_strings_length(in);
+
+ char const **const result = malloc((size + 1) * sizeof(char const *));
+ if (0 == result) {
+ perror("bear: malloc");
+ exit(EXIT_FAILURE);
+ }
+
+ char const **out_it = result;
+ for (char const *const *in_it = in; (in_it) && (*in_it);
+ ++in_it, ++out_it) {
+ *out_it = strdup(*in_it);
+ if (0 == *out_it) {
+ perror("bear: strdup");
+ exit(EXIT_FAILURE);
+ }
+ }
+ *out_it = 0;
+ return result;
+}
+
+static char const **bear_strings_append(char const **const in,
+ char const *const e) {
+ size_t size = bear_strings_length(in);
+ char const **result = realloc(in, (size + 2) * sizeof(char const *));
+ if (0 == result) {
+ perror("bear: realloc");
+ exit(EXIT_FAILURE);
+ }
+ result[size++] = e;
+ result[size++] = 0;
+ return result;
+}
+
+static size_t bear_strings_length(char const *const *const in) {
+ size_t result = 0;
+ for (char const *const *it = in; (it) && (*it); ++it)
+ ++result;
+ return result;
+}
+
+static void bear_strings_release(char const **in) {
+ for (char const *const *it = in; (it) && (*it); ++it) {
+ free((void *)*it);
+ }
+ free((void *)in);
+}
diff --git a/tools/scan-build-py/libscanbuild/__init__.py b/tools/scan-build-py/libscanbuild/__init__.py
new file mode 100644
index 000000000000..c020b4e4345d
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/__init__.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+"""
+This module responsible to run the Clang static analyzer against any build
+and generate reports.
+"""
+
+
+def duplicate_check(method):
+ """ Predicate to detect duplicated entries.
+
+ Unique hash method can be use to detect duplicates. Entries are
+ represented as dictionaries, which has no default hash method.
+ This implementation uses a set datatype to store the unique hash values.
+
+ This method returns a method which can detect the duplicate values. """
+
+ def predicate(entry):
+ entry_hash = predicate.unique(entry)
+ if entry_hash not in predicate.state:
+ predicate.state.add(entry_hash)
+ return False
+ return True
+
+ predicate.unique = method
+ predicate.state = set()
+ return predicate
+
+
+def tempdir():
+ """ Return the default temorary directory. """
+
+ from os import getenv
+ return getenv('TMPDIR', getenv('TEMP', getenv('TMP', '/tmp')))
+
+
+def initialize_logging(verbose_level):
+ """ Output content controlled by the verbosity level. """
+
+ import sys
+ import os.path
+ import logging
+ level = logging.WARNING - min(logging.WARNING, (10 * verbose_level))
+
+ if verbose_level <= 3:
+ fmt_string = '{0}: %(levelname)s: %(message)s'
+ else:
+ fmt_string = '{0}: %(levelname)s: %(funcName)s: %(message)s'
+
+ program = os.path.basename(sys.argv[0])
+ logging.basicConfig(format=fmt_string.format(program), level=level)
+
+
+def command_entry_point(function):
+ """ Decorator for command entry points. """
+
+ import functools
+ import logging
+
+ @functools.wraps(function)
+ def wrapper(*args, **kwargs):
+
+ exit_code = 127
+ try:
+ exit_code = function(*args, **kwargs)
+ except KeyboardInterrupt:
+ logging.warning('Keyboard interupt')
+ except Exception:
+ logging.exception('Internal error.')
+ if logging.getLogger().isEnabledFor(logging.DEBUG):
+ logging.error("Please report this bug and attach the output "
+ "to the bug report")
+ else:
+ logging.error("Please run this command again and turn on "
+ "verbose mode (add '-vvv' as argument).")
+ finally:
+ return exit_code
+
+ return wrapper
diff --git a/tools/scan-build-py/libscanbuild/analyze.py b/tools/scan-build-py/libscanbuild/analyze.py
new file mode 100644
index 000000000000..0d3547befeef
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/analyze.py
@@ -0,0 +1,502 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module implements the 'scan-build' command API.
+
+To run the static analyzer against a build is done in multiple steps:
+
+ -- Intercept: capture the compilation command during the build,
+ -- Analyze: run the analyzer against the captured commands,
+ -- Report: create a cover report from the analyzer outputs. """
+
+import sys
+import re
+import os
+import os.path
+import json
+import argparse
+import logging
+import subprocess
+import multiprocessing
+from libscanbuild import initialize_logging, tempdir, command_entry_point
+from libscanbuild.runner import run
+from libscanbuild.intercept import capture
+from libscanbuild.report import report_directory, document
+from libscanbuild.clang import get_checkers
+from libscanbuild.runner import action_check
+from libscanbuild.command import classify_parameters, classify_source
+
+__all__ = ['analyze_build_main', 'analyze_build_wrapper']
+
+COMPILER_WRAPPER_CC = 'analyze-cc'
+COMPILER_WRAPPER_CXX = 'analyze-c++'
+
+
+@command_entry_point
+def analyze_build_main(bin_dir, from_build_command):
+ """ Entry point for 'analyze-build' and 'scan-build'. """
+
+ parser = create_parser(from_build_command)
+ args = parser.parse_args()
+ validate(parser, args, from_build_command)
+
+ # setup logging
+ initialize_logging(args.verbose)
+ logging.debug('Parsed arguments: %s', args)
+
+ with report_directory(args.output, args.keep_empty) as target_dir:
+ if not from_build_command:
+ # run analyzer only and generate cover report
+ run_analyzer(args, target_dir)
+ number_of_bugs = document(args, target_dir, True)
+ return number_of_bugs if args.status_bugs else 0
+ elif args.intercept_first:
+ # run build command and capture compiler executions
+ exit_code = capture(args, bin_dir)
+ # next step to run the analyzer against the captured commands
+ if need_analyzer(args.build):
+ run_analyzer(args, target_dir)
+ # cover report generation and bug counting
+ number_of_bugs = document(args, target_dir, True)
+ # remove the compilation database when it was not requested
+ if os.path.exists(args.cdb):
+ os.unlink(args.cdb)
+ # set exit status as it was requested
+ return number_of_bugs if args.status_bugs else exit_code
+ else:
+ return exit_code
+ else:
+ # run the build command with compiler wrappers which
+ # execute the analyzer too. (interposition)
+ environment = setup_environment(args, target_dir, bin_dir)
+ logging.debug('run build in environment: %s', environment)
+ exit_code = subprocess.call(args.build, env=environment)
+ logging.debug('build finished with exit code: %d', exit_code)
+ # cover report generation and bug counting
+ number_of_bugs = document(args, target_dir, False)
+ # set exit status as it was requested
+ return number_of_bugs if args.status_bugs else exit_code
+
+
+def need_analyzer(args):
+ """ Check the intent of the build command.
+
+ When static analyzer run against project configure step, it should be
+ silent and no need to run the analyzer or generate report.
+
+ To run `scan-build` against the configure step might be neccessary,
+ when compiler wrappers are used. That's the moment when build setup
+ check the compiler and capture the location for the build process. """
+
+ return len(args) and not re.search('configure|autogen', args[0])
+
+
+def run_analyzer(args, output_dir):
+ """ Runs the analyzer against the given compilation database. """
+
+ def exclude(filename):
+ """ Return true when any excluded directory prefix the filename. """
+ return any(re.match(r'^' + directory, filename)
+ for directory in args.excludes)
+
+ consts = {
+ 'clang': args.clang,
+ 'output_dir': output_dir,
+ 'output_format': args.output_format,
+ 'output_failures': args.output_failures,
+ 'direct_args': analyzer_params(args)
+ }
+
+ logging.debug('run analyzer against compilation database')
+ with open(args.cdb, 'r') as handle:
+ generator = (dict(cmd, **consts)
+ for cmd in json.load(handle) if not exclude(cmd['file']))
+ # when verbose output requested execute sequentially
+ pool = multiprocessing.Pool(1 if args.verbose > 2 else None)
+ for current in pool.imap_unordered(run, generator):
+ if current is not None:
+ # display error message from the static analyzer
+ for line in current['error_output']:
+ logging.info(line.rstrip())
+ pool.close()
+ pool.join()
+
+
+def setup_environment(args, destination, bin_dir):
+ """ Set up environment for build command to interpose compiler wrapper. """
+
+ environment = dict(os.environ)
+ environment.update({
+ 'CC': os.path.join(bin_dir, COMPILER_WRAPPER_CC),
+ 'CXX': os.path.join(bin_dir, COMPILER_WRAPPER_CXX),
+ 'ANALYZE_BUILD_CC': args.cc,
+ 'ANALYZE_BUILD_CXX': args.cxx,
+ 'ANALYZE_BUILD_CLANG': args.clang if need_analyzer(args.build) else '',
+ 'ANALYZE_BUILD_VERBOSE': 'DEBUG' if args.verbose > 2 else 'WARNING',
+ 'ANALYZE_BUILD_REPORT_DIR': destination,
+ 'ANALYZE_BUILD_REPORT_FORMAT': args.output_format,
+ 'ANALYZE_BUILD_REPORT_FAILURES': 'yes' if args.output_failures else '',
+ 'ANALYZE_BUILD_PARAMETERS': ' '.join(analyzer_params(args))
+ })
+ return environment
+
+
+def analyze_build_wrapper(cplusplus):
+ """ Entry point for `analyze-cc` and `analyze-c++` compiler wrappers. """
+
+ # initialize wrapper logging
+ logging.basicConfig(format='analyze: %(levelname)s: %(message)s',
+ level=os.getenv('ANALYZE_BUILD_VERBOSE', 'INFO'))
+ # execute with real compiler
+ compiler = os.getenv('ANALYZE_BUILD_CXX', 'c++') if cplusplus \
+ else os.getenv('ANALYZE_BUILD_CC', 'cc')
+ compilation = [compiler] + sys.argv[1:]
+ logging.info('execute compiler: %s', compilation)
+ result = subprocess.call(compilation)
+ # exit when it fails, ...
+ if result or not os.getenv('ANALYZE_BUILD_CLANG'):
+ return result
+ # ... and run the analyzer if all went well.
+ try:
+ # collect the needed parameters from environment, crash when missing
+ consts = {
+ 'clang': os.getenv('ANALYZE_BUILD_CLANG'),
+ 'output_dir': os.getenv('ANALYZE_BUILD_REPORT_DIR'),
+ 'output_format': os.getenv('ANALYZE_BUILD_REPORT_FORMAT'),
+ 'output_failures': os.getenv('ANALYZE_BUILD_REPORT_FAILURES'),
+ 'direct_args': os.getenv('ANALYZE_BUILD_PARAMETERS',
+ '').split(' '),
+ 'directory': os.getcwd(),
+ }
+ # get relevant parameters from command line arguments
+ args = classify_parameters(sys.argv)
+ filenames = args.pop('files', [])
+ for filename in (name for name in filenames if classify_source(name)):
+ parameters = dict(args, file=filename, **consts)
+ logging.debug('analyzer parameters %s', parameters)
+ current = action_check(parameters)
+ # display error message from the static analyzer
+ if current is not None:
+ for line in current['error_output']:
+ logging.info(line.rstrip())
+ except Exception:
+ logging.exception("run analyzer inside compiler wrapper failed.")
+ return 0
+
+
+def analyzer_params(args):
+ """ A group of command line arguments can mapped to command
+ line arguments of the analyzer. This method generates those. """
+
+ def prefix_with(constant, pieces):
+ """ From a sequence create another sequence where every second element
+ is from the original sequence and the odd elements are the prefix.
+
+ eg.: prefix_with(0, [1,2,3]) creates [0, 1, 0, 2, 0, 3] """
+
+ return [elem for piece in pieces for elem in [constant, piece]]
+
+ result = []
+
+ if args.store_model:
+ result.append('-analyzer-store={0}'.format(args.store_model))
+ if args.constraints_model:
+ result.append(
+ '-analyzer-constraints={0}'.format(args.constraints_model))
+ if args.internal_stats:
+ result.append('-analyzer-stats')
+ if args.analyze_headers:
+ result.append('-analyzer-opt-analyze-headers')
+ if args.stats:
+ result.append('-analyzer-checker=debug.Stats')
+ if args.maxloop:
+ result.extend(['-analyzer-max-loop', str(args.maxloop)])
+ if args.output_format:
+ result.append('-analyzer-output={0}'.format(args.output_format))
+ if args.analyzer_config:
+ result.append(args.analyzer_config)
+ if args.verbose >= 4:
+ result.append('-analyzer-display-progress')
+ if args.plugins:
+ result.extend(prefix_with('-load', args.plugins))
+ if args.enable_checker:
+ checkers = ','.join(args.enable_checker)
+ result.extend(['-analyzer-checker', checkers])
+ if args.disable_checker:
+ checkers = ','.join(args.disable_checker)
+ result.extend(['-analyzer-disable-checker', checkers])
+ if os.getenv('UBIVIZ'):
+ result.append('-analyzer-viz-egraph-ubigraph')
+
+ return prefix_with('-Xclang', result)
+
+
+def print_active_checkers(checkers):
+ """ Print active checkers to stdout. """
+
+ for name in sorted(name for name, (_, active) in checkers.items()
+ if active):
+ print(name)
+
+
+def print_checkers(checkers):
+ """ Print verbose checker help to stdout. """
+
+ print('')
+ print('available checkers:')
+ print('')
+ for name in sorted(checkers.keys()):
+ description, active = checkers[name]
+ prefix = '+' if active else ' '
+ if len(name) > 30:
+ print(' {0} {1}'.format(prefix, name))
+ print(' ' * 35 + description)
+ else:
+ print(' {0} {1: <30} {2}'.format(prefix, name, description))
+ print('')
+ print('NOTE: "+" indicates that an analysis is enabled by default.')
+ print('')
+
+
+def validate(parser, args, from_build_command):
+ """ Validation done by the parser itself, but semantic check still
+ needs to be done. This method is doing that. """
+
+ if args.help_checkers_verbose:
+ print_checkers(get_checkers(args.clang, args.plugins))
+ parser.exit()
+ elif args.help_checkers:
+ print_active_checkers(get_checkers(args.clang, args.plugins))
+ parser.exit()
+
+ if from_build_command and not args.build:
+ parser.error('missing build command')
+
+
+def create_parser(from_build_command):
+ """ Command line argument parser factory method. """
+
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+
+ parser.add_argument(
+ '--verbose', '-v',
+ action='count',
+ default=0,
+ help="""Enable verbose output from '%(prog)s'. A second and third
+ flag increases verbosity.""")
+ parser.add_argument(
+ '--override-compiler',
+ action='store_true',
+ help="""Always resort to the compiler wrapper even when better
+ interposition methods are available.""")
+ parser.add_argument(
+ '--intercept-first',
+ action='store_true',
+ help="""Run the build commands only, build a compilation database,
+ then run the static analyzer afterwards.
+ Generally speaking it has better coverage on build commands.
+ With '--override-compiler' it use compiler wrapper, but does
+ not run the analyzer till the build is finished. """)
+ parser.add_argument(
+ '--cdb',
+ metavar='<file>',
+ default="compile_commands.json",
+ help="""The JSON compilation database.""")
+
+ parser.add_argument(
+ '--output', '-o',
+ metavar='<path>',
+ default=tempdir(),
+ help="""Specifies the output directory for analyzer reports.
+ Subdirectory will be created if default directory is targeted.
+ """)
+ parser.add_argument(
+ '--status-bugs',
+ action='store_true',
+ help="""By default, the exit status of '%(prog)s' is the same as the
+ executed build command. Specifying this option causes the exit
+ status of '%(prog)s' to be non zero if it found potential bugs
+ and zero otherwise.""")
+ parser.add_argument(
+ '--html-title',
+ metavar='<title>',
+ help="""Specify the title used on generated HTML pages.
+ If not specified, a default title will be used.""")
+ parser.add_argument(
+ '--analyze-headers',
+ action='store_true',
+ help="""Also analyze functions in #included files. By default, such
+ functions are skipped unless they are called by functions
+ within the main source file.""")
+ format_group = parser.add_mutually_exclusive_group()
+ format_group.add_argument(
+ '--plist', '-plist',
+ dest='output_format',
+ const='plist',
+ default='html',
+ action='store_const',
+ help="""This option outputs the results as a set of .plist files.""")
+ format_group.add_argument(
+ '--plist-html', '-plist-html',
+ dest='output_format',
+ const='plist-html',
+ default='html',
+ action='store_const',
+ help="""This option outputs the results as a set of .html and .plist
+ files.""")
+ # TODO: implement '-view '
+
+ advanced = parser.add_argument_group('advanced options')
+ advanced.add_argument(
+ '--keep-empty',
+ action='store_true',
+ help="""Don't remove the build results directory even if no issues
+ were reported.""")
+ advanced.add_argument(
+ '--no-failure-reports', '-no-failure-reports',
+ dest='output_failures',
+ action='store_false',
+ help="""Do not create a 'failures' subdirectory that includes analyzer
+ crash reports and preprocessed source files.""")
+ advanced.add_argument(
+ '--stats', '-stats',
+ action='store_true',
+ help="""Generates visitation statistics for the project being analyzed.
+ """)
+ advanced.add_argument(
+ '--internal-stats',
+ action='store_true',
+ help="""Generate internal analyzer statistics.""")
+ advanced.add_argument(
+ '--maxloop', '-maxloop',
+ metavar='<loop count>',
+ type=int,
+ help="""Specifiy the number of times a block can be visited before
+ giving up. Increase for more comprehensive coverage at a cost
+ of speed.""")
+ advanced.add_argument(
+ '--store', '-store',
+ metavar='<model>',
+ dest='store_model',
+ choices=['region', 'basic'],
+ help="""Specify the store model used by the analyzer.
+ 'region' specifies a field- sensitive store model.
+ 'basic' which is far less precise but can more quickly
+ analyze code. 'basic' was the default store model for
+ checker-0.221 and earlier.""")
+ advanced.add_argument(
+ '--constraints', '-constraints',
+ metavar='<model>',
+ dest='constraints_model',
+ choices=['range', 'basic'],
+ help="""Specify the contraint engine used by the analyzer. Specifying
+ 'basic' uses a simpler, less powerful constraint model used by
+ checker-0.160 and earlier.""")
+ advanced.add_argument(
+ '--use-analyzer',
+ metavar='<path>',
+ dest='clang',
+ default='clang',
+ help="""'%(prog)s' uses the 'clang' executable relative to itself for
+ static analysis. One can override this behavior with this
+ option by using the 'clang' packaged with Xcode (on OS X) or
+ from the PATH.""")
+ advanced.add_argument(
+ '--use-cc',
+ metavar='<path>',
+ dest='cc',
+ default='cc',
+ help="""When '%(prog)s' analyzes a project by interposing a "fake
+ compiler", which executes a real compiler for compilation and
+ do other tasks (to run the static analyzer or just record the
+ compiler invocation). Because of this interposing, '%(prog)s'
+ does not know what compiler your project normally uses.
+ Instead, it simply overrides the CC environment variable, and
+ guesses your default compiler.
+
+ If you need '%(prog)s' to use a specific compiler for
+ *compilation* then you can use this option to specify a path
+ to that compiler.""")
+ advanced.add_argument(
+ '--use-c++',
+ metavar='<path>',
+ dest='cxx',
+ default='c++',
+ help="""This is the same as "--use-cc" but for C++ code.""")
+ advanced.add_argument(
+ '--analyzer-config', '-analyzer-config',
+ metavar='<options>',
+ help="""Provide options to pass through to the analyzer's
+ -analyzer-config flag. Several options are separated with
+ comma: 'key1=val1,key2=val2'
+
+ Available options:
+ stable-report-filename=true or false (default)
+
+ Switch the page naming to:
+ report-<filename>-<function/method name>-<id>.html
+ instead of report-XXXXXX.html""")
+ advanced.add_argument(
+ '--exclude',
+ metavar='<directory>',
+ dest='excludes',
+ action='append',
+ default=[],
+ help="""Do not run static analyzer against files found in this
+ directory. (You can specify this option multiple times.)
+ Could be usefull when project contains 3rd party libraries.
+ The directory path shall be absolute path as file names in
+ the compilation database.""")
+
+ plugins = parser.add_argument_group('checker options')
+ plugins.add_argument(
+ '--load-plugin', '-load-plugin',
+ metavar='<plugin library>',
+ dest='plugins',
+ action='append',
+ help="""Loading external checkers using the clang plugin interface.""")
+ plugins.add_argument(
+ '--enable-checker', '-enable-checker',
+ metavar='<checker name>',
+ action=AppendCommaSeparated,
+ help="""Enable specific checker.""")
+ plugins.add_argument(
+ '--disable-checker', '-disable-checker',
+ metavar='<checker name>',
+ action=AppendCommaSeparated,
+ help="""Disable specific checker.""")
+ plugins.add_argument(
+ '--help-checkers',
+ action='store_true',
+ help="""A default group of checkers is run unless explicitly disabled.
+ Exactly which checkers constitute the default group is a
+ function of the operating system in use. These can be printed
+ with this flag.""")
+ plugins.add_argument(
+ '--help-checkers-verbose',
+ action='store_true',
+ help="""Print all available checkers and mark the enabled ones.""")
+
+ if from_build_command:
+ parser.add_argument(
+ dest='build',
+ nargs=argparse.REMAINDER,
+ help="""Command to run.""")
+
+ return parser
+
+
+class AppendCommaSeparated(argparse.Action):
+ """ argparse Action class to support multiple comma separated lists. """
+
+ def __call__(self, __parser, namespace, values, __option_string):
+ # getattr(obj, attr, default) does not really returns default but none
+ if getattr(namespace, self.dest, None) is None:
+ setattr(namespace, self.dest, [])
+ # once it's fixed we can use as expected
+ actual = getattr(namespace, self.dest)
+ actual.extend(values.split(','))
+ setattr(namespace, self.dest, actual)
diff --git a/tools/scan-build-py/libscanbuild/clang.py b/tools/scan-build-py/libscanbuild/clang.py
new file mode 100644
index 000000000000..0c3454b16a76
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/clang.py
@@ -0,0 +1,156 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module is responsible for the Clang executable.
+
+Since Clang command line interface is so rich, but this project is using only
+a subset of that, it makes sense to create a function specific wrapper. """
+
+import re
+import subprocess
+import logging
+from libscanbuild.shell import decode
+
+__all__ = ['get_version', 'get_arguments', 'get_checkers']
+
+
+def get_version(cmd):
+ """ Returns the compiler version as string. """
+
+ lines = subprocess.check_output([cmd, '-v'], stderr=subprocess.STDOUT)
+ return lines.decode('ascii').splitlines()[0]
+
+
+def get_arguments(command, cwd):
+ """ Capture Clang invocation.
+
+ This method returns the front-end invocation that would be executed as
+ a result of the given driver invocation. """
+
+ def lastline(stream):
+ last = None
+ for line in stream:
+ last = line
+ if last is None:
+ raise Exception("output not found")
+ return last
+
+ cmd = command[:]
+ cmd.insert(1, '-###')
+ logging.debug('exec command in %s: %s', cwd, ' '.join(cmd))
+ child = subprocess.Popen(cmd,
+ cwd=cwd,
+ universal_newlines=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ line = lastline(child.stdout)
+ child.stdout.close()
+ child.wait()
+ if child.returncode == 0:
+ if re.search(r'clang(.*): error:', line):
+ raise Exception(line)
+ return decode(line)
+ else:
+ raise Exception(line)
+
+
+def get_active_checkers(clang, plugins):
+ """ To get the default plugins we execute Clang to print how this
+ compilation would be called.
+
+ For input file we specify stdin and pass only language information. """
+
+ def checkers(language):
+ """ Returns a list of active checkers for the given language. """
+
+ load = [elem
+ for plugin in plugins
+ for elem in ['-Xclang', '-load', '-Xclang', plugin]]
+ cmd = [clang, '--analyze'] + load + ['-x', language, '-']
+ pattern = re.compile(r'^-analyzer-checker=(.*)$')
+ return [pattern.match(arg).group(1)
+ for arg in get_arguments(cmd, '.') if pattern.match(arg)]
+
+ result = set()
+ for language in ['c', 'c++', 'objective-c', 'objective-c++']:
+ result.update(checkers(language))
+ return result
+
+
+def get_checkers(clang, plugins):
+ """ Get all the available checkers from default and from the plugins.
+
+ clang -- the compiler we are using
+ plugins -- list of plugins which was requested by the user
+
+ This method returns a dictionary of all available checkers and status.
+
+ {<plugin name>: (<plugin description>, <is active by default>)} """
+
+ plugins = plugins if plugins else []
+
+ def parse_checkers(stream):
+ """ Parse clang -analyzer-checker-help output.
+
+ Below the line 'CHECKERS:' are there the name description pairs.
+ Many of them are in one line, but some long named plugins has the
+ name and the description in separate lines.
+
+ The plugin name is always prefixed with two space character. The
+ name contains no whitespaces. Then followed by newline (if it's
+ too long) or other space characters comes the description of the
+ plugin. The description ends with a newline character. """
+
+ # find checkers header
+ for line in stream:
+ if re.match(r'^CHECKERS:', line):
+ break
+ # find entries
+ state = None
+ for line in stream:
+ if state and not re.match(r'^\s\s\S', line):
+ yield (state, line.strip())
+ state = None
+ elif re.match(r'^\s\s\S+$', line.rstrip()):
+ state = line.strip()
+ else:
+ pattern = re.compile(r'^\s\s(?P<key>\S*)\s*(?P<value>.*)')
+ match = pattern.match(line.rstrip())
+ if match:
+ current = match.groupdict()
+ yield (current['key'], current['value'])
+
+ def is_active(actives, entry):
+ """ Returns true if plugin name is matching the active plugin names.
+
+ actives -- set of active plugin names (or prefixes).
+ entry -- the current plugin name to judge.
+
+ The active plugin names are specific plugin names or prefix of some
+ names. One example for prefix, when it say 'unix' and it shall match
+ on 'unix.API', 'unix.Malloc' and 'unix.MallocSizeof'. """
+
+ return any(re.match(r'^' + a + r'(\.|$)', entry) for a in actives)
+
+ actives = get_active_checkers(clang, plugins)
+
+ load = [elem for plugin in plugins for elem in ['-load', plugin]]
+ cmd = [clang, '-cc1'] + load + ['-analyzer-checker-help']
+
+ logging.debug('exec command: %s', ' '.join(cmd))
+ child = subprocess.Popen(cmd,
+ universal_newlines=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ checkers = {
+ k: (v, is_active(actives, k))
+ for k, v in parse_checkers(child.stdout)
+ }
+ child.stdout.close()
+ child.wait()
+ if child.returncode == 0 and len(checkers):
+ return checkers
+ else:
+ raise Exception('Could not query Clang for available checkers.')
diff --git a/tools/scan-build-py/libscanbuild/command.py b/tools/scan-build-py/libscanbuild/command.py
new file mode 100644
index 000000000000..69ca3393f955
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/command.py
@@ -0,0 +1,133 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module is responsible for to parse a compiler invocation. """
+
+import re
+import os
+
+__all__ = ['Action', 'classify_parameters', 'classify_source']
+
+
+class Action(object):
+ """ Enumeration class for compiler action. """
+
+ Link, Compile, Ignored = range(3)
+
+
+def classify_parameters(command):
+ """ Parses the command line arguments of the given invocation. """
+
+ # result value of this method.
+ # some value are preset, some will be set only when found.
+ result = {
+ 'action': Action.Link,
+ 'files': [],
+ 'output': None,
+ 'compile_options': [],
+ 'c++': is_cplusplus_compiler(command[0])
+ # archs_seen
+ # language
+ }
+
+ # data structure to ignore compiler parameters.
+ # key: parameter name, value: number of parameters to ignore afterwards.
+ ignored = {
+ '-g': 0,
+ '-fsyntax-only': 0,
+ '-save-temps': 0,
+ '-install_name': 1,
+ '-exported_symbols_list': 1,
+ '-current_version': 1,
+ '-compatibility_version': 1,
+ '-init': 1,
+ '-e': 1,
+ '-seg1addr': 1,
+ '-bundle_loader': 1,
+ '-multiply_defined': 1,
+ '-sectorder': 3,
+ '--param': 1,
+ '--serialize-diagnostics': 1
+ }
+
+ args = iter(command[1:])
+ for arg in args:
+ # compiler action parameters are the most important ones...
+ if arg in {'-E', '-S', '-cc1', '-M', '-MM', '-###'}:
+ result.update({'action': Action.Ignored})
+ elif arg == '-c':
+ result.update({'action': max(result['action'], Action.Compile)})
+ # arch flags are taken...
+ elif arg == '-arch':
+ archs = result.get('archs_seen', [])
+ result.update({'archs_seen': archs + [next(args)]})
+ # explicit language option taken...
+ elif arg == '-x':
+ result.update({'language': next(args)})
+ # output flag taken...
+ elif arg == '-o':
+ result.update({'output': next(args)})
+ # warning disable options are taken...
+ elif re.match(r'^-Wno-', arg):
+ result['compile_options'].append(arg)
+ # warning options are ignored...
+ elif re.match(r'^-[mW].+', arg):
+ pass
+ # some preprocessor parameters are ignored...
+ elif arg in {'-MD', '-MMD', '-MG', '-MP'}:
+ pass
+ elif arg in {'-MF', '-MT', '-MQ'}:
+ next(args)
+ # linker options are ignored...
+ elif arg in {'-static', '-shared', '-s', '-rdynamic'} or \
+ re.match(r'^-[lL].+', arg):
+ pass
+ elif arg in {'-l', '-L', '-u', '-z', '-T', '-Xlinker'}:
+ next(args)
+ # some other options are ignored...
+ elif arg in ignored.keys():
+ for _ in range(ignored[arg]):
+ next(args)
+ # parameters which looks source file are taken...
+ elif re.match(r'^[^-].+', arg) and classify_source(arg):
+ result['files'].append(arg)
+ # and consider everything else as compile option.
+ else:
+ result['compile_options'].append(arg)
+
+ return result
+
+
+def classify_source(filename, cplusplus=False):
+ """ Return the language from file name extension. """
+
+ mapping = {
+ '.c': 'c++' if cplusplus else 'c',
+ '.i': 'c++-cpp-output' if cplusplus else 'c-cpp-output',
+ '.ii': 'c++-cpp-output',
+ '.m': 'objective-c',
+ '.mi': 'objective-c-cpp-output',
+ '.mm': 'objective-c++',
+ '.mii': 'objective-c++-cpp-output',
+ '.C': 'c++',
+ '.cc': 'c++',
+ '.CC': 'c++',
+ '.cp': 'c++',
+ '.cpp': 'c++',
+ '.cxx': 'c++',
+ '.c++': 'c++',
+ '.C++': 'c++',
+ '.txx': 'c++'
+ }
+
+ __, extension = os.path.splitext(os.path.basename(filename))
+ return mapping.get(extension)
+
+
+def is_cplusplus_compiler(name):
+ """ Returns true when the compiler name refer to a C++ compiler. """
+
+ match = re.match(r'^([^/]*/)*(\w*-)*(\w+\+\+)(-(\d+(\.\d+){0,3}))?$', name)
+ return False if match is None else True
diff --git a/tools/scan-build-py/libscanbuild/intercept.py b/tools/scan-build-py/libscanbuild/intercept.py
new file mode 100644
index 000000000000..6062e2ea8ca9
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/intercept.py
@@ -0,0 +1,359 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module is responsible to capture the compiler invocation of any
+build process. The result of that should be a compilation database.
+
+This implementation is using the LD_PRELOAD or DYLD_INSERT_LIBRARIES
+mechanisms provided by the dynamic linker. The related library is implemented
+in C language and can be found under 'libear' directory.
+
+The 'libear' library is capturing all child process creation and logging the
+relevant information about it into separate files in a specified directory.
+The parameter of this process is the output directory name, where the report
+files shall be placed. This parameter is passed as an environment variable.
+
+The module also implements compiler wrappers to intercept the compiler calls.
+
+The module implements the build command execution and the post-processing of
+the output files, which will condensates into a compilation database. """
+
+import sys
+import os
+import os.path
+import re
+import itertools
+import json
+import glob
+import argparse
+import logging
+import subprocess
+from libear import build_libear, TemporaryDirectory
+from libscanbuild import duplicate_check, tempdir, initialize_logging
+from libscanbuild import command_entry_point
+from libscanbuild.command import Action, classify_parameters
+from libscanbuild.shell import encode, decode
+
+__all__ = ['capture', 'intercept_build_main', 'intercept_build_wrapper']
+
+GS = chr(0x1d)
+RS = chr(0x1e)
+US = chr(0x1f)
+
+COMPILER_WRAPPER_CC = 'intercept-cc'
+COMPILER_WRAPPER_CXX = 'intercept-c++'
+
+
+@command_entry_point
+def intercept_build_main(bin_dir):
+ """ Entry point for 'intercept-build' command. """
+
+ parser = create_parser()
+ args = parser.parse_args()
+
+ initialize_logging(args.verbose)
+ logging.debug('Parsed arguments: %s', args)
+
+ if not args.build:
+ parser.print_help()
+ return 0
+
+ return capture(args, bin_dir)
+
+
+def capture(args, bin_dir):
+ """ The entry point of build command interception. """
+
+ def post_processing(commands):
+ """ To make a compilation database, it needs to filter out commands
+ which are not compiler calls. Needs to find the source file name
+ from the arguments. And do shell escaping on the command.
+
+ To support incremental builds, it is desired to read elements from
+ an existing compilation database from a previous run. These elemets
+ shall be merged with the new elements. """
+
+ # create entries from the current run
+ current = itertools.chain.from_iterable(
+ # creates a sequence of entry generators from an exec,
+ # but filter out non compiler calls before.
+ (format_entry(x) for x in commands if is_compiler_call(x)))
+ # read entries from previous run
+ if 'append' in args and args.append and os.path.exists(args.cdb):
+ with open(args.cdb) as handle:
+ previous = iter(json.load(handle))
+ else:
+ previous = iter([])
+ # filter out duplicate entries from both
+ duplicate = duplicate_check(entry_hash)
+ return (entry for entry in itertools.chain(previous, current)
+ if os.path.exists(entry['file']) and not duplicate(entry))
+
+ with TemporaryDirectory(prefix='intercept-', dir=tempdir()) as tmp_dir:
+ # run the build command
+ environment = setup_environment(args, tmp_dir, bin_dir)
+ logging.debug('run build in environment: %s', environment)
+ exit_code = subprocess.call(args.build, env=environment)
+ logging.info('build finished with exit code: %d', exit_code)
+ # read the intercepted exec calls
+ commands = itertools.chain.from_iterable(
+ parse_exec_trace(os.path.join(tmp_dir, filename))
+ for filename in sorted(glob.iglob(os.path.join(tmp_dir, '*.cmd'))))
+ # do post processing only if that was requested
+ if 'raw_entries' not in args or not args.raw_entries:
+ entries = post_processing(commands)
+ else:
+ entries = commands
+ # dump the compilation database
+ with open(args.cdb, 'w+') as handle:
+ json.dump(list(entries), handle, sort_keys=True, indent=4)
+ return exit_code
+
+
+def setup_environment(args, destination, bin_dir):
+ """ Sets up the environment for the build command.
+
+ It sets the required environment variables and execute the given command.
+ The exec calls will be logged by the 'libear' preloaded library or by the
+ 'wrapper' programs. """
+
+ c_compiler = args.cc if 'cc' in args else 'cc'
+ cxx_compiler = args.cxx if 'cxx' in args else 'c++'
+
+ libear_path = None if args.override_compiler or is_preload_disabled(
+ sys.platform) else build_libear(c_compiler, destination)
+
+ environment = dict(os.environ)
+ environment.update({'INTERCEPT_BUILD_TARGET_DIR': destination})
+
+ if not libear_path:
+ logging.debug('intercept gonna use compiler wrappers')
+ environment.update({
+ 'CC': os.path.join(bin_dir, COMPILER_WRAPPER_CC),
+ 'CXX': os.path.join(bin_dir, COMPILER_WRAPPER_CXX),
+ 'INTERCEPT_BUILD_CC': c_compiler,
+ 'INTERCEPT_BUILD_CXX': cxx_compiler,
+ 'INTERCEPT_BUILD_VERBOSE': 'DEBUG' if args.verbose > 2 else 'INFO'
+ })
+ elif sys.platform == 'darwin':
+ logging.debug('intercept gonna preload libear on OSX')
+ environment.update({
+ 'DYLD_INSERT_LIBRARIES': libear_path,
+ 'DYLD_FORCE_FLAT_NAMESPACE': '1'
+ })
+ else:
+ logging.debug('intercept gonna preload libear on UNIX')
+ environment.update({'LD_PRELOAD': libear_path})
+
+ return environment
+
+
+def intercept_build_wrapper(cplusplus):
+ """ Entry point for `intercept-cc` and `intercept-c++` compiler wrappers.
+
+ It does generate execution report into target directory. And execute
+ the wrapped compilation with the real compiler. The parameters for
+ report and execution are from environment variables.
+
+ Those parameters which for 'libear' library can't have meaningful
+ values are faked. """
+
+ # initialize wrapper logging
+ logging.basicConfig(format='intercept: %(levelname)s: %(message)s',
+ level=os.getenv('INTERCEPT_BUILD_VERBOSE', 'INFO'))
+ # write report
+ try:
+ target_dir = os.getenv('INTERCEPT_BUILD_TARGET_DIR')
+ if not target_dir:
+ raise UserWarning('exec report target directory not found')
+ pid = str(os.getpid())
+ target_file = os.path.join(target_dir, pid + '.cmd')
+ logging.debug('writing exec report to: %s', target_file)
+ with open(target_file, 'ab') as handler:
+ working_dir = os.getcwd()
+ command = US.join(sys.argv) + US
+ content = RS.join([pid, pid, 'wrapper', working_dir, command]) + GS
+ handler.write(content.encode('utf-8'))
+ except IOError:
+ logging.exception('writing exec report failed')
+ except UserWarning as warning:
+ logging.warning(warning)
+ # execute with real compiler
+ compiler = os.getenv('INTERCEPT_BUILD_CXX', 'c++') if cplusplus \
+ else os.getenv('INTERCEPT_BUILD_CC', 'cc')
+ compilation = [compiler] + sys.argv[1:]
+ logging.debug('execute compiler: %s', compilation)
+ return subprocess.call(compilation)
+
+
+def parse_exec_trace(filename):
+ """ Parse the file generated by the 'libear' preloaded library.
+
+ Given filename points to a file which contains the basic report
+ generated by the interception library or wrapper command. A single
+ report file _might_ contain multiple process creation info. """
+
+ logging.debug('parse exec trace file: %s', filename)
+ with open(filename, 'r') as handler:
+ content = handler.read()
+ for group in filter(bool, content.split(GS)):
+ records = group.split(RS)
+ yield {
+ 'pid': records[0],
+ 'ppid': records[1],
+ 'function': records[2],
+ 'directory': records[3],
+ 'command': records[4].split(US)[:-1]
+ }
+
+
+def format_entry(entry):
+ """ Generate the desired fields for compilation database entries. """
+
+ def abspath(cwd, name):
+ """ Create normalized absolute path from input filename. """
+ fullname = name if os.path.isabs(name) else os.path.join(cwd, name)
+ return os.path.normpath(fullname)
+
+ logging.debug('format this command: %s', entry['command'])
+ atoms = classify_parameters(entry['command'])
+ if atoms['action'] <= Action.Compile:
+ for source in atoms['files']:
+ compiler = 'c++' if atoms['c++'] else 'cc'
+ flags = atoms['compile_options']
+ flags += ['-o', atoms['output']] if atoms['output'] else []
+ flags += ['-x', atoms['language']] if 'language' in atoms else []
+ flags += [elem
+ for arch in atoms.get('archs_seen', [])
+ for elem in ['-arch', arch]]
+ command = [compiler, '-c'] + flags + [source]
+ logging.debug('formated as: %s', command)
+ yield {
+ 'directory': entry['directory'],
+ 'command': encode(command),
+ 'file': abspath(entry['directory'], source)
+ }
+
+
+def is_compiler_call(entry):
+ """ A predicate to decide the entry is a compiler call or not. """
+
+ patterns = [
+ re.compile(r'^([^/]*/)*intercept-c(c|\+\+)$'),
+ re.compile(r'^([^/]*/)*c(c|\+\+)$'),
+ re.compile(r'^([^/]*/)*([^-]*-)*[mg](cc|\+\+)(-\d+(\.\d+){0,2})?$'),
+ re.compile(r'^([^/]*/)*([^-]*-)*clang(\+\+)?(-\d+(\.\d+){0,2})?$'),
+ re.compile(r'^([^/]*/)*llvm-g(cc|\+\+)$'),
+ ]
+ executable = entry['command'][0]
+ return any((pattern.match(executable) for pattern in patterns))
+
+
+def is_preload_disabled(platform):
+ """ Library-based interposition will fail silently if SIP is enabled,
+ so this should be detected. You can detect whether SIP is enabled on
+ Darwin by checking whether (1) there is a binary called 'csrutil' in
+ the path and, if so, (2) whether the output of executing 'csrutil status'
+ contains 'System Integrity Protection status: enabled'.
+
+ Same problem on linux when SELinux is enabled. The status query program
+ 'sestatus' and the output when it's enabled 'SELinux status: enabled'. """
+
+ if platform == 'darwin':
+ pattern = re.compile(r'System Integrity Protection status:\s+enabled')
+ command = ['csrutil', 'status']
+ elif platform in {'linux', 'linux2'}:
+ pattern = re.compile(r'SELinux status:\s+enabled')
+ command = ['sestatus']
+ else:
+ return False
+
+ try:
+ lines = subprocess.check_output(command).decode('utf-8')
+ return any((pattern.match(line) for line in lines.splitlines()))
+ except:
+ return False
+
+
+def entry_hash(entry):
+ """ Implement unique hash method for compilation database entries. """
+
+ # For faster lookup in set filename is reverted
+ filename = entry['file'][::-1]
+ # For faster lookup in set directory is reverted
+ directory = entry['directory'][::-1]
+ # On OS X the 'cc' and 'c++' compilers are wrappers for
+ # 'clang' therefore both call would be logged. To avoid
+ # this the hash does not contain the first word of the
+ # command.
+ command = ' '.join(decode(entry['command'])[1:])
+
+ return '<>'.join([filename, directory, command])
+
+
+def create_parser():
+ """ Command line argument parser factory method. """
+
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+
+ parser.add_argument(
+ '--verbose', '-v',
+ action='count',
+ default=0,
+ help="""Enable verbose output from '%(prog)s'. A second and third
+ flag increases verbosity.""")
+ parser.add_argument(
+ '--cdb',
+ metavar='<file>',
+ default="compile_commands.json",
+ help="""The JSON compilation database.""")
+ group = parser.add_mutually_exclusive_group()
+ group.add_argument(
+ '--append',
+ action='store_true',
+ help="""Append new entries to existing compilation database.""")
+ group.add_argument(
+ '--disable-filter', '-n',
+ dest='raw_entries',
+ action='store_true',
+ help="""Intercepted child process creation calls (exec calls) are all
+ logged to the output. The output is not a compilation database.
+ This flag is for debug purposes.""")
+
+ advanced = parser.add_argument_group('advanced options')
+ advanced.add_argument(
+ '--override-compiler',
+ action='store_true',
+ help="""Always resort to the compiler wrapper even when better
+ intercept methods are available.""")
+ advanced.add_argument(
+ '--use-cc',
+ metavar='<path>',
+ dest='cc',
+ default='cc',
+ help="""When '%(prog)s' analyzes a project by interposing a compiler
+ wrapper, which executes a real compiler for compilation and
+ do other tasks (record the compiler invocation). Because of
+ this interposing, '%(prog)s' does not know what compiler your
+ project normally uses. Instead, it simply overrides the CC
+ environment variable, and guesses your default compiler.
+
+ If you need '%(prog)s' to use a specific compiler for
+ *compilation* then you can use this option to specify a path
+ to that compiler.""")
+ advanced.add_argument(
+ '--use-c++',
+ metavar='<path>',
+ dest='cxx',
+ default='c++',
+ help="""This is the same as "--use-cc" but for C++ code.""")
+
+ parser.add_argument(
+ dest='build',
+ nargs=argparse.REMAINDER,
+ help="""Command to run.""")
+
+ return parser
diff --git a/tools/scan-build-py/libscanbuild/report.py b/tools/scan-build-py/libscanbuild/report.py
new file mode 100644
index 000000000000..efc0a55de619
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/report.py
@@ -0,0 +1,530 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module is responsible to generate 'index.html' for the report.
+
+The input for this step is the output directory, where individual reports
+could be found. It parses those reports and generates 'index.html'. """
+
+import re
+import os
+import os.path
+import sys
+import shutil
+import time
+import tempfile
+import itertools
+import plistlib
+import glob
+import json
+import logging
+import contextlib
+from libscanbuild import duplicate_check
+from libscanbuild.clang import get_version
+
+__all__ = ['report_directory', 'document']
+
+
+@contextlib.contextmanager
+def report_directory(hint, keep):
+ """ Responsible for the report directory.
+
+ hint -- could specify the parent directory of the output directory.
+ keep -- a boolean value to keep or delete the empty report directory. """
+
+ stamp = time.strftime('scan-build-%Y-%m-%d-%H%M%S-', time.localtime())
+ name = tempfile.mkdtemp(prefix=stamp, dir=hint)
+
+ logging.info('Report directory created: %s', name)
+
+ try:
+ yield name
+ finally:
+ if os.listdir(name):
+ msg = "Run 'scan-view %s' to examine bug reports."
+ keep = True
+ else:
+ if keep:
+ msg = "Report directory '%s' contans no report, but kept."
+ else:
+ msg = "Removing directory '%s' because it contains no report."
+ logging.warning(msg, name)
+
+ if not keep:
+ os.rmdir(name)
+
+
+def document(args, output_dir, use_cdb):
+ """ Generates cover report and returns the number of bugs/crashes. """
+
+ html_reports_available = args.output_format in {'html', 'plist-html'}
+
+ logging.debug('count crashes and bugs')
+ crash_count = sum(1 for _ in read_crashes(output_dir))
+ bug_counter = create_counters()
+ for bug in read_bugs(output_dir, html_reports_available):
+ bug_counter(bug)
+ result = crash_count + bug_counter.total
+
+ if html_reports_available and result:
+ logging.debug('generate index.html file')
+ # common prefix for source files to have sort filenames
+ prefix = commonprefix_from(args.cdb) if use_cdb else os.getcwd()
+ # assemble the cover from multiple fragments
+ try:
+ fragments = []
+ if bug_counter.total:
+ fragments.append(bug_summary(output_dir, bug_counter))
+ fragments.append(bug_report(output_dir, prefix))
+ if crash_count:
+ fragments.append(crash_report(output_dir, prefix))
+ assemble_cover(output_dir, prefix, args, fragments)
+ # copy additinal files to the report
+ copy_resource_files(output_dir)
+ if use_cdb:
+ shutil.copy(args.cdb, output_dir)
+ finally:
+ for fragment in fragments:
+ os.remove(fragment)
+ return result
+
+
+def assemble_cover(output_dir, prefix, args, fragments):
+ """ Put together the fragments into a final report. """
+
+ import getpass
+ import socket
+ import datetime
+
+ if args.html_title is None:
+ args.html_title = os.path.basename(prefix) + ' - analyzer results'
+
+ with open(os.path.join(output_dir, 'index.html'), 'w') as handle:
+ indent = 0
+ handle.write(reindent("""
+ |<!DOCTYPE html>
+ |<html>
+ | <head>
+ | <title>{html_title}</title>
+ | <link type="text/css" rel="stylesheet" href="scanview.css"/>
+ | <script type='text/javascript' src="sorttable.js"></script>
+ | <script type='text/javascript' src='selectable.js'></script>
+ | </head>""", indent).format(html_title=args.html_title))
+ handle.write(comment('SUMMARYENDHEAD'))
+ handle.write(reindent("""
+ | <body>
+ | <h1>{html_title}</h1>
+ | <table>
+ | <tr><th>User:</th><td>{user_name}@{host_name}</td></tr>
+ | <tr><th>Working Directory:</th><td>{current_dir}</td></tr>
+ | <tr><th>Command Line:</th><td>{cmd_args}</td></tr>
+ | <tr><th>Clang Version:</th><td>{clang_version}</td></tr>
+ | <tr><th>Date:</th><td>{date}</td></tr>
+ | </table>""", indent).format(html_title=args.html_title,
+ user_name=getpass.getuser(),
+ host_name=socket.gethostname(),
+ current_dir=prefix,
+ cmd_args=' '.join(sys.argv),
+ clang_version=get_version(args.clang),
+ date=datetime.datetime.today(
+ ).strftime('%c')))
+ for fragment in fragments:
+ # copy the content of fragments
+ with open(fragment, 'r') as input_handle:
+ shutil.copyfileobj(input_handle, handle)
+ handle.write(reindent("""
+ | </body>
+ |</html>""", indent))
+
+
+def bug_summary(output_dir, bug_counter):
+ """ Bug summary is a HTML table to give a better overview of the bugs. """
+
+ name = os.path.join(output_dir, 'summary.html.fragment')
+ with open(name, 'w') as handle:
+ indent = 4
+ handle.write(reindent("""
+ |<h2>Bug Summary</h2>
+ |<table>
+ | <thead>
+ | <tr>
+ | <td>Bug Type</td>
+ | <td>Quantity</td>
+ | <td class="sorttable_nosort">Display?</td>
+ | </tr>
+ | </thead>
+ | <tbody>""", indent))
+ handle.write(reindent("""
+ | <tr style="font-weight:bold">
+ | <td class="SUMM_DESC">All Bugs</td>
+ | <td class="Q">{0}</td>
+ | <td>
+ | <center>
+ | <input checked type="checkbox" id="AllBugsCheck"
+ | onClick="CopyCheckedStateToCheckButtons(this);"/>
+ | </center>
+ | </td>
+ | </tr>""", indent).format(bug_counter.total))
+ for category, types in bug_counter.categories.items():
+ handle.write(reindent("""
+ | <tr>
+ | <th>{0}</th><th colspan=2></th>
+ | </tr>""", indent).format(category))
+ for bug_type in types.values():
+ handle.write(reindent("""
+ | <tr>
+ | <td class="SUMM_DESC">{bug_type}</td>
+ | <td class="Q">{bug_count}</td>
+ | <td>
+ | <center>
+ | <input checked type="checkbox"
+ | onClick="ToggleDisplay(this,'{bug_type_class}');"/>
+ | </center>
+ | </td>
+ | </tr>""", indent).format(**bug_type))
+ handle.write(reindent("""
+ | </tbody>
+ |</table>""", indent))
+ handle.write(comment('SUMMARYBUGEND'))
+ return name
+
+
+def bug_report(output_dir, prefix):
+ """ Creates a fragment from the analyzer reports. """
+
+ pretty = prettify_bug(prefix, output_dir)
+ bugs = (pretty(bug) for bug in read_bugs(output_dir, True))
+
+ name = os.path.join(output_dir, 'bugs.html.fragment')
+ with open(name, 'w') as handle:
+ indent = 4
+ handle.write(reindent("""
+ |<h2>Reports</h2>
+ |<table class="sortable" style="table-layout:automatic">
+ | <thead>
+ | <tr>
+ | <td>Bug Group</td>
+ | <td class="sorttable_sorted">
+ | Bug Type
+ | <span id="sorttable_sortfwdind">&nbsp;&#x25BE;</span>
+ | </td>
+ | <td>File</td>
+ | <td>Function/Method</td>
+ | <td class="Q">Line</td>
+ | <td class="Q">Path Length</td>
+ | <td class="sorttable_nosort"></td>
+ | </tr>
+ | </thead>
+ | <tbody>""", indent))
+ handle.write(comment('REPORTBUGCOL'))
+ for current in bugs:
+ handle.write(reindent("""
+ | <tr class="{bug_type_class}">
+ | <td class="DESC">{bug_category}</td>
+ | <td class="DESC">{bug_type}</td>
+ | <td>{bug_file}</td>
+ | <td class="DESC">{bug_function}</td>
+ | <td class="Q">{bug_line}</td>
+ | <td class="Q">{bug_path_length}</td>
+ | <td><a href="{report_file}#EndPath">View Report</a></td>
+ | </tr>""", indent).format(**current))
+ handle.write(comment('REPORTBUG', {'id': current['report_file']}))
+ handle.write(reindent("""
+ | </tbody>
+ |</table>""", indent))
+ handle.write(comment('REPORTBUGEND'))
+ return name
+
+
+def crash_report(output_dir, prefix):
+ """ Creates a fragment from the compiler crashes. """
+
+ pretty = prettify_crash(prefix, output_dir)
+ crashes = (pretty(crash) for crash in read_crashes(output_dir))
+
+ name = os.path.join(output_dir, 'crashes.html.fragment')
+ with open(name, 'w') as handle:
+ indent = 4
+ handle.write(reindent("""
+ |<h2>Analyzer Failures</h2>
+ |<p>The analyzer had problems processing the following files:</p>
+ |<table>
+ | <thead>
+ | <tr>
+ | <td>Problem</td>
+ | <td>Source File</td>
+ | <td>Preprocessed File</td>
+ | <td>STDERR Output</td>
+ | </tr>
+ | </thead>
+ | <tbody>""", indent))
+ for current in crashes:
+ handle.write(reindent("""
+ | <tr>
+ | <td>{problem}</td>
+ | <td>{source}</td>
+ | <td><a href="{file}">preprocessor output</a></td>
+ | <td><a href="{stderr}">analyzer std err</a></td>
+ | </tr>""", indent).format(**current))
+ handle.write(comment('REPORTPROBLEM', current))
+ handle.write(reindent("""
+ | </tbody>
+ |</table>""", indent))
+ handle.write(comment('REPORTCRASHES'))
+ return name
+
+
+def read_crashes(output_dir):
+ """ Generate a unique sequence of crashes from given output directory. """
+
+ return (parse_crash(filename)
+ for filename in glob.iglob(os.path.join(output_dir, 'failures',
+ '*.info.txt')))
+
+
+def read_bugs(output_dir, html):
+ """ Generate a unique sequence of bugs from given output directory.
+
+ Duplicates can be in a project if the same module was compiled multiple
+ times with different compiler options. These would be better to show in
+ the final report (cover) only once. """
+
+ parser = parse_bug_html if html else parse_bug_plist
+ pattern = '*.html' if html else '*.plist'
+
+ duplicate = duplicate_check(
+ lambda bug: '{bug_line}.{bug_path_length}:{bug_file}'.format(**bug))
+
+ bugs = itertools.chain.from_iterable(
+ # parser creates a bug generator not the bug itself
+ parser(filename)
+ for filename in glob.iglob(os.path.join(output_dir, pattern)))
+
+ return (bug for bug in bugs if not duplicate(bug))
+
+
+def parse_bug_plist(filename):
+ """ Returns the generator of bugs from a single .plist file. """
+
+ content = plistlib.readPlist(filename)
+ files = content.get('files')
+ for bug in content.get('diagnostics', []):
+ if len(files) <= int(bug['location']['file']):
+ logging.warning('Parsing bug from "%s" failed', filename)
+ continue
+
+ yield {
+ 'result': filename,
+ 'bug_type': bug['type'],
+ 'bug_category': bug['category'],
+ 'bug_line': int(bug['location']['line']),
+ 'bug_path_length': int(bug['location']['col']),
+ 'bug_file': files[int(bug['location']['file'])]
+ }
+
+
+def parse_bug_html(filename):
+ """ Parse out the bug information from HTML output. """
+
+ patterns = [re.compile(r'<!-- BUGTYPE (?P<bug_type>.*) -->$'),
+ re.compile(r'<!-- BUGFILE (?P<bug_file>.*) -->$'),
+ re.compile(r'<!-- BUGPATHLENGTH (?P<bug_path_length>.*) -->$'),
+ re.compile(r'<!-- BUGLINE (?P<bug_line>.*) -->$'),
+ re.compile(r'<!-- BUGCATEGORY (?P<bug_category>.*) -->$'),
+ re.compile(r'<!-- BUGDESC (?P<bug_description>.*) -->$'),
+ re.compile(r'<!-- FUNCTIONNAME (?P<bug_function>.*) -->$')]
+ endsign = re.compile(r'<!-- BUGMETAEND -->')
+
+ bug = {
+ 'report_file': filename,
+ 'bug_function': 'n/a', # compatibility with < clang-3.5
+ 'bug_category': 'Other',
+ 'bug_line': 0,
+ 'bug_path_length': 1
+ }
+
+ with open(filename) as handler:
+ for line in handler.readlines():
+ # do not read the file further
+ if endsign.match(line):
+ break
+ # search for the right lines
+ for regex in patterns:
+ match = regex.match(line.strip())
+ if match:
+ bug.update(match.groupdict())
+ break
+
+ encode_value(bug, 'bug_line', int)
+ encode_value(bug, 'bug_path_length', int)
+
+ yield bug
+
+
+def parse_crash(filename):
+ """ Parse out the crash information from the report file. """
+
+ match = re.match(r'(.*)\.info\.txt', filename)
+ name = match.group(1) if match else None
+ with open(filename) as handler:
+ lines = handler.readlines()
+ return {
+ 'source': lines[0].rstrip(),
+ 'problem': lines[1].rstrip(),
+ 'file': name,
+ 'info': name + '.info.txt',
+ 'stderr': name + '.stderr.txt'
+ }
+
+
+def category_type_name(bug):
+ """ Create a new bug attribute from bug by category and type.
+
+ The result will be used as CSS class selector in the final report. """
+
+ def smash(key):
+ """ Make value ready to be HTML attribute value. """
+
+ return bug.get(key, '').lower().replace(' ', '_').replace("'", '')
+
+ return escape('bt_' + smash('bug_category') + '_' + smash('bug_type'))
+
+
+def create_counters():
+ """ Create counters for bug statistics.
+
+ Two entries are maintained: 'total' is an integer, represents the
+ number of bugs. The 'categories' is a two level categorisation of bug
+ counters. The first level is 'bug category' the second is 'bug type'.
+ Each entry in this classification is a dictionary of 'count', 'type'
+ and 'label'. """
+
+ def predicate(bug):
+ bug_category = bug['bug_category']
+ bug_type = bug['bug_type']
+ current_category = predicate.categories.get(bug_category, dict())
+ current_type = current_category.get(bug_type, {
+ 'bug_type': bug_type,
+ 'bug_type_class': category_type_name(bug),
+ 'bug_count': 0
+ })
+ current_type.update({'bug_count': current_type['bug_count'] + 1})
+ current_category.update({bug_type: current_type})
+ predicate.categories.update({bug_category: current_category})
+ predicate.total += 1
+
+ predicate.total = 0
+ predicate.categories = dict()
+ return predicate
+
+
+def prettify_bug(prefix, output_dir):
+ def predicate(bug):
+ """ Make safe this values to embed into HTML. """
+
+ bug['bug_type_class'] = category_type_name(bug)
+
+ encode_value(bug, 'bug_file', lambda x: escape(chop(prefix, x)))
+ encode_value(bug, 'bug_category', escape)
+ encode_value(bug, 'bug_type', escape)
+ encode_value(bug, 'report_file', lambda x: escape(chop(output_dir, x)))
+ return bug
+
+ return predicate
+
+
+def prettify_crash(prefix, output_dir):
+ def predicate(crash):
+ """ Make safe this values to embed into HTML. """
+
+ encode_value(crash, 'source', lambda x: escape(chop(prefix, x)))
+ encode_value(crash, 'problem', escape)
+ encode_value(crash, 'file', lambda x: escape(chop(output_dir, x)))
+ encode_value(crash, 'info', lambda x: escape(chop(output_dir, x)))
+ encode_value(crash, 'stderr', lambda x: escape(chop(output_dir, x)))
+ return crash
+
+ return predicate
+
+
+def copy_resource_files(output_dir):
+ """ Copy the javascript and css files to the report directory. """
+
+ this_dir = os.path.dirname(os.path.realpath(__file__))
+ for resource in os.listdir(os.path.join(this_dir, 'resources')):
+ shutil.copy(os.path.join(this_dir, 'resources', resource), output_dir)
+
+
+def encode_value(container, key, encode):
+ """ Run 'encode' on 'container[key]' value and update it. """
+
+ if key in container:
+ value = encode(container[key])
+ container.update({key: value})
+
+
+def chop(prefix, filename):
+ """ Create 'filename' from '/prefix/filename' """
+
+ return filename if not len(prefix) else os.path.relpath(filename, prefix)
+
+
+def escape(text):
+ """ Paranoid HTML escape method. (Python version independent) """
+
+ escape_table = {
+ '&': '&amp;',
+ '"': '&quot;',
+ "'": '&apos;',
+ '>': '&gt;',
+ '<': '&lt;'
+ }
+ return ''.join(escape_table.get(c, c) for c in text)
+
+
+def reindent(text, indent):
+ """ Utility function to format html output and keep indentation. """
+
+ result = ''
+ for line in text.splitlines():
+ if len(line.strip()):
+ result += ' ' * indent + line.split('|')[1] + os.linesep
+ return result
+
+
+def comment(name, opts=dict()):
+ """ Utility function to format meta information as comment. """
+
+ attributes = ''
+ for key, value in opts.items():
+ attributes += ' {0}="{1}"'.format(key, value)
+
+ return '<!-- {0}{1} -->{2}'.format(name, attributes, os.linesep)
+
+
+def commonprefix_from(filename):
+ """ Create file prefix from a compilation database entries. """
+
+ with open(filename, 'r') as handle:
+ return commonprefix(item['file'] for item in json.load(handle))
+
+
+def commonprefix(files):
+ """ Fixed version of os.path.commonprefix. Return the longest path prefix
+ that is a prefix of all paths in filenames. """
+
+ result = None
+ for current in files:
+ if result is not None:
+ result = os.path.commonprefix([result, current])
+ else:
+ result = current
+
+ if result is None:
+ return ''
+ elif not os.path.isdir(result):
+ return os.path.dirname(result)
+ else:
+ return os.path.abspath(result)
diff --git a/tools/scan-build-py/libscanbuild/resources/scanview.css b/tools/scan-build-py/libscanbuild/resources/scanview.css
new file mode 100644
index 000000000000..cf8a5a6ad470
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/resources/scanview.css
@@ -0,0 +1,62 @@
+body { color:#000000; background-color:#ffffff }
+body { font-family: Helvetica, sans-serif; font-size:9pt }
+h1 { font-size: 14pt; }
+h2 { font-size: 12pt; }
+table { font-size:9pt }
+table { border-spacing: 0px; border: 1px solid black }
+th, table thead {
+ background-color:#eee; color:#666666;
+ font-weight: bold; cursor: default;
+ text-align:center;
+ font-weight: bold; font-family: Verdana;
+ white-space:nowrap;
+}
+.W { font-size:0px }
+th, td { padding:5px; padding-left:8px; text-align:left }
+td.SUMM_DESC { padding-left:12px }
+td.DESC { white-space:pre }
+td.Q { text-align:right }
+td { text-align:left }
+tbody.scrollContent { overflow:auto }
+
+table.form_group {
+ background-color: #ccc;
+ border: 1px solid #333;
+ padding: 2px;
+}
+
+table.form_inner_group {
+ background-color: #ccc;
+ border: 1px solid #333;
+ padding: 0px;
+}
+
+table.form {
+ background-color: #999;
+ border: 1px solid #333;
+ padding: 2px;
+}
+
+td.form_label {
+ text-align: right;
+ vertical-align: top;
+}
+/* For one line entires */
+td.form_clabel {
+ text-align: right;
+ vertical-align: center;
+}
+td.form_value {
+ text-align: left;
+ vertical-align: top;
+}
+td.form_submit {
+ text-align: right;
+ vertical-align: top;
+}
+
+h1.SubmitFail {
+ color: #f00;
+}
+h1.SubmitOk {
+}
diff --git a/tools/scan-build-py/libscanbuild/resources/selectable.js b/tools/scan-build-py/libscanbuild/resources/selectable.js
new file mode 100644
index 000000000000..53f6a8da13d8
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/resources/selectable.js
@@ -0,0 +1,47 @@
+function SetDisplay(RowClass, DisplayVal)
+{
+ var Rows = document.getElementsByTagName("tr");
+ for ( var i = 0 ; i < Rows.length; ++i ) {
+ if (Rows[i].className == RowClass) {
+ Rows[i].style.display = DisplayVal;
+ }
+ }
+}
+
+function CopyCheckedStateToCheckButtons(SummaryCheckButton) {
+ var Inputs = document.getElementsByTagName("input");
+ for ( var i = 0 ; i < Inputs.length; ++i ) {
+ if (Inputs[i].type == "checkbox") {
+ if(Inputs[i] != SummaryCheckButton) {
+ Inputs[i].checked = SummaryCheckButton.checked;
+ Inputs[i].onclick();
+ }
+ }
+ }
+}
+
+function returnObjById( id ) {
+ if (document.getElementById)
+ var returnVar = document.getElementById(id);
+ else if (document.all)
+ var returnVar = document.all[id];
+ else if (document.layers)
+ var returnVar = document.layers[id];
+ return returnVar;
+}
+
+var NumUnchecked = 0;
+
+function ToggleDisplay(CheckButton, ClassName) {
+ if (CheckButton.checked) {
+ SetDisplay(ClassName, "");
+ if (--NumUnchecked == 0) {
+ returnObjById("AllBugsCheck").checked = true;
+ }
+ }
+ else {
+ SetDisplay(ClassName, "none");
+ NumUnchecked++;
+ returnObjById("AllBugsCheck").checked = false;
+ }
+}
diff --git a/tools/scan-build-py/libscanbuild/resources/sorttable.js b/tools/scan-build-py/libscanbuild/resources/sorttable.js
new file mode 100644
index 000000000000..32faa078d899
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/resources/sorttable.js
@@ -0,0 +1,492 @@
+/*
+ SortTable
+ version 2
+ 7th April 2007
+ Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/
+
+ Instructions:
+ Download this file
+ Add <script src="sorttable.js"></script> to your HTML
+ Add class="sortable" to any table you'd like to make sortable
+ Click on the headers to sort
+
+ Thanks to many, many people for contributions and suggestions.
+ Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
+ This basically means: do what you want with it.
+*/
+
+
+var stIsIE = /*@cc_on!@*/false;
+
+sorttable = {
+ init: function() {
+ // quit if this function has already been called
+ if (arguments.callee.done) return;
+ // flag this function so we don't do the same thing twice
+ arguments.callee.done = true;
+ // kill the timer
+ if (_timer) clearInterval(_timer);
+
+ if (!document.createElement || !document.getElementsByTagName) return;
+
+ sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
+
+ forEach(document.getElementsByTagName('table'), function(table) {
+ if (table.className.search(/\bsortable\b/) != -1) {
+ sorttable.makeSortable(table);
+ }
+ });
+
+ },
+
+ makeSortable: function(table) {
+ if (table.getElementsByTagName('thead').length == 0) {
+ // table doesn't have a tHead. Since it should have, create one and
+ // put the first table row in it.
+ the = document.createElement('thead');
+ the.appendChild(table.rows[0]);
+ table.insertBefore(the,table.firstChild);
+ }
+ // Safari doesn't support table.tHead, sigh
+ if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0];
+
+ if (table.tHead.rows.length != 1) return; // can't cope with two header rows
+
+ // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
+ // "total" rows, for example). This is B&R, since what you're supposed
+ // to do is put them in a tfoot. So, if there are sortbottom rows,
+ // for backward compatibility, move them to tfoot (creating it if needed).
+ sortbottomrows = [];
+ for (var i=0; i<table.rows.length; i++) {
+ if (table.rows[i].className.search(/\bsortbottom\b/) != -1) {
+ sortbottomrows[sortbottomrows.length] = table.rows[i];
+ }
+ }
+ if (sortbottomrows) {
+ if (table.tFoot == null) {
+ // table doesn't have a tfoot. Create one.
+ tfo = document.createElement('tfoot');
+ table.appendChild(tfo);
+ }
+ for (var i=0; i<sortbottomrows.length; i++) {
+ tfo.appendChild(sortbottomrows[i]);
+ }
+ delete sortbottomrows;
+ }
+
+ // work through each column and calculate its type
+ headrow = table.tHead.rows[0].cells;
+ for (var i=0; i<headrow.length; i++) {
+ // manually override the type with a sorttable_type attribute
+ if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col
+ mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
+ if (mtch) { override = mtch[1]; }
+ if (mtch && typeof sorttable["sort_"+override] == 'function') {
+ headrow[i].sorttable_sortfunction = sorttable["sort_"+override];
+ } else {
+ headrow[i].sorttable_sortfunction = sorttable.guessType(table,i);
+ }
+ // make it clickable to sort
+ headrow[i].sorttable_columnindex = i;
+ headrow[i].sorttable_tbody = table.tBodies[0];
+ dean_addEvent(headrow[i],"click", function(e) {
+
+ if (this.className.search(/\bsorttable_sorted\b/) != -1) {
+ // if we're already sorted by this column, just
+ // reverse the table, which is quicker
+ sorttable.reverse(this.sorttable_tbody);
+ this.className = this.className.replace('sorttable_sorted',
+ 'sorttable_sorted_reverse');
+ this.removeChild(document.getElementById('sorttable_sortfwdind'));
+ sortrevind = document.createElement('span');
+ sortrevind.id = "sorttable_sortrevind";
+ sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25B4;';
+ this.appendChild(sortrevind);
+ return;
+ }
+ if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
+ // if we're already sorted by this column in reverse, just
+ // re-reverse the table, which is quicker
+ sorttable.reverse(this.sorttable_tbody);
+ this.className = this.className.replace('sorttable_sorted_reverse',
+ 'sorttable_sorted');
+ this.removeChild(document.getElementById('sorttable_sortrevind'));
+ sortfwdind = document.createElement('span');
+ sortfwdind.id = "sorttable_sortfwdind";
+ sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
+ this.appendChild(sortfwdind);
+ return;
+ }
+
+ // remove sorttable_sorted classes
+ theadrow = this.parentNode;
+ forEach(theadrow.childNodes, function(cell) {
+ if (cell.nodeType == 1) { // an element
+ cell.className = cell.className.replace('sorttable_sorted_reverse','');
+ cell.className = cell.className.replace('sorttable_sorted','');
+ }
+ });
+ sortfwdind = document.getElementById('sorttable_sortfwdind');
+ if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); }
+ sortrevind = document.getElementById('sorttable_sortrevind');
+ if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); }
+
+ this.className += ' sorttable_sorted';
+ sortfwdind = document.createElement('span');
+ sortfwdind.id = "sorttable_sortfwdind";
+ sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
+ this.appendChild(sortfwdind);
+
+ // build an array to sort. This is a Schwartzian transform thing,
+ // i.e., we "decorate" each row with the actual sort key,
+ // sort based on the sort keys, and then put the rows back in order
+ // which is a lot faster because you only do getInnerText once per row
+ row_array = [];
+ col = this.sorttable_columnindex;
+ rows = this.sorttable_tbody.rows;
+ for (var j=0; j<rows.length; j++) {
+ row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]];
+ }
+ /* If you want a stable sort, uncomment the following line */
+ sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
+ /* and comment out this one */
+ //row_array.sort(this.sorttable_sortfunction);
+
+ tb = this.sorttable_tbody;
+ for (var j=0; j<row_array.length; j++) {
+ tb.appendChild(row_array[j][1]);
+ }
+
+ delete row_array;
+ });
+ }
+ }
+ },
+
+ guessType: function(table, column) {
+ // guess the type of a column based on its first non-blank row
+ sortfn = sorttable.sort_alpha;
+ for (var i=0; i<table.tBodies[0].rows.length; i++) {
+ text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
+ if (text != '') {
+ if (text.match(/^-?[£$¤]?[\d,.]+%?$/)) {
+ return sorttable.sort_numeric;
+ }
+ // check for a date: dd/mm/yyyy or dd/mm/yy
+ // can have / or . or - as separator
+ // can be mm/dd as well
+ possdate = text.match(sorttable.DATE_RE)
+ if (possdate) {
+ // looks like a date
+ first = parseInt(possdate[1]);
+ second = parseInt(possdate[2]);
+ if (first > 12) {
+ // definitely dd/mm
+ return sorttable.sort_ddmm;
+ } else if (second > 12) {
+ return sorttable.sort_mmdd;
+ } else {
+ // looks like a date, but we can't tell which, so assume
+ // that it's dd/mm (English imperialism!) and keep looking
+ sortfn = sorttable.sort_ddmm;
+ }
+ }
+ }
+ }
+ return sortfn;
+ },
+
+ getInnerText: function(node) {
+ // gets the text we want to use for sorting for a cell.
+ // strips leading and trailing whitespace.
+ // this is *not* a generic getInnerText function; it's special to sorttable.
+ // for example, you can override the cell text with a customkey attribute.
+ // it also gets .value for <input> fields.
+
+ hasInputs = (typeof node.getElementsByTagName == 'function') &&
+ node.getElementsByTagName('input').length;
+
+ if (node.getAttribute("sorttable_customkey") != null) {
+ return node.getAttribute("sorttable_customkey");
+ }
+ else if (typeof node.textContent != 'undefined' && !hasInputs) {
+ return node.textContent.replace(/^\s+|\s+$/g, '');
+ }
+ else if (typeof node.innerText != 'undefined' && !hasInputs) {
+ return node.innerText.replace(/^\s+|\s+$/g, '');
+ }
+ else if (typeof node.text != 'undefined' && !hasInputs) {
+ return node.text.replace(/^\s+|\s+$/g, '');
+ }
+ else {
+ switch (node.nodeType) {
+ case 3:
+ if (node.nodeName.toLowerCase() == 'input') {
+ return node.value.replace(/^\s+|\s+$/g, '');
+ }
+ case 4:
+ return node.nodeValue.replace(/^\s+|\s+$/g, '');
+ break;
+ case 1:
+ case 11:
+ var innerText = '';
+ for (var i = 0; i < node.childNodes.length; i++) {
+ innerText += sorttable.getInnerText(node.childNodes[i]);
+ }
+ return innerText.replace(/^\s+|\s+$/g, '');
+ break;
+ default:
+ return '';
+ }
+ }
+ },
+
+ reverse: function(tbody) {
+ // reverse the rows in a tbody
+ newrows = [];
+ for (var i=0; i<tbody.rows.length; i++) {
+ newrows[newrows.length] = tbody.rows[i];
+ }
+ for (var i=newrows.length-1; i>=0; i--) {
+ tbody.appendChild(newrows[i]);
+ }
+ delete newrows;
+ },
+
+ /* sort functions
+ each sort function takes two parameters, a and b
+ you are comparing a[0] and b[0] */
+ sort_numeric: function(a,b) {
+ aa = parseFloat(a[0].replace(/[^0-9.-]/g,''));
+ if (isNaN(aa)) aa = 0;
+ bb = parseFloat(b[0].replace(/[^0-9.-]/g,''));
+ if (isNaN(bb)) bb = 0;
+ return aa-bb;
+ },
+ sort_alpha: function(a,b) {
+ if (a[0]==b[0]) return 0;
+ if (a[0]<b[0]) return -1;
+ return 1;
+ },
+ sort_ddmm: function(a,b) {
+ mtch = a[0].match(sorttable.DATE_RE);
+ y = mtch[3]; m = mtch[2]; d = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt1 = y+m+d;
+ mtch = b[0].match(sorttable.DATE_RE);
+ y = mtch[3]; m = mtch[2]; d = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt2 = y+m+d;
+ if (dt1==dt2) return 0;
+ if (dt1<dt2) return -1;
+ return 1;
+ },
+ sort_mmdd: function(a,b) {
+ mtch = a[0].match(sorttable.DATE_RE);
+ y = mtch[3]; d = mtch[2]; m = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt1 = y+m+d;
+ mtch = b[0].match(sorttable.DATE_RE);
+ y = mtch[3]; d = mtch[2]; m = mtch[1];
+ if (m.length == 1) m = '0'+m;
+ if (d.length == 1) d = '0'+d;
+ dt2 = y+m+d;
+ if (dt1==dt2) return 0;
+ if (dt1<dt2) return -1;
+ return 1;
+ },
+
+ shaker_sort: function(list, comp_func) {
+ // A stable sort function to allow multi-level sorting of data
+ // see: http://en.wikipedia.org/wiki/Cocktail_sort
+ // thanks to Joseph Nahmias
+ var b = 0;
+ var t = list.length - 1;
+ var swap = true;
+
+ while(swap) {
+ swap = false;
+ for(var i = b; i < t; ++i) {
+ if ( comp_func(list[i], list[i+1]) > 0 ) {
+ var q = list[i]; list[i] = list[i+1]; list[i+1] = q;
+ swap = true;
+ }
+ } // for
+ t--;
+
+ if (!swap) break;
+
+ for(var i = t; i > b; --i) {
+ if ( comp_func(list[i], list[i-1]) < 0 ) {
+ var q = list[i]; list[i] = list[i-1]; list[i-1] = q;
+ swap = true;
+ }
+ } // for
+ b++;
+
+ } // while(swap)
+ }
+}
+
+/* ******************************************************************
+ Supporting functions: bundled here to avoid depending on a library
+ ****************************************************************** */
+
+// Dean Edwards/Matthias Miller/John Resig
+
+/* for Mozilla/Opera9 */
+if (document.addEventListener) {
+ document.addEventListener("DOMContentLoaded", sorttable.init, false);
+}
+
+/* for Internet Explorer */
+/*@cc_on @*/
+/*@if (@_win32)
+ document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
+ var script = document.getElementById("__ie_onload");
+ script.onreadystatechange = function() {
+ if (this.readyState == "complete") {
+ sorttable.init(); // call the onload handler
+ }
+ };
+/*@end @*/
+
+/* for Safari */
+if (/WebKit/i.test(navigator.userAgent)) { // sniff
+ var _timer = setInterval(function() {
+ if (/loaded|complete/.test(document.readyState)) {
+ sorttable.init(); // call the onload handler
+ }
+ }, 10);
+}
+
+/* for other browsers */
+window.onload = sorttable.init;
+
+// written by Dean Edwards, 2005
+// with input from Tino Zijdel, Matthias Miller, Diego Perini
+
+// http://dean.edwards.name/weblog/2005/10/add-event/
+
+function dean_addEvent(element, type, handler) {
+ if (element.addEventListener) {
+ element.addEventListener(type, handler, false);
+ } else {
+ // assign each event handler a unique ID
+ if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++;
+ // create a hash table of event types for the element
+ if (!element.events) element.events = {};
+ // create a hash table of event handlers for each element/event pair
+ var handlers = element.events[type];
+ if (!handlers) {
+ handlers = element.events[type] = {};
+ // store the existing event handler (if there is one)
+ if (element["on" + type]) {
+ handlers[0] = element["on" + type];
+ }
+ }
+ // store the event handler in the hash table
+ handlers[handler.$$guid] = handler;
+ // assign a global event handler to do all the work
+ element["on" + type] = handleEvent;
+ }
+};
+// a counter used to create unique IDs
+dean_addEvent.guid = 1;
+
+function removeEvent(element, type, handler) {
+ if (element.removeEventListener) {
+ element.removeEventListener(type, handler, false);
+ } else {
+ // delete the event handler from the hash table
+ if (element.events && element.events[type]) {
+ delete element.events[type][handler.$$guid];
+ }
+ }
+};
+
+function handleEvent(event) {
+ var returnValue = true;
+ // grab the event object (IE uses a global event object)
+ event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
+ // get a reference to the hash table of event handlers
+ var handlers = this.events[event.type];
+ // execute each event handler
+ for (var i in handlers) {
+ this.$$handleEvent = handlers[i];
+ if (this.$$handleEvent(event) === false) {
+ returnValue = false;
+ }
+ }
+ return returnValue;
+};
+
+function fixEvent(event) {
+ // add W3C standard event methods
+ event.preventDefault = fixEvent.preventDefault;
+ event.stopPropagation = fixEvent.stopPropagation;
+ return event;
+};
+fixEvent.preventDefault = function() {
+ this.returnValue = false;
+};
+fixEvent.stopPropagation = function() {
+ this.cancelBubble = true;
+}
+
+// Dean's forEach: http://dean.edwards.name/base/forEach.js
+/*
+ forEach, version 1.0
+ Copyright 2006, Dean Edwards
+ License: http://www.opensource.org/licenses/mit-license.php
+*/
+
+// array-like enumeration
+if (!Array.forEach) { // mozilla already supports this
+ Array.forEach = function(array, block, context) {
+ for (var i = 0; i < array.length; i++) {
+ block.call(context, array[i], i, array);
+ }
+ };
+}
+
+// generic enumeration
+Function.prototype.forEach = function(object, block, context) {
+ for (var key in object) {
+ if (typeof this.prototype[key] == "undefined") {
+ block.call(context, object[key], key, object);
+ }
+ }
+};
+
+// character enumeration
+String.forEach = function(string, block, context) {
+ Array.forEach(string.split(""), function(chr, index) {
+ block.call(context, chr, index, string);
+ });
+};
+
+// globally resolve forEach enumeration
+var forEach = function(object, block, context) {
+ if (object) {
+ var resolve = Object; // default
+ if (object instanceof Function) {
+ // functions have a "length" property
+ resolve = Function;
+ } else if (object.forEach instanceof Function) {
+ // the object implements a custom forEach method so use that
+ object.forEach(block, context);
+ return;
+ } else if (typeof object == "string") {
+ // the object is a string
+ resolve = String;
+ } else if (typeof object.length == "number") {
+ // the object is array-like
+ resolve = Array;
+ }
+ resolve.forEach(object, block, context);
+ }
+};
diff --git a/tools/scan-build-py/libscanbuild/runner.py b/tools/scan-build-py/libscanbuild/runner.py
new file mode 100644
index 000000000000..248ca90ad3e6
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/runner.py
@@ -0,0 +1,256 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module is responsible to run the analyzer commands. """
+
+import os
+import os.path
+import tempfile
+import functools
+import subprocess
+import logging
+from libscanbuild.command import classify_parameters, Action, classify_source
+from libscanbuild.clang import get_arguments, get_version
+from libscanbuild.shell import decode
+
+__all__ = ['run']
+
+
+def require(required):
+ """ Decorator for checking the required values in state.
+
+ It checks the required attributes in the passed state and stop when
+ any of those is missing. """
+
+ def decorator(function):
+ @functools.wraps(function)
+ def wrapper(*args, **kwargs):
+ for key in required:
+ if key not in args[0]:
+ raise KeyError(
+ '{0} not passed to {1}'.format(key, function.__name__))
+
+ return function(*args, **kwargs)
+
+ return wrapper
+
+ return decorator
+
+
+@require(['command', 'directory', 'file', # an entry from compilation database
+ 'clang', 'direct_args', # compiler name, and arguments from command
+ 'output_dir', 'output_format', 'output_failures'])
+def run(opts):
+ """ Entry point to run (or not) static analyzer against a single entry
+ of the compilation database.
+
+ This complex task is decomposed into smaller methods which are calling
+ each other in chain. If the analyzis is not possibe the given method
+ just return and break the chain.
+
+ The passed parameter is a python dictionary. Each method first check
+ that the needed parameters received. (This is done by the 'require'
+ decorator. It's like an 'assert' to check the contract between the
+ caller and the called method.) """
+
+ try:
+ command = opts.pop('command')
+ logging.debug("Run analyzer against '%s'", command)
+ opts.update(classify_parameters(decode(command)))
+
+ return action_check(opts)
+ except Exception:
+ logging.error("Problem occured during analyzis.", exc_info=1)
+ return None
+
+
+@require(['report', 'directory', 'clang', 'output_dir', 'language', 'file',
+ 'error_type', 'error_output', 'exit_code'])
+def report_failure(opts):
+ """ Create report when analyzer failed.
+
+ The major report is the preprocessor output. The output filename generated
+ randomly. The compiler output also captured into '.stderr.txt' file.
+ And some more execution context also saved into '.info.txt' file. """
+
+ def extension(opts):
+ """ Generate preprocessor file extension. """
+
+ mapping = {'objective-c++': '.mii', 'objective-c': '.mi', 'c++': '.ii'}
+ return mapping.get(opts['language'], '.i')
+
+ def destination(opts):
+ """ Creates failures directory if not exits yet. """
+
+ name = os.path.join(opts['output_dir'], 'failures')
+ if not os.path.isdir(name):
+ os.makedirs(name)
+ return name
+
+ error = opts['error_type']
+ (handle, name) = tempfile.mkstemp(suffix=extension(opts),
+ prefix='clang_' + error + '_',
+ dir=destination(opts))
+ os.close(handle)
+ cwd = opts['directory']
+ cmd = get_arguments([opts['clang']] + opts['report'] + ['-o', name], cwd)
+ logging.debug('exec command in %s: %s', cwd, ' '.join(cmd))
+ subprocess.call(cmd, cwd=cwd)
+
+ with open(name + '.info.txt', 'w') as handle:
+ handle.write(opts['file'] + os.linesep)
+ handle.write(error.title().replace('_', ' ') + os.linesep)
+ handle.write(' '.join(cmd) + os.linesep)
+ handle.write(' '.join(os.uname()) + os.linesep)
+ handle.write(get_version(cmd[0]))
+ handle.close()
+
+ with open(name + '.stderr.txt', 'w') as handle:
+ handle.writelines(opts['error_output'])
+ handle.close()
+
+ return {
+ 'error_output': opts['error_output'],
+ 'exit_code': opts['exit_code']
+ }
+
+
+@require(['clang', 'analyze', 'directory', 'output'])
+def run_analyzer(opts, continuation=report_failure):
+ """ It assembles the analysis command line and executes it. Capture the
+ output of the analysis and returns with it. If failure reports are
+ requested, it calls the continuation to generate it. """
+
+ cwd = opts['directory']
+ cmd = get_arguments([opts['clang']] + opts['analyze'] + opts['output'],
+ cwd)
+ logging.debug('exec command in %s: %s', cwd, ' '.join(cmd))
+ child = subprocess.Popen(cmd,
+ cwd=cwd,
+ universal_newlines=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ output = child.stdout.readlines()
+ child.stdout.close()
+ # do report details if it were asked
+ child.wait()
+ if opts.get('output_failures', False) and child.returncode:
+ error_type = 'crash' if child.returncode & 127 else 'other_error'
+ opts.update({
+ 'error_type': error_type,
+ 'error_output': output,
+ 'exit_code': child.returncode
+ })
+ return continuation(opts)
+ return {'error_output': output, 'exit_code': child.returncode}
+
+
+@require(['output_dir'])
+def set_analyzer_output(opts, continuation=run_analyzer):
+ """ Create output file if was requested.
+
+ This plays a role only if .plist files are requested. """
+
+ if opts.get('output_format') in {'plist', 'plist-html'}:
+ with tempfile.NamedTemporaryFile(prefix='report-',
+ suffix='.plist',
+ delete=False,
+ dir=opts['output_dir']) as output:
+ opts.update({'output': ['-o', output.name]})
+ return continuation(opts)
+ else:
+ opts.update({'output': ['-o', opts['output_dir']]})
+ return continuation(opts)
+
+
+@require(['file', 'directory', 'clang', 'direct_args', 'language',
+ 'output_dir', 'output_format', 'output_failures'])
+def create_commands(opts, continuation=set_analyzer_output):
+ """ Create command to run analyzer or failure report generation.
+
+ It generates commands (from compilation database entries) which contains
+ enough information to run the analyzer (and the crash report generation
+ if that was requested). """
+
+ common = []
+ if 'arch' in opts:
+ common.extend(['-arch', opts.pop('arch')])
+ common.extend(opts.pop('compile_options', []))
+ common.extend(['-x', opts['language']])
+ common.append(os.path.relpath(opts['file'], opts['directory']))
+
+ opts.update({
+ 'analyze': ['--analyze'] + opts['direct_args'] + common,
+ 'report': ['-fsyntax-only', '-E'] + common
+ })
+
+ return continuation(opts)
+
+
+@require(['file', 'c++'])
+def language_check(opts, continuation=create_commands):
+ """ Find out the language from command line parameters or file name
+ extension. The decision also influenced by the compiler invocation. """
+
+ accepteds = {
+ 'c', 'c++', 'objective-c', 'objective-c++', 'c-cpp-output',
+ 'c++-cpp-output', 'objective-c-cpp-output'
+ }
+
+ key = 'language'
+ language = opts[key] if key in opts else \
+ classify_source(opts['file'], opts['c++'])
+
+ if language is None:
+ logging.debug('skip analysis, language not known')
+ return None
+ elif language not in accepteds:
+ logging.debug('skip analysis, language not supported')
+ return None
+ else:
+ logging.debug('analysis, language: %s', language)
+ opts.update({key: language})
+ return continuation(opts)
+
+
+@require([])
+def arch_check(opts, continuation=language_check):
+ """ Do run analyzer through one of the given architectures. """
+
+ disableds = {'ppc', 'ppc64'}
+
+ key = 'archs_seen'
+ if key in opts:
+ # filter out disabled architectures and -arch switches
+ archs = [a for a in opts[key] if a not in disableds]
+
+ if not archs:
+ logging.debug('skip analysis, found not supported arch')
+ return None
+ else:
+ # There should be only one arch given (or the same multiple
+ # times). If there are multiple arch are given and are not
+ # the same, those should not change the pre-processing step.
+ # But that's the only pass we have before run the analyzer.
+ arch = archs.pop()
+ logging.debug('analysis, on arch: %s', arch)
+
+ opts.update({'arch': arch})
+ del opts[key]
+ return continuation(opts)
+ else:
+ logging.debug('analysis, on default arch')
+ return continuation(opts)
+
+
+@require(['action'])
+def action_check(opts, continuation=arch_check):
+ """ Continue analysis only if it compilation or link. """
+
+ if opts.pop('action') <= Action.Compile:
+ return continuation(opts)
+ else:
+ logging.debug('skip analysis, not compilation nor link')
+ return None
diff --git a/tools/scan-build-py/libscanbuild/shell.py b/tools/scan-build-py/libscanbuild/shell.py
new file mode 100644
index 000000000000..a575946a9540
--- /dev/null
+++ b/tools/scan-build-py/libscanbuild/shell.py
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+""" This module implements basic shell escaping/unescaping methods. """
+
+import re
+import shlex
+
+__all__ = ['encode', 'decode']
+
+
+def encode(command):
+ """ Takes a command as list and returns a string. """
+
+ def needs_quote(word):
+ """ Returns true if arguments needs to be protected by quotes.
+
+ Previous implementation was shlex.split method, but that's not good
+ for this job. Currently is running through the string with a basic
+ state checking. """
+
+ reserved = {' ', '$', '%', '&', '(', ')', '[', ']', '{', '}', '*', '|',
+ '<', '>', '@', '?', '!'}
+ state = 0
+ for current in word:
+ if state == 0 and current in reserved:
+ return True
+ elif state == 0 and current == '\\':
+ state = 1
+ elif state == 1 and current in reserved | {'\\'}:
+ state = 0
+ elif state == 0 and current == '"':
+ state = 2
+ elif state == 2 and current == '"':
+ state = 0
+ elif state == 0 and current == "'":
+ state = 3
+ elif state == 3 and current == "'":
+ state = 0
+ return state != 0
+
+ def escape(word):
+ """ Do protect argument if that's needed. """
+
+ table = {'\\': '\\\\', '"': '\\"'}
+ escaped = ''.join([table.get(c, c) for c in word])
+
+ return '"' + escaped + '"' if needs_quote(word) else escaped
+
+ return " ".join([escape(arg) for arg in command])
+
+
+def decode(string):
+ """ Takes a command string and returns as a list. """
+
+ def unescape(arg):
+ """ Gets rid of the escaping characters. """
+
+ if len(arg) >= 2 and arg[0] == arg[-1] and arg[0] == '"':
+ arg = arg[1:-1]
+ return re.sub(r'\\(["\\])', r'\1', arg)
+ return re.sub(r'\\([\\ $%&\(\)\[\]\{\}\*|<>@?!])', r'\1', arg)
+
+ return [unescape(arg) for arg in shlex.split(string)]
diff --git a/tools/scan-build-py/tests/__init__.py b/tools/scan-build-py/tests/__init__.py
new file mode 100644
index 000000000000..bde2376a6721
--- /dev/null
+++ b/tools/scan-build-py/tests/__init__.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import unittest
+
+import tests.unit
+import tests.functional.cases
+
+
+def suite():
+ loader = unittest.TestLoader()
+ suite = unittest.TestSuite()
+ suite.addTests(loader.loadTestsFromModule(tests.unit))
+ suite.addTests(loader.loadTestsFromModule(tests.functional.cases))
+ return suite
diff --git a/tools/scan-build-py/tests/functional/__init__.py b/tools/scan-build-py/tests/functional/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/__init__.py
diff --git a/tools/scan-build-py/tests/functional/cases/__init__.py b/tools/scan-build-py/tests/functional/cases/__init__.py
new file mode 100644
index 000000000000..8fb84657029a
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/cases/__init__.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import re
+import os.path
+import subprocess
+
+
+def load_tests(loader, suite, pattern):
+ from . import test_from_cdb
+ suite.addTests(loader.loadTestsFromModule(test_from_cdb))
+ from . import test_from_cmd
+ suite.addTests(loader.loadTestsFromModule(test_from_cmd))
+ from . import test_create_cdb
+ suite.addTests(loader.loadTestsFromModule(test_create_cdb))
+ from . import test_exec_anatomy
+ suite.addTests(loader.loadTestsFromModule(test_exec_anatomy))
+ return suite
+
+
+def make_args(target):
+ this_dir, _ = os.path.split(__file__)
+ path = os.path.normpath(os.path.join(this_dir, '..', 'src'))
+ return ['make', 'SRCDIR={}'.format(path), 'OBJDIR={}'.format(target), '-f',
+ os.path.join(path, 'build', 'Makefile')]
+
+
+def silent_call(cmd, *args, **kwargs):
+ kwargs.update({'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT})
+ return subprocess.call(cmd, *args, **kwargs)
+
+
+def silent_check_call(cmd, *args, **kwargs):
+ kwargs.update({'stdout': subprocess.PIPE, 'stderr': subprocess.STDOUT})
+ return subprocess.check_call(cmd, *args, **kwargs)
+
+
+def call_and_report(analyzer_cmd, build_cmd):
+ child = subprocess.Popen(analyzer_cmd + ['-v'] + build_cmd,
+ universal_newlines=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+
+ pattern = re.compile('Report directory created: (.+)')
+ directory = None
+ for line in child.stdout.readlines():
+ match = pattern.search(line)
+ if match and match.lastindex == 1:
+ directory = match.group(1)
+ break
+ child.stdout.close()
+ child.wait()
+
+ return (child.returncode, directory)
+
+
+def check_call_and_report(analyzer_cmd, build_cmd):
+ exit_code, result = call_and_report(analyzer_cmd, build_cmd)
+ if exit_code != 0:
+ raise subprocess.CalledProcessError(
+ exit_code, analyzer_cmd + build_cmd, None)
+ else:
+ return result
+
+
+def create_empty_file(filename):
+ with open(filename, 'a') as handle:
+ pass
diff --git a/tools/scan-build-py/tests/functional/cases/test_create_cdb.py b/tools/scan-build-py/tests/functional/cases/test_create_cdb.py
new file mode 100644
index 000000000000..6d449ba39c0b
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/cases/test_create_cdb.py
@@ -0,0 +1,191 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+from ...unit import fixtures
+from . import make_args, silent_check_call, silent_call, create_empty_file
+import unittest
+
+import os.path
+import json
+
+
+class CompilationDatabaseTest(unittest.TestCase):
+ @staticmethod
+ def run_intercept(tmpdir, args):
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + args
+ silent_check_call(
+ ['intercept-build', '--cdb', result] + make)
+ return result
+
+ @staticmethod
+ def count_entries(filename):
+ with open(filename, 'r') as handler:
+ content = json.load(handler)
+ return len(content)
+
+ def test_successful_build(self):
+ with fixtures.TempDir() as tmpdir:
+ result = self.run_intercept(tmpdir, ['build_regular'])
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+ def test_successful_build_with_wrapper(self):
+ with fixtures.TempDir() as tmpdir:
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + ['build_regular']
+ silent_check_call(['intercept-build', '--cdb', result,
+ '--override-compiler'] + make)
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+ @unittest.skipIf(os.getenv('TRAVIS'), 'ubuntu make return -11')
+ def test_successful_build_parallel(self):
+ with fixtures.TempDir() as tmpdir:
+ result = self.run_intercept(tmpdir, ['-j', '4', 'build_regular'])
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+ @unittest.skipIf(os.getenv('TRAVIS'), 'ubuntu env remove clang from path')
+ def test_successful_build_on_empty_env(self):
+ with fixtures.TempDir() as tmpdir:
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + ['CC=clang', 'build_regular']
+ silent_check_call(['intercept-build', '--cdb', result,
+ 'env', '-'] + make)
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+ def test_successful_build_all_in_one(self):
+ with fixtures.TempDir() as tmpdir:
+ result = self.run_intercept(tmpdir, ['build_all_in_one'])
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+ def test_not_successful_build(self):
+ with fixtures.TempDir() as tmpdir:
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + ['build_broken']
+ silent_call(
+ ['intercept-build', '--cdb', result] + make)
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(2, self.count_entries(result))
+
+
+class ExitCodeTest(unittest.TestCase):
+ @staticmethod
+ def run_intercept(tmpdir, target):
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + [target]
+ return silent_call(
+ ['intercept-build', '--cdb', result] + make)
+
+ def test_successful_build(self):
+ with fixtures.TempDir() as tmpdir:
+ exitcode = self.run_intercept(tmpdir, 'build_clean')
+ self.assertFalse(exitcode)
+
+ def test_not_successful_build(self):
+ with fixtures.TempDir() as tmpdir:
+ exitcode = self.run_intercept(tmpdir, 'build_broken')
+ self.assertTrue(exitcode)
+
+
+class ResumeFeatureTest(unittest.TestCase):
+ @staticmethod
+ def run_intercept(tmpdir, target, args):
+ result = os.path.join(tmpdir, 'cdb.json')
+ make = make_args(tmpdir) + [target]
+ silent_check_call(
+ ['intercept-build', '--cdb', result] + args + make)
+ return result
+
+ @staticmethod
+ def count_entries(filename):
+ with open(filename, 'r') as handler:
+ content = json.load(handler)
+ return len(content)
+
+ def test_overwrite_existing_cdb(self):
+ with fixtures.TempDir() as tmpdir:
+ result = self.run_intercept(tmpdir, 'build_clean', [])
+ self.assertTrue(os.path.isfile(result))
+ result = self.run_intercept(tmpdir, 'build_regular', [])
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(2, self.count_entries(result))
+
+ def test_append_to_existing_cdb(self):
+ with fixtures.TempDir() as tmpdir:
+ result = self.run_intercept(tmpdir, 'build_clean', [])
+ self.assertTrue(os.path.isfile(result))
+ result = self.run_intercept(tmpdir, 'build_regular', ['--append'])
+ self.assertTrue(os.path.isfile(result))
+ self.assertEqual(5, self.count_entries(result))
+
+
+class ResultFormatingTest(unittest.TestCase):
+ @staticmethod
+ def run_intercept(tmpdir, command):
+ result = os.path.join(tmpdir, 'cdb.json')
+ silent_check_call(
+ ['intercept-build', '--cdb', result] + command,
+ cwd=tmpdir)
+ with open(result, 'r') as handler:
+ content = json.load(handler)
+ return content
+
+ def assert_creates_number_of_entries(self, command, count):
+ with fixtures.TempDir() as tmpdir:
+ filename = os.path.join(tmpdir, 'test.c')
+ create_empty_file(filename)
+ command.append(filename)
+ cmd = ['sh', '-c', ' '.join(command)]
+ cdb = self.run_intercept(tmpdir, cmd)
+ self.assertEqual(count, len(cdb))
+
+ def test_filter_preprocessor_only_calls(self):
+ self.assert_creates_number_of_entries(['cc', '-c'], 1)
+ self.assert_creates_number_of_entries(['cc', '-c', '-E'], 0)
+ self.assert_creates_number_of_entries(['cc', '-c', '-M'], 0)
+ self.assert_creates_number_of_entries(['cc', '-c', '-MM'], 0)
+
+ def assert_command_creates_entry(self, command, expected):
+ with fixtures.TempDir() as tmpdir:
+ filename = os.path.join(tmpdir, command[-1])
+ create_empty_file(filename)
+ cmd = ['sh', '-c', ' '.join(command)]
+ cdb = self.run_intercept(tmpdir, cmd)
+ self.assertEqual(' '.join(expected), cdb[0]['command'])
+
+ def test_filter_preprocessor_flags(self):
+ self.assert_command_creates_entry(
+ ['cc', '-c', '-MD', 'test.c'],
+ ['cc', '-c', 'test.c'])
+ self.assert_command_creates_entry(
+ ['cc', '-c', '-MMD', 'test.c'],
+ ['cc', '-c', 'test.c'])
+ self.assert_command_creates_entry(
+ ['cc', '-c', '-MD', '-MF', 'test.d', 'test.c'],
+ ['cc', '-c', 'test.c'])
+
+ def test_pass_language_flag(self):
+ self.assert_command_creates_entry(
+ ['cc', '-c', '-x', 'c', 'test.c'],
+ ['cc', '-c', '-x', 'c', 'test.c'])
+ self.assert_command_creates_entry(
+ ['cc', '-c', 'test.c'],
+ ['cc', '-c', 'test.c'])
+
+ def test_pass_arch_flags(self):
+ self.assert_command_creates_entry(
+ ['clang', '-c', 'test.c'],
+ ['cc', '-c', 'test.c'])
+ self.assert_command_creates_entry(
+ ['clang', '-c', '-arch', 'i386', 'test.c'],
+ ['cc', '-c', '-arch', 'i386', 'test.c'])
+ self.assert_command_creates_entry(
+ ['clang', '-c', '-arch', 'i386', '-arch', 'armv7l', 'test.c'],
+ ['cc', '-c', '-arch', 'i386', '-arch', 'armv7l', 'test.c'])
diff --git a/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py b/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py
new file mode 100644
index 000000000000..329a477e03d7
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/cases/test_exec_anatomy.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+from ...unit import fixtures
+import unittest
+
+import os.path
+import subprocess
+import json
+
+
+def run(source_dir, target_dir):
+ def execute(cmd):
+ return subprocess.check_call(cmd,
+ cwd=target_dir,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+
+ execute(['cmake', source_dir])
+ execute(['make'])
+
+ result_file = os.path.join(target_dir, 'result.json')
+ expected_file = os.path.join(target_dir, 'expected.json')
+ execute(['intercept-build', '--cdb', result_file, './exec',
+ expected_file])
+ return (expected_file, result_file)
+
+
+class ExecAnatomyTest(unittest.TestCase):
+ def assertEqualJson(self, expected, result):
+ def read_json(filename):
+ with open(filename) as handler:
+ return json.load(handler)
+
+ lhs = read_json(expected)
+ rhs = read_json(result)
+ for item in lhs:
+ self.assertTrue(rhs.count(item))
+ for item in rhs:
+ self.assertTrue(lhs.count(item))
+
+ def test_all_exec_calls(self):
+ this_dir, _ = os.path.split(__file__)
+ source_dir = os.path.normpath(os.path.join(this_dir, '..', 'exec'))
+ with fixtures.TempDir() as tmp_dir:
+ expected, result = run(source_dir, tmp_dir)
+ self.assertEqualJson(expected, result)
diff --git a/tools/scan-build-py/tests/functional/cases/test_from_cdb.py b/tools/scan-build-py/tests/functional/cases/test_from_cdb.py
new file mode 100644
index 000000000000..c579020db22c
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/cases/test_from_cdb.py
@@ -0,0 +1,183 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+from ...unit import fixtures
+from . import call_and_report
+import unittest
+
+import os.path
+import string
+import subprocess
+import glob
+
+
+def prepare_cdb(name, target_dir):
+ target_file = 'build_{0}.json'.format(name)
+ this_dir, _ = os.path.split(__file__)
+ path = os.path.normpath(os.path.join(this_dir, '..', 'src'))
+ source_dir = os.path.join(path, 'compilation_database')
+ source_file = os.path.join(source_dir, target_file + '.in')
+ target_file = os.path.join(target_dir, 'compile_commands.json')
+ with open(source_file, 'r') as in_handle:
+ with open(target_file, 'w') as out_handle:
+ for line in in_handle:
+ temp = string.Template(line)
+ out_handle.write(temp.substitute(path=path))
+ return target_file
+
+
+def run_analyzer(directory, cdb, args):
+ cmd = ['analyze-build', '--cdb', cdb, '--output', directory] \
+ + args
+ return call_and_report(cmd, [])
+
+
+class OutputDirectoryTest(unittest.TestCase):
+ def test_regular_keeps_report_dir(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
+ self.assertTrue(os.path.isdir(reportdir))
+
+ def test_clear_deletes_report_dir(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('clean', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
+ self.assertFalse(os.path.isdir(reportdir))
+
+ def test_clear_keeps_report_dir_when_asked(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('clean', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, ['--keep-empty'])
+ self.assertTrue(os.path.isdir(reportdir))
+
+
+class ExitCodeTest(unittest.TestCase):
+ def test_regular_does_not_set_exit_code(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, __ = run_analyzer(tmpdir, cdb, [])
+ self.assertFalse(exit_code)
+
+ def test_clear_does_not_set_exit_code(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('clean', tmpdir)
+ exit_code, __ = run_analyzer(tmpdir, cdb, [])
+ self.assertFalse(exit_code)
+
+ def test_regular_sets_exit_code_if_asked(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, __ = run_analyzer(tmpdir, cdb, ['--status-bugs'])
+ self.assertTrue(exit_code)
+
+ def test_clear_does_not_set_exit_code_if_asked(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('clean', tmpdir)
+ exit_code, __ = run_analyzer(tmpdir, cdb, ['--status-bugs'])
+ self.assertFalse(exit_code)
+
+ def test_regular_sets_exit_code_if_asked_from_plist(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, __ = run_analyzer(
+ tmpdir, cdb, ['--status-bugs', '--plist'])
+ self.assertTrue(exit_code)
+
+ def test_clear_does_not_set_exit_code_if_asked_from_plist(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('clean', tmpdir)
+ exit_code, __ = run_analyzer(
+ tmpdir, cdb, ['--status-bugs', '--plist'])
+ self.assertFalse(exit_code)
+
+
+class OutputFormatTest(unittest.TestCase):
+ @staticmethod
+ def get_html_count(directory):
+ return len(glob.glob(os.path.join(directory, 'report-*.html')))
+
+ @staticmethod
+ def get_plist_count(directory):
+ return len(glob.glob(os.path.join(directory, 'report-*.plist')))
+
+ def test_default_creates_html_report(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
+ self.assertTrue(
+ os.path.exists(os.path.join(reportdir, 'index.html')))
+ self.assertEqual(self.get_html_count(reportdir), 2)
+ self.assertEqual(self.get_plist_count(reportdir), 0)
+
+ def test_plist_and_html_creates_html_report(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, ['--plist-html'])
+ self.assertTrue(
+ os.path.exists(os.path.join(reportdir, 'index.html')))
+ self.assertEqual(self.get_html_count(reportdir), 2)
+ self.assertEqual(self.get_plist_count(reportdir), 5)
+
+ def test_plist_does_not_creates_html_report(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('regular', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, ['--plist'])
+ self.assertFalse(
+ os.path.exists(os.path.join(reportdir, 'index.html')))
+ self.assertEqual(self.get_html_count(reportdir), 0)
+ self.assertEqual(self.get_plist_count(reportdir), 5)
+
+
+class FailureReportTest(unittest.TestCase):
+ def test_broken_creates_failure_reports(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('broken', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
+ self.assertTrue(
+ os.path.isdir(os.path.join(reportdir, 'failures')))
+
+ def test_broken_does_not_creates_failure_reports(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('broken', tmpdir)
+ exit_code, reportdir = run_analyzer(
+ tmpdir, cdb, ['--no-failure-reports'])
+ self.assertFalse(
+ os.path.isdir(os.path.join(reportdir, 'failures')))
+
+
+class TitleTest(unittest.TestCase):
+ def assertTitleEqual(self, directory, expected):
+ import re
+ patterns = [
+ re.compile(r'<title>(?P<page>.*)</title>'),
+ re.compile(r'<h1>(?P<head>.*)</h1>')
+ ]
+ result = dict()
+
+ index = os.path.join(directory, 'index.html')
+ with open(index, 'r') as handler:
+ for line in handler.readlines():
+ for regex in patterns:
+ match = regex.match(line.strip())
+ if match:
+ result.update(match.groupdict())
+ break
+ self.assertEqual(result['page'], result['head'])
+ self.assertEqual(result['page'], expected)
+
+ def test_default_title_in_report(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('broken', tmpdir)
+ exit_code, reportdir = run_analyzer(tmpdir, cdb, [])
+ self.assertTitleEqual(reportdir, 'src - analyzer results')
+
+ def test_given_title_in_report(self):
+ with fixtures.TempDir() as tmpdir:
+ cdb = prepare_cdb('broken', tmpdir)
+ exit_code, reportdir = run_analyzer(
+ tmpdir, cdb, ['--html-title', 'this is the title'])
+ self.assertTitleEqual(reportdir, 'this is the title')
diff --git a/tools/scan-build-py/tests/functional/cases/test_from_cmd.py b/tools/scan-build-py/tests/functional/cases/test_from_cmd.py
new file mode 100644
index 000000000000..fe7ecf69915b
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/cases/test_from_cmd.py
@@ -0,0 +1,118 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+from ...unit import fixtures
+from . import make_args, check_call_and_report, create_empty_file
+import unittest
+
+import os
+import os.path
+import glob
+
+
+class OutputDirectoryTest(unittest.TestCase):
+
+ @staticmethod
+ def run_analyzer(outdir, args, cmd):
+ return check_call_and_report(
+ ['scan-build', '--intercept-first', '-o', outdir] + args,
+ cmd)
+
+ def test_regular_keeps_report_dir(self):
+ with fixtures.TempDir() as tmpdir:
+ make = make_args(tmpdir) + ['build_regular']
+ outdir = self.run_analyzer(tmpdir, [], make)
+ self.assertTrue(os.path.isdir(outdir))
+
+ def test_clear_deletes_report_dir(self):
+ with fixtures.TempDir() as tmpdir:
+ make = make_args(tmpdir) + ['build_clean']
+ outdir = self.run_analyzer(tmpdir, [], make)
+ self.assertFalse(os.path.isdir(outdir))
+
+ def test_clear_keeps_report_dir_when_asked(self):
+ with fixtures.TempDir() as tmpdir:
+ make = make_args(tmpdir) + ['build_clean']
+ outdir = self.run_analyzer(tmpdir, ['--keep-empty'], make)
+ self.assertTrue(os.path.isdir(outdir))
+
+
+class RunAnalyzerTest(unittest.TestCase):
+
+ @staticmethod
+ def get_plist_count(directory):
+ return len(glob.glob(os.path.join(directory, 'report-*.plist')))
+
+ def test_interposition_works(self):
+ with fixtures.TempDir() as tmpdir:
+ make = make_args(tmpdir) + ['build_regular']
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
+ make)
+
+ self.assertTrue(os.path.isdir(outdir))
+ self.assertEqual(self.get_plist_count(outdir), 5)
+
+ def test_intercept_wrapper_works(self):
+ with fixtures.TempDir() as tmpdir:
+ make = make_args(tmpdir) + ['build_regular']
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--intercept-first',
+ '--override-compiler'],
+ make)
+
+ self.assertTrue(os.path.isdir(outdir))
+ self.assertEqual(self.get_plist_count(outdir), 5)
+
+ def test_intercept_library_works(self):
+ with fixtures.TempDir() as tmpdir:
+ make = make_args(tmpdir) + ['build_regular']
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--intercept-first'],
+ make)
+
+ self.assertTrue(os.path.isdir(outdir))
+ self.assertEqual(self.get_plist_count(outdir), 5)
+
+ @staticmethod
+ def compile_empty_source_file(target_dir, is_cxx):
+ compiler = '$CXX' if is_cxx else '$CC'
+ src_file_name = 'test.cxx' if is_cxx else 'test.c'
+ src_file = os.path.join(target_dir, src_file_name)
+ obj_file = os.path.join(target_dir, 'test.o')
+ create_empty_file(src_file)
+ command = ' '.join([compiler, '-c', src_file, '-o', obj_file])
+ return ['sh', '-c', command]
+
+ def test_interposition_cc_works(self):
+ with fixtures.TempDir() as tmpdir:
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
+ self.compile_empty_source_file(tmpdir, False))
+ self.assertEqual(self.get_plist_count(outdir), 1)
+
+ def test_interposition_cxx_works(self):
+ with fixtures.TempDir() as tmpdir:
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--override-compiler'],
+ self.compile_empty_source_file(tmpdir, True))
+ self.assertEqual(self.get_plist_count(outdir), 1)
+
+ def test_intercept_cc_works(self):
+ with fixtures.TempDir() as tmpdir:
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--override-compiler',
+ '--intercept-first'],
+ self.compile_empty_source_file(tmpdir, False))
+ self.assertEqual(self.get_plist_count(outdir), 1)
+
+ def test_intercept_cxx_works(self):
+ with fixtures.TempDir() as tmpdir:
+ outdir = check_call_and_report(
+ ['scan-build', '--plist', '-o', tmpdir, '--override-compiler',
+ '--intercept-first'],
+ self.compile_empty_source_file(tmpdir, True))
+ self.assertEqual(self.get_plist_count(outdir), 1)
diff --git a/tools/scan-build-py/tests/functional/exec/CMakeLists.txt b/tools/scan-build-py/tests/functional/exec/CMakeLists.txt
new file mode 100644
index 000000000000..6e5d2e966184
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/exec/CMakeLists.txt
@@ -0,0 +1,32 @@
+project(exec C)
+
+cmake_minimum_required(VERSION 2.8)
+
+include(CheckCCompilerFlag)
+check_c_compiler_flag("-std=c99" C99_SUPPORTED)
+if (C99_SUPPORTED)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
+endif()
+
+include(CheckFunctionExists)
+include(CheckSymbolExists)
+
+add_definitions(-D_GNU_SOURCE)
+list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
+
+check_function_exists(execve HAVE_EXECVE)
+check_function_exists(execv HAVE_EXECV)
+check_function_exists(execvpe HAVE_EXECVPE)
+check_function_exists(execvp HAVE_EXECVP)
+check_function_exists(execvP HAVE_EXECVP2)
+check_function_exists(exect HAVE_EXECT)
+check_function_exists(execl HAVE_EXECL)
+check_function_exists(execlp HAVE_EXECLP)
+check_function_exists(execle HAVE_EXECLE)
+check_function_exists(posix_spawn HAVE_POSIX_SPAWN)
+check_function_exists(posix_spawnp HAVE_POSIX_SPAWNP)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+add_executable(exec main.c)
diff --git a/tools/scan-build-py/tests/functional/exec/config.h.in b/tools/scan-build-py/tests/functional/exec/config.h.in
new file mode 100644
index 000000000000..6221083fd2cc
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/exec/config.h.in
@@ -0,0 +1,20 @@
+/* -*- coding: utf-8 -*-
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+*/
+
+#pragma once
+
+#cmakedefine HAVE_EXECVE
+#cmakedefine HAVE_EXECV
+#cmakedefine HAVE_EXECVPE
+#cmakedefine HAVE_EXECVP
+#cmakedefine HAVE_EXECVP2
+#cmakedefine HAVE_EXECT
+#cmakedefine HAVE_EXECL
+#cmakedefine HAVE_EXECLP
+#cmakedefine HAVE_EXECLE
+#cmakedefine HAVE_POSIX_SPAWN
+#cmakedefine HAVE_POSIX_SPAWNP
diff --git a/tools/scan-build-py/tests/functional/exec/main.c b/tools/scan-build-py/tests/functional/exec/main.c
new file mode 100644
index 000000000000..830cf3749cbd
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/exec/main.c
@@ -0,0 +1,307 @@
+/* -*- coding: utf-8 -*-
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+*/
+
+#include "config.h"
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <paths.h>
+
+#if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP
+#include <spawn.h>
+#endif
+
+// ..:: environment access fixer - begin ::..
+#ifdef HAVE_NSGETENVIRON
+#include <crt_externs.h>
+#else
+extern char **environ;
+#endif
+
+char **get_environ() {
+#ifdef HAVE_NSGETENVIRON
+ return *_NSGetEnviron();
+#else
+ return environ;
+#endif
+}
+// ..:: environment access fixer - end ::..
+
+// ..:: test fixtures - begin ::..
+static char const *cwd = NULL;
+static FILE *fd = NULL;
+static int need_comma = 0;
+
+void expected_out_open(const char *expected) {
+ cwd = getcwd(NULL, 0);
+ fd = fopen(expected, "w");
+ if (!fd) {
+ perror("fopen");
+ exit(EXIT_FAILURE);
+ }
+ fprintf(fd, "[\n");
+ need_comma = 0;
+}
+
+void expected_out_close() {
+ fprintf(fd, "]\n");
+ fclose(fd);
+ fd = NULL;
+
+ free((void *)cwd);
+ cwd = NULL;
+}
+
+void expected_out(const char *file) {
+ if (need_comma)
+ fprintf(fd, ",\n");
+ else
+ need_comma = 1;
+
+ fprintf(fd, "{\n");
+ fprintf(fd, " \"directory\": \"%s\",\n", cwd);
+ fprintf(fd, " \"command\": \"cc -c %s\",\n", file);
+ fprintf(fd, " \"file\": \"%s/%s\"\n", cwd, file);
+ fprintf(fd, "}\n");
+}
+
+void create_source(char *file) {
+ FILE *fd = fopen(file, "w");
+ if (!fd) {
+ perror("fopen");
+ exit(EXIT_FAILURE);
+ }
+ fprintf(fd, "typedef int score;\n");
+ fclose(fd);
+}
+
+typedef void (*exec_fun)();
+
+void wait_for(pid_t child) {
+ int status;
+ if (-1 == waitpid(child, &status, 0)) {
+ perror("wait");
+ exit(EXIT_FAILURE);
+ }
+ if (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE) {
+ fprintf(stderr, "children process has non zero exit code\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+#define FORK(FUNC) \
+ { \
+ pid_t child = fork(); \
+ if (-1 == child) { \
+ perror("fork"); \
+ exit(EXIT_FAILURE); \
+ } else if (0 == child) { \
+ FUNC fprintf(stderr, "children process failed to exec\n"); \
+ exit(EXIT_FAILURE); \
+ } else { \
+ wait_for(child); \
+ } \
+ }
+// ..:: test fixtures - end ::..
+
+#ifdef HAVE_EXECV
+void call_execv() {
+ char *const file = "execv.c";
+ char *const compiler = "/usr/bin/cc";
+ char *const argv[] = {"cc", "-c", file, 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execv(compiler, argv);)
+}
+#endif
+
+#ifdef HAVE_EXECVE
+void call_execve() {
+ char *const file = "execve.c";
+ char *const compiler = "/usr/bin/cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+ char *const envp[] = {"THIS=THAT", 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execve(compiler, argv, envp);)
+}
+#endif
+
+#ifdef HAVE_EXECVP
+void call_execvp() {
+ char *const file = "execvp.c";
+ char *const compiler = "cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execvp(compiler, argv);)
+}
+#endif
+
+#ifdef HAVE_EXECVP2
+void call_execvP() {
+ char *const file = "execv_p.c";
+ char *const compiler = "cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execvP(compiler, _PATH_DEFPATH, argv);)
+}
+#endif
+
+#ifdef HAVE_EXECVPE
+void call_execvpe() {
+ char *const file = "execvpe.c";
+ char *const compiler = "cc";
+ char *const argv[] = {"/usr/bin/cc", "-c", file, 0};
+ char *const envp[] = {"THIS=THAT", 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execvpe(compiler, argv, envp);)
+}
+#endif
+
+#ifdef HAVE_EXECT
+void call_exect() {
+ char *const file = "exect.c";
+ char *const compiler = "/usr/bin/cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+ char *const envp[] = {"THIS=THAT", 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(exect(compiler, argv, envp);)
+}
+#endif
+
+#ifdef HAVE_EXECL
+void call_execl() {
+ char *const file = "execl.c";
+ char *const compiler = "/usr/bin/cc";
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execl(compiler, "cc", "-c", file, (char *)0);)
+}
+#endif
+
+#ifdef HAVE_EXECLP
+void call_execlp() {
+ char *const file = "execlp.c";
+ char *const compiler = "cc";
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execlp(compiler, compiler, "-c", file, (char *)0);)
+}
+#endif
+
+#ifdef HAVE_EXECLE
+void call_execle() {
+ char *const file = "execle.c";
+ char *const compiler = "/usr/bin/cc";
+ char *const envp[] = {"THIS=THAT", 0};
+
+ expected_out(file);
+ create_source(file);
+
+ FORK(execle(compiler, compiler, "-c", file, (char *)0, envp);)
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWN
+void call_posix_spawn() {
+ char *const file = "posix_spawn.c";
+ char *const compiler = "cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+
+ expected_out(file);
+ create_source(file);
+
+ pid_t child;
+ if (0 != posix_spawn(&child, "/usr/bin/cc", 0, 0, argv, get_environ())) {
+ perror("posix_spawn");
+ exit(EXIT_FAILURE);
+ }
+ wait_for(child);
+}
+#endif
+
+#ifdef HAVE_POSIX_SPAWNP
+void call_posix_spawnp() {
+ char *const file = "posix_spawnp.c";
+ char *const compiler = "cc";
+ char *const argv[] = {compiler, "-c", file, 0};
+
+ expected_out(file);
+ create_source(file);
+
+ pid_t child;
+ if (0 != posix_spawnp(&child, "cc", 0, 0, argv, get_environ())) {
+ perror("posix_spawnp");
+ exit(EXIT_FAILURE);
+ }
+ wait_for(child);
+}
+#endif
+
+int main(int argc, char *const argv[]) {
+ if (argc != 2)
+ exit(EXIT_FAILURE);
+
+ expected_out_open(argv[1]);
+#ifdef HAVE_EXECV
+ call_execv();
+#endif
+#ifdef HAVE_EXECVE
+ call_execve();
+#endif
+#ifdef HAVE_EXECVP
+ call_execvp();
+#endif
+#ifdef HAVE_EXECVP2
+ call_execvP();
+#endif
+#ifdef HAVE_EXECVPE
+ call_execvpe();
+#endif
+#ifdef HAVE_EXECT
+ call_exect();
+#endif
+#ifdef HAVE_EXECL
+ call_execl();
+#endif
+#ifdef HAVE_EXECLP
+ call_execlp();
+#endif
+#ifdef HAVE_EXECLE
+ call_execle();
+#endif
+#ifdef HAVE_POSIX_SPAWN
+ call_posix_spawn();
+#endif
+#ifdef HAVE_POSIX_SPAWNP
+ call_posix_spawnp();
+#endif
+ expected_out_close();
+ return 0;
+}
diff --git a/tools/scan-build-py/tests/functional/src/broken-one.c b/tools/scan-build-py/tests/functional/src/broken-one.c
new file mode 100644
index 000000000000..f0550238132c
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/broken-one.c
@@ -0,0 +1,6 @@
+#include <notexisting.hpp>
+
+int value(int in)
+{
+ return 2 * in;
+}
diff --git a/tools/scan-build-py/tests/functional/src/broken-two.c b/tools/scan-build-py/tests/functional/src/broken-two.c
new file mode 100644
index 000000000000..7b4c12ff5c39
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/broken-two.c
@@ -0,0 +1 @@
+int test() { ;
diff --git a/tools/scan-build-py/tests/functional/src/build/Makefile b/tools/scan-build-py/tests/functional/src/build/Makefile
new file mode 100644
index 000000000000..a8c0aafd0e5e
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/build/Makefile
@@ -0,0 +1,42 @@
+SRCDIR := ..
+OBJDIR := .
+
+CFLAGS = -Wall -DDEBUG -Dvariable="value with space" -I $(SRCDIR)/include
+LDFLAGS =
+PROGRAM = $(OBJDIR)/prg
+
+$(OBJDIR)/main.o: $(SRCDIR)/main.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/main.c
+
+$(OBJDIR)/clean-one.o: $(SRCDIR)/clean-one.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/clean-one.c
+
+$(OBJDIR)/clean-two.o: $(SRCDIR)/clean-two.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/clean-two.c
+
+$(OBJDIR)/emit-one.o: $(SRCDIR)/emit-one.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/emit-one.c
+
+$(OBJDIR)/emit-two.o: $(SRCDIR)/emit-two.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/emit-two.c
+
+$(OBJDIR)/broken-one.o: $(SRCDIR)/broken-one.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/broken-one.c
+
+$(OBJDIR)/broken-two.o: $(SRCDIR)/broken-two.c
+ $(CC) $(CFLAGS) -c -o $@ $(SRCDIR)/broken-two.c
+
+$(PROGRAM): $(OBJDIR)/main.o $(OBJDIR)/clean-one.o $(OBJDIR)/clean-two.o $(OBJDIR)/emit-one.o $(OBJDIR)/emit-two.o
+ $(CC) $(LDFLAGS) -o $@ $(OBJDIR)/main.o $(OBJDIR)/clean-one.o $(OBJDIR)/clean-two.o $(OBJDIR)/emit-one.o $(OBJDIR)/emit-two.o
+
+build_regular: $(PROGRAM)
+
+build_clean: $(OBJDIR)/main.o $(OBJDIR)/clean-one.o $(OBJDIR)/clean-two.o
+
+build_broken: $(OBJDIR)/main.o $(OBJDIR)/broken-one.o $(OBJDIR)/broken-two.o
+
+build_all_in_one: $(SRCDIR)/main.c $(SRCDIR)/clean-one.c $(SRCDIR)/clean-two.c $(SRCDIR)/emit-one.c $(SRCDIR)/emit-two.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROGRAM) $(SRCDIR)/main.c $(SRCDIR)/clean-one.c $(SRCDIR)/clean-two.c $(SRCDIR)/emit-one.c $(SRCDIR)/emit-two.c
+
+clean:
+ rm -f $(PROGRAM) $(OBJDIR)/*.o
diff --git a/tools/scan-build-py/tests/functional/src/clean-one.c b/tools/scan-build-py/tests/functional/src/clean-one.c
new file mode 100644
index 000000000000..08c5f33609bb
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/clean-one.c
@@ -0,0 +1,13 @@
+#include <clean-one.h>
+
+int do_nothing_loop()
+{
+ int i = 32;
+ int idx = 0;
+
+ for (idx = i; idx > 0; --idx)
+ {
+ i += idx;
+ }
+ return i;
+}
diff --git a/tools/scan-build-py/tests/functional/src/clean-two.c b/tools/scan-build-py/tests/functional/src/clean-two.c
new file mode 100644
index 000000000000..73bc288627d0
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/clean-two.c
@@ -0,0 +1,11 @@
+#include <clean-one.h>
+
+#include <stdlib.h>
+
+unsigned int another_method()
+{
+ unsigned int const size = do_nothing_loop();
+ unsigned int const square = size * size;
+
+ return square;
+}
diff --git a/tools/scan-build-py/tests/functional/src/compilation_database/build_broken.json.in b/tools/scan-build-py/tests/functional/src/compilation_database/build_broken.json.in
new file mode 100644
index 000000000000..104a4191cb1b
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/compilation_database/build_broken.json.in
@@ -0,0 +1,43 @@
+[
+{
+ "directory": "${path}",
+ "command": "g++ -c -o main.o main.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/main.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o broken-one.o broken-one.c -Wall -DDEBUG \"-Dvariable=value with space\"",
+ "file": "${path}/broken-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o broken-two.o broken-two.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/broken-two.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o clean-one.o clean-one.c -Wall -DDEBUG \"-Dvariable=value with space\" -Iinclude",
+ "file": "${path}/clean-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o clean-two.o clean-two.c -Wall -DDEBUG -Dvariable=value -I ./include",
+ "file": "${path}/clean-two.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o emit-one.o emit-one.c -Wall -DDEBUG \"-Dvariable=value with space\"",
+ "file": "${path}/emit-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o emit-two.o emit-two.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/emit-two.c"
+}
+]
diff --git a/tools/scan-build-py/tests/functional/src/compilation_database/build_clean.json.in b/tools/scan-build-py/tests/functional/src/compilation_database/build_clean.json.in
new file mode 100644
index 000000000000..aa4dcde8e5e7
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/compilation_database/build_clean.json.in
@@ -0,0 +1,19 @@
+[
+{
+ "directory": "${path}",
+ "command": "g++ -c -o main.o main.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/main.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o clean-one.o clean-one.c -Wall -DDEBUG \"-Dvariable=value with space\" -Iinclude",
+ "file": "${path}/clean-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o clean-two.o clean-two.c -Wall -DDEBUG -Dvariable=value -I ./include",
+ "file": "${path}/clean-two.c"
+}
+]
diff --git a/tools/scan-build-py/tests/functional/src/compilation_database/build_regular.json.in b/tools/scan-build-py/tests/functional/src/compilation_database/build_regular.json.in
new file mode 100644
index 000000000000..0200c1d8624a
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/compilation_database/build_regular.json.in
@@ -0,0 +1,31 @@
+[
+{
+ "directory": "${path}",
+ "command": "g++ -c -o main.o main.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/main.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o clean-one.o clean-one.c -Wall -DDEBUG \"-Dvariable=value with space\" -Iinclude",
+ "file": "${path}/clean-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o clean-two.o clean-two.c -Wall -DDEBUG -Dvariable=value -I ./include",
+ "file": "${path}/clean-two.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "cc -c -o emit-one.o emit-one.c -Wall -DDEBUG \"-Dvariable=value with space\"",
+ "file": "${path}/emit-one.c"
+}
+,
+{
+ "directory": "${path}",
+ "command": "g++ -c -o emit-two.o emit-two.c -Wall -DDEBUG -Dvariable=value",
+ "file": "${path}/emit-two.c"
+}
+]
diff --git a/tools/scan-build-py/tests/functional/src/emit-one.c b/tools/scan-build-py/tests/functional/src/emit-one.c
new file mode 100644
index 000000000000..6cbd9cea72b9
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/emit-one.c
@@ -0,0 +1,23 @@
+#include <assert.h>
+
+int div(int numerator, int denominator)
+{
+ return numerator / denominator;
+}
+
+void div_test()
+{
+ int i = 0;
+ for (i = 0; i < 2; ++i)
+ assert(div(2 * i, i) == 2);
+}
+
+int do_nothing()
+{
+ unsigned int i = 0;
+
+ int k = 100;
+ int j = k + 1;
+
+ return j;
+}
diff --git a/tools/scan-build-py/tests/functional/src/emit-two.c b/tools/scan-build-py/tests/functional/src/emit-two.c
new file mode 100644
index 000000000000..faea77167f4c
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/emit-two.c
@@ -0,0 +1,13 @@
+
+int bad_guy(int * i)
+{
+ *i = 9;
+ return *i;
+}
+
+void bad_guy_test()
+{
+ int * ptr = 0;
+
+ bad_guy(ptr);
+}
diff --git a/tools/scan-build-py/tests/functional/src/include/clean-one.h b/tools/scan-build-py/tests/functional/src/include/clean-one.h
new file mode 100644
index 000000000000..695dbd04c658
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/include/clean-one.h
@@ -0,0 +1,6 @@
+#ifndef CLEAN_ONE_H
+#define CLEAN_ONE_H
+
+int do_nothing_loop();
+
+#endif
diff --git a/tools/scan-build-py/tests/functional/src/main.c b/tools/scan-build-py/tests/functional/src/main.c
new file mode 100644
index 000000000000..905869dfa380
--- /dev/null
+++ b/tools/scan-build-py/tests/functional/src/main.c
@@ -0,0 +1,4 @@
+int main()
+{
+ return 0;
+}
diff --git a/tools/scan-build-py/tests/unit/__init__.py b/tools/scan-build-py/tests/unit/__init__.py
new file mode 100644
index 000000000000..4fa9edc0fff1
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/__init__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+from . import test_command
+from . import test_clang
+from . import test_runner
+from . import test_report
+from . import test_analyze
+from . import test_intercept
+from . import test_shell
+
+
+def load_tests(loader, suite, pattern):
+ suite.addTests(loader.loadTestsFromModule(test_command))
+ suite.addTests(loader.loadTestsFromModule(test_clang))
+ suite.addTests(loader.loadTestsFromModule(test_runner))
+ suite.addTests(loader.loadTestsFromModule(test_report))
+ suite.addTests(loader.loadTestsFromModule(test_analyze))
+ suite.addTests(loader.loadTestsFromModule(test_intercept))
+ suite.addTests(loader.loadTestsFromModule(test_shell))
+ return suite
diff --git a/tools/scan-build-py/tests/unit/fixtures.py b/tools/scan-build-py/tests/unit/fixtures.py
new file mode 100644
index 000000000000..d80f5e64774c
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/fixtures.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import contextlib
+import tempfile
+import shutil
+import unittest
+
+
+class Spy(object):
+ def __init__(self):
+ self.arg = None
+ self.success = 0
+
+ def call(self, params):
+ self.arg = params
+ return self.success
+
+
+@contextlib.contextmanager
+def TempDir():
+ name = tempfile.mkdtemp(prefix='scan-build-test-')
+ try:
+ yield name
+ finally:
+ shutil.rmtree(name)
+
+
+class TestCase(unittest.TestCase):
+ def assertIn(self, element, collection):
+ found = False
+ for it in collection:
+ if element == it:
+ found = True
+
+ self.assertTrue(found, '{0} does not have {1}'.format(collection,
+ element))
diff --git a/tools/scan-build-py/tests/unit/test_analyze.py b/tools/scan-build-py/tests/unit/test_analyze.py
new file mode 100644
index 000000000000..b77db4818024
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/test_analyze.py
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import libscanbuild.analyze as sut
+from . import fixtures
diff --git a/tools/scan-build-py/tests/unit/test_clang.py b/tools/scan-build-py/tests/unit/test_clang.py
new file mode 100644
index 000000000000..2f1fd79d4a92
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/test_clang.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import libscanbuild.clang as sut
+from . import fixtures
+import os.path
+
+
+class GetClangArgumentsTest(fixtures.TestCase):
+ def test_get_clang_arguments(self):
+ with fixtures.TempDir() as tmpdir:
+ filename = os.path.join(tmpdir, 'test.c')
+ with open(filename, 'w') as handle:
+ handle.write('')
+
+ result = sut.get_arguments(
+ ['clang', '-c', filename, '-DNDEBUG', '-Dvar="this is it"'],
+ tmpdir)
+
+ self.assertIn('NDEBUG', result)
+ self.assertIn('var="this is it"', result)
+
+ def test_get_clang_arguments_fails(self):
+ self.assertRaises(
+ Exception, sut.get_arguments,
+ ['clang', '-###', '-fsyntax-only', '-x', 'c', 'notexist.c'], '.')
+
+
+class GetCheckersTest(fixtures.TestCase):
+ def test_get_checkers(self):
+ # this test is only to see is not crashing
+ result = sut.get_checkers('clang', [])
+ self.assertTrue(len(result))
+
+ def test_get_active_checkers(self):
+ # this test is only to see is not crashing
+ result = sut.get_active_checkers('clang', [])
+ self.assertTrue(len(result))
diff --git a/tools/scan-build-py/tests/unit/test_command.py b/tools/scan-build-py/tests/unit/test_command.py
new file mode 100644
index 000000000000..9a6aae65c605
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/test_command.py
@@ -0,0 +1,193 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import libscanbuild.command as sut
+from . import fixtures
+import unittest
+
+
+class ParseTest(unittest.TestCase):
+
+ def test_action(self):
+ def test(expected, cmd):
+ opts = sut.classify_parameters(cmd)
+ self.assertEqual(expected, opts['action'])
+
+ Link = sut.Action.Link
+ test(Link, ['clang', 'source.c'])
+
+ Compile = sut.Action.Compile
+ test(Compile, ['clang', '-c', 'source.c'])
+ test(Compile, ['clang', '-c', 'source.c', '-MF', 'source.d'])
+
+ Preprocess = sut.Action.Ignored
+ test(Preprocess, ['clang', '-E', 'source.c'])
+ test(Preprocess, ['clang', '-c', '-E', 'source.c'])
+ test(Preprocess, ['clang', '-c', '-M', 'source.c'])
+ test(Preprocess, ['clang', '-c', '-MM', 'source.c'])
+
+ def test_optimalizations(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('compile_options', [])
+
+ self.assertEqual(['-O'], test(['clang', '-c', 'source.c', '-O']))
+ self.assertEqual(['-O1'], test(['clang', '-c', 'source.c', '-O1']))
+ self.assertEqual(['-Os'], test(['clang', '-c', 'source.c', '-Os']))
+ self.assertEqual(['-O2'], test(['clang', '-c', 'source.c', '-O2']))
+ self.assertEqual(['-O3'], test(['clang', '-c', 'source.c', '-O3']))
+
+ def test_language(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('language')
+
+ self.assertEqual(None, test(['clang', '-c', 'source.c']))
+ self.assertEqual('c', test(['clang', '-c', 'source.c', '-x', 'c']))
+ self.assertEqual('cpp', test(['clang', '-c', 'source.c', '-x', 'cpp']))
+
+ def test_output(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('output')
+
+ self.assertEqual(None, test(['clang', '-c', 'source.c']))
+ self.assertEqual('source.o',
+ test(['clang', '-c', '-o', 'source.o', 'source.c']))
+
+ def test_arch(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('archs_seen', [])
+
+ eq = self.assertEqual
+
+ eq([], test(['clang', '-c', 'source.c']))
+ eq(['mips'],
+ test(['clang', '-c', 'source.c', '-arch', 'mips']))
+ eq(['mips', 'i386'],
+ test(['clang', '-c', 'source.c', '-arch', 'mips', '-arch', 'i386']))
+
+ def test_input_file(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('files', [])
+
+ eq = self.assertEqual
+
+ eq(['src.c'], test(['clang', 'src.c']))
+ eq(['src.c'], test(['clang', '-c', 'src.c']))
+ eq(['s1.c', 's2.c'], test(['clang', '-c', 's1.c', 's2.c']))
+
+ def test_include(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('compile_options', [])
+
+ eq = self.assertEqual
+
+ eq([], test(['clang', '-c', 'src.c']))
+ eq(['-include', '/usr/local/include'],
+ test(['clang', '-c', 'src.c', '-include', '/usr/local/include']))
+ eq(['-I.'],
+ test(['clang', '-c', 'src.c', '-I.']))
+ eq(['-I', '.'],
+ test(['clang', '-c', 'src.c', '-I', '.']))
+ eq(['-I/usr/local/include'],
+ test(['clang', '-c', 'src.c', '-I/usr/local/include']))
+ eq(['-I', '/usr/local/include'],
+ test(['clang', '-c', 'src.c', '-I', '/usr/local/include']))
+ eq(['-I/opt', '-I', '/opt/otp/include'],
+ test(['clang', '-c', 'src.c', '-I/opt', '-I', '/opt/otp/include']))
+ eq(['-isystem', '/path'],
+ test(['clang', '-c', 'src.c', '-isystem', '/path']))
+ eq(['-isystem=/path'],
+ test(['clang', '-c', 'src.c', '-isystem=/path']))
+
+ def test_define(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('compile_options', [])
+
+ eq = self.assertEqual
+
+ eq([], test(['clang', '-c', 'src.c']))
+ eq(['-DNDEBUG'],
+ test(['clang', '-c', 'src.c', '-DNDEBUG']))
+ eq(['-UNDEBUG'],
+ test(['clang', '-c', 'src.c', '-UNDEBUG']))
+ eq(['-Dvar1=val1', '-Dvar2=val2'],
+ test(['clang', '-c', 'src.c', '-Dvar1=val1', '-Dvar2=val2']))
+ eq(['-Dvar="val ues"'],
+ test(['clang', '-c', 'src.c', '-Dvar="val ues"']))
+
+ def test_ignored_flags(self):
+ def test(flags):
+ cmd = ['clang', 'src.o']
+ opts = sut.classify_parameters(cmd + flags)
+ self.assertEqual(['src.o'], opts.get('compile_options'))
+
+ test([])
+ test(['-lrt', '-L/opt/company/lib'])
+ test(['-static'])
+ test(['-Wnoexcept', '-Wall'])
+ test(['-mtune=i386', '-mcpu=i386'])
+
+ def test_compile_only_flags(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('compile_options', [])
+
+ eq = self.assertEqual
+
+ eq(['-std=C99'],
+ test(['clang', '-c', 'src.c', '-std=C99']))
+ eq(['-nostdinc'],
+ test(['clang', '-c', 'src.c', '-nostdinc']))
+ eq(['-isystem', '/image/debian'],
+ test(['clang', '-c', 'src.c', '-isystem', '/image/debian']))
+ eq(['-iprefix', '/usr/local'],
+ test(['clang', '-c', 'src.c', '-iprefix', '/usr/local']))
+ eq(['-iquote=me'],
+ test(['clang', '-c', 'src.c', '-iquote=me']))
+ eq(['-iquote', 'me'],
+ test(['clang', '-c', 'src.c', '-iquote', 'me']))
+
+ def test_compile_and_link_flags(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('compile_options', [])
+
+ eq = self.assertEqual
+
+ eq(['-fsinged-char'],
+ test(['clang', '-c', 'src.c', '-fsinged-char']))
+ eq(['-fPIC'],
+ test(['clang', '-c', 'src.c', '-fPIC']))
+ eq(['-stdlib=libc++'],
+ test(['clang', '-c', 'src.c', '-stdlib=libc++']))
+ eq(['--sysroot', '/'],
+ test(['clang', '-c', 'src.c', '--sysroot', '/']))
+ eq(['-isysroot', '/'],
+ test(['clang', '-c', 'src.c', '-isysroot', '/']))
+ eq([],
+ test(['clang', '-c', 'src.c', '-fsyntax-only']))
+ eq([],
+ test(['clang', '-c', 'src.c', '-sectorder', 'a', 'b', 'c']))
+
+ def test_detect_cxx_from_compiler_name(self):
+ def test(cmd):
+ opts = sut.classify_parameters(cmd)
+ return opts.get('c++')
+
+ eq = self.assertEqual
+
+ eq(False, test(['cc', '-c', 'src.c']))
+ eq(True, test(['c++', '-c', 'src.c']))
+ eq(False, test(['clang', '-c', 'src.c']))
+ eq(True, test(['clang++', '-c', 'src.c']))
+ eq(False, test(['gcc', '-c', 'src.c']))
+ eq(True, test(['g++', '-c', 'src.c']))
diff --git a/tools/scan-build-py/tests/unit/test_intercept.py b/tools/scan-build-py/tests/unit/test_intercept.py
new file mode 100644
index 000000000000..b6f01f36eeb3
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/test_intercept.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import libscanbuild.intercept as sut
+from . import fixtures
+import os.path
+
+
+class InterceptUtilTest(fixtures.TestCase):
+
+ def test_is_compiler_call_filter(self):
+ def test(command):
+ return sut.is_compiler_call({'command': [command]})
+
+ self.assertTrue(test('clang'))
+ self.assertTrue(test('clang-3.6'))
+ self.assertTrue(test('clang++'))
+ self.assertTrue(test('clang++-3.5.1'))
+ self.assertTrue(test('cc'))
+ self.assertTrue(test('c++'))
+ self.assertTrue(test('gcc'))
+ self.assertTrue(test('g++'))
+ self.assertTrue(test('/usr/local/bin/gcc'))
+ self.assertTrue(test('/usr/local/bin/g++'))
+ self.assertTrue(test('/usr/local/bin/clang'))
+ self.assertTrue(test('armv7_neno-linux-gnueabi-g++'))
+
+ self.assertFalse(test(''))
+ self.assertFalse(test('ld'))
+ self.assertFalse(test('as'))
+ self.assertFalse(test('/usr/local/bin/compiler'))
+
+ def test_format_entry_filters_action(self):
+ def test(command):
+ return list(sut.format_entry(
+ {'command': command, 'directory': '/opt/src/project'}))
+
+ self.assertTrue(test(['cc', '-c', 'file.c', '-o', 'file.o']))
+ self.assertFalse(test(['cc', '-E', 'file.c']))
+ self.assertFalse(test(['cc', '-MM', 'file.c']))
+ self.assertFalse(test(['cc', 'this.o', 'that.o', '-o', 'a.out']))
+ self.assertFalse(test(['cc', '-print-prog-name']))
+
+ def test_format_entry_normalize_filename(self):
+ directory = os.path.join(os.sep, 'home', 'me', 'project')
+
+ def test(command):
+ result = list(sut.format_entry(
+ {'command': command, 'directory': directory}))
+ return result[0]['file']
+
+ self.assertEqual(test(['cc', '-c', 'file.c']),
+ os.path.join(directory, 'file.c'))
+ self.assertEqual(test(['cc', '-c', './file.c']),
+ os.path.join(directory, 'file.c'))
+ self.assertEqual(test(['cc', '-c', '../file.c']),
+ os.path.join(os.path.dirname(directory), 'file.c'))
+ self.assertEqual(test(['cc', '-c', '/opt/file.c']),
+ '/opt/file.c')
+
+ def test_sip(self):
+ def create_status_report(filename, message):
+ content = """#!/usr/bin/env sh
+ echo 'sa-la-la-la'
+ echo 'la-la-la'
+ echo '{0}'
+ echo 'sa-la-la-la'
+ echo 'la-la-la'
+ """.format(message)
+ lines = [line.strip() for line in content.split('\n')]
+ with open(filename, 'w') as handle:
+ handle.write('\n'.join(lines))
+ handle.close()
+ os.chmod(filename, 0x1ff)
+
+ def create_csrutil(dest_dir, status):
+ filename = os.path.join(dest_dir, 'csrutil')
+ message = 'System Integrity Protection status: {0}'.format(status)
+ return create_status_report(filename, message)
+
+ def create_sestatus(dest_dir, status):
+ filename = os.path.join(dest_dir, 'sestatus')
+ message = 'SELinux status:\t{0}'.format(status)
+ return create_status_report(filename, message)
+
+ ENABLED = 'enabled'
+ DISABLED = 'disabled'
+
+ OSX = 'darwin'
+ LINUX = 'linux'
+
+ with fixtures.TempDir() as tmpdir:
+ try:
+ saved = os.environ['PATH']
+ os.environ['PATH'] = tmpdir + ':' + saved
+
+ create_csrutil(tmpdir, ENABLED)
+ self.assertTrue(sut.is_preload_disabled(OSX))
+
+ create_csrutil(tmpdir, DISABLED)
+ self.assertFalse(sut.is_preload_disabled(OSX))
+
+ create_sestatus(tmpdir, ENABLED)
+ self.assertTrue(sut.is_preload_disabled(LINUX))
+
+ create_sestatus(tmpdir, DISABLED)
+ self.assertFalse(sut.is_preload_disabled(LINUX))
+ finally:
+ os.environ['PATH'] = saved
+
+ try:
+ saved = os.environ['PATH']
+ os.environ['PATH'] = ''
+ # shall be false when it's not in the path
+ self.assertFalse(sut.is_preload_disabled(OSX))
+ self.assertFalse(sut.is_preload_disabled(LINUX))
+
+ self.assertFalse(sut.is_preload_disabled('unix'))
+ finally:
+ os.environ['PATH'] = saved
diff --git a/tools/scan-build-py/tests/unit/test_report.py b/tools/scan-build-py/tests/unit/test_report.py
new file mode 100644
index 000000000000..d505afc20a89
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/test_report.py
@@ -0,0 +1,146 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import libscanbuild.report as sut
+from . import fixtures
+import unittest
+import os
+import os.path
+
+
+def run_bug_parse(content):
+ with fixtures.TempDir() as tmpdir:
+ file_name = os.path.join(tmpdir, 'test.html')
+ with open(file_name, 'w') as handle:
+ handle.writelines(content)
+ for bug in sut.parse_bug_html(file_name):
+ return bug
+
+
+def run_crash_parse(content, preproc):
+ with fixtures.TempDir() as tmpdir:
+ file_name = os.path.join(tmpdir, preproc + '.info.txt')
+ with open(file_name, 'w') as handle:
+ handle.writelines(content)
+ return sut.parse_crash(file_name)
+
+
+class ParseFileTest(unittest.TestCase):
+
+ def test_parse_bug(self):
+ content = [
+ "some header\n",
+ "<!-- BUGDESC Division by zero -->\n",
+ "<!-- BUGTYPE Division by zero -->\n",
+ "<!-- BUGCATEGORY Logic error -->\n",
+ "<!-- BUGFILE xx -->\n",
+ "<!-- BUGLINE 5 -->\n",
+ "<!-- BUGCOLUMN 22 -->\n",
+ "<!-- BUGPATHLENGTH 4 -->\n",
+ "<!-- BUGMETAEND -->\n",
+ "<!-- REPORTHEADER -->\n",
+ "some tails\n"]
+ result = run_bug_parse(content)
+ self.assertEqual(result['bug_category'], 'Logic error')
+ self.assertEqual(result['bug_path_length'], 4)
+ self.assertEqual(result['bug_line'], 5)
+ self.assertEqual(result['bug_description'], 'Division by zero')
+ self.assertEqual(result['bug_type'], 'Division by zero')
+ self.assertEqual(result['bug_file'], 'xx')
+
+ def test_parse_bug_empty(self):
+ content = []
+ result = run_bug_parse(content)
+ self.assertEqual(result['bug_category'], 'Other')
+ self.assertEqual(result['bug_path_length'], 1)
+ self.assertEqual(result['bug_line'], 0)
+
+ def test_parse_crash(self):
+ content = [
+ "/some/path/file.c\n",
+ "Some very serious Error\n",
+ "bla\n",
+ "bla-bla\n"]
+ result = run_crash_parse(content, 'file.i')
+ self.assertEqual(result['source'], content[0].rstrip())
+ self.assertEqual(result['problem'], content[1].rstrip())
+ self.assertEqual(os.path.basename(result['file']),
+ 'file.i')
+ self.assertEqual(os.path.basename(result['info']),
+ 'file.i.info.txt')
+ self.assertEqual(os.path.basename(result['stderr']),
+ 'file.i.stderr.txt')
+
+ def test_parse_real_crash(self):
+ import libscanbuild.runner as sut2
+ import re
+ with fixtures.TempDir() as tmpdir:
+ filename = os.path.join(tmpdir, 'test.c')
+ with open(filename, 'w') as handle:
+ handle.write('int main() { return 0')
+ # produce failure report
+ opts = {'directory': os.getcwd(),
+ 'clang': 'clang',
+ 'file': filename,
+ 'report': ['-fsyntax-only', '-E', filename],
+ 'language': 'c',
+ 'output_dir': tmpdir,
+ 'error_type': 'other_error',
+ 'error_output': 'some output',
+ 'exit_code': 13}
+ sut2.report_failure(opts)
+ # find the info file
+ pp_file = None
+ for root, _, files in os.walk(tmpdir):
+ keys = [os.path.join(root, name) for name in files]
+ for key in keys:
+ if re.match(r'^(.*/)+clang(.*)\.i$', key):
+ pp_file = key
+ self.assertIsNot(pp_file, None)
+ # read the failure report back
+ result = sut.parse_crash(pp_file + '.info.txt')
+ self.assertEqual(result['source'], filename)
+ self.assertEqual(result['problem'], 'Other Error')
+ self.assertEqual(result['file'], pp_file)
+ self.assertEqual(result['info'], pp_file + '.info.txt')
+ self.assertEqual(result['stderr'], pp_file + '.stderr.txt')
+
+
+class ReportMethodTest(unittest.TestCase):
+
+ def test_chop(self):
+ self.assertEqual('file', sut.chop('/prefix', '/prefix/file'))
+ self.assertEqual('file', sut.chop('/prefix/', '/prefix/file'))
+ self.assertEqual('lib/file', sut.chop('/prefix/', '/prefix/lib/file'))
+ self.assertEqual('/prefix/file', sut.chop('', '/prefix/file'))
+
+ def test_chop_when_cwd(self):
+ self.assertEqual('../src/file', sut.chop('/cwd', '/src/file'))
+ self.assertEqual('../src/file', sut.chop('/prefix/cwd',
+ '/prefix/src/file'))
+
+
+class GetPrefixFromCompilationDatabaseTest(fixtures.TestCase):
+
+ def test_with_different_filenames(self):
+ self.assertEqual(
+ sut.commonprefix(['/tmp/a.c', '/tmp/b.c']), '/tmp')
+
+ def test_with_different_dirnames(self):
+ self.assertEqual(
+ sut.commonprefix(['/tmp/abs/a.c', '/tmp/ack/b.c']), '/tmp')
+
+ def test_no_common_prefix(self):
+ self.assertEqual(
+ sut.commonprefix(['/tmp/abs/a.c', '/usr/ack/b.c']), '/')
+
+ def test_with_single_file(self):
+ self.assertEqual(
+ sut.commonprefix(['/tmp/a.c']), '/tmp')
+
+ def test_empty(self):
+ self.assertEqual(
+ sut.commonprefix([]), '')
diff --git a/tools/scan-build-py/tests/unit/test_runner.py b/tools/scan-build-py/tests/unit/test_runner.py
new file mode 100644
index 000000000000..ea10051d8506
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/test_runner.py
@@ -0,0 +1,213 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import libscanbuild.runner as sut
+from . import fixtures
+import unittest
+import re
+import os
+import os.path
+
+
+def run_analyzer(content, opts):
+ with fixtures.TempDir() as tmpdir:
+ filename = os.path.join(tmpdir, 'test.cpp')
+ with open(filename, 'w') as handle:
+ handle.write(content)
+
+ opts.update({
+ 'directory': os.getcwd(),
+ 'clang': 'clang',
+ 'file': filename,
+ 'language': 'c++',
+ 'analyze': ['--analyze', '-x', 'c++', filename],
+ 'output': ['-o', tmpdir]})
+ spy = fixtures.Spy()
+ result = sut.run_analyzer(opts, spy.call)
+ return (result, spy.arg)
+
+
+class RunAnalyzerTest(unittest.TestCase):
+
+ def test_run_analyzer(self):
+ content = "int div(int n, int d) { return n / d; }"
+ (result, fwds) = run_analyzer(content, dict())
+ self.assertEqual(None, fwds)
+ self.assertEqual(0, result['exit_code'])
+
+ def test_run_analyzer_crash(self):
+ content = "int div(int n, int d) { return n / d }"
+ (result, fwds) = run_analyzer(content, dict())
+ self.assertEqual(None, fwds)
+ self.assertEqual(1, result['exit_code'])
+
+ def test_run_analyzer_crash_and_forwarded(self):
+ content = "int div(int n, int d) { return n / d }"
+ (_, fwds) = run_analyzer(content, {'output_failures': True})
+ self.assertEqual('crash', fwds['error_type'])
+ self.assertEqual(1, fwds['exit_code'])
+ self.assertTrue(len(fwds['error_output']) > 0)
+
+
+class SetAnalyzerOutputTest(fixtures.TestCase):
+
+ def test_not_defined(self):
+ with fixtures.TempDir() as tmpdir:
+ opts = {'output_dir': tmpdir}
+ spy = fixtures.Spy()
+ sut.set_analyzer_output(opts, spy.call)
+ self.assertTrue(os.path.exists(spy.arg['output'][1]))
+ self.assertTrue(os.path.isdir(spy.arg['output'][1]))
+
+ def test_html(self):
+ with fixtures.TempDir() as tmpdir:
+ opts = {'output_dir': tmpdir, 'output_format': 'html'}
+ spy = fixtures.Spy()
+ sut.set_analyzer_output(opts, spy.call)
+ self.assertTrue(os.path.exists(spy.arg['output'][1]))
+ self.assertTrue(os.path.isdir(spy.arg['output'][1]))
+
+ def test_plist_html(self):
+ with fixtures.TempDir() as tmpdir:
+ opts = {'output_dir': tmpdir, 'output_format': 'plist-html'}
+ spy = fixtures.Spy()
+ sut.set_analyzer_output(opts, spy.call)
+ self.assertTrue(os.path.exists(spy.arg['output'][1]))
+ self.assertTrue(os.path.isfile(spy.arg['output'][1]))
+
+ def test_plist(self):
+ with fixtures.TempDir() as tmpdir:
+ opts = {'output_dir': tmpdir, 'output_format': 'plist'}
+ spy = fixtures.Spy()
+ sut.set_analyzer_output(opts, spy.call)
+ self.assertTrue(os.path.exists(spy.arg['output'][1]))
+ self.assertTrue(os.path.isfile(spy.arg['output'][1]))
+
+
+class ReportFailureTest(fixtures.TestCase):
+
+ def assertUnderFailures(self, path):
+ self.assertEqual('failures', os.path.basename(os.path.dirname(path)))
+
+ def test_report_failure_create_files(self):
+ with fixtures.TempDir() as tmpdir:
+ # create input file
+ filename = os.path.join(tmpdir, 'test.c')
+ with open(filename, 'w') as handle:
+ handle.write('int main() { return 0')
+ uname_msg = ' '.join(os.uname()) + os.linesep
+ error_msg = 'this is my error output'
+ # execute test
+ opts = {'directory': os.getcwd(),
+ 'clang': 'clang',
+ 'file': filename,
+ 'report': ['-fsyntax-only', '-E', filename],
+ 'language': 'c',
+ 'output_dir': tmpdir,
+ 'error_type': 'other_error',
+ 'error_output': error_msg,
+ 'exit_code': 13}
+ sut.report_failure(opts)
+ # verify the result
+ result = dict()
+ pp_file = None
+ for root, _, files in os.walk(tmpdir):
+ keys = [os.path.join(root, name) for name in files]
+ for key in keys:
+ with open(key, 'r') as handle:
+ result[key] = handle.readlines()
+ if re.match(r'^(.*/)+clang(.*)\.i$', key):
+ pp_file = key
+
+ # prepocessor file generated
+ self.assertUnderFailures(pp_file)
+ # info file generated and content dumped
+ info_file = pp_file + '.info.txt'
+ self.assertIn(info_file, result)
+ self.assertEqual('Other Error\n', result[info_file][1])
+ self.assertEqual(uname_msg, result[info_file][3])
+ # error file generated and content dumped
+ error_file = pp_file + '.stderr.txt'
+ self.assertIn(error_file, result)
+ self.assertEqual([error_msg], result[error_file])
+
+
+class AnalyzerTest(unittest.TestCase):
+
+ def test_set_language(self):
+ def test(expected, input):
+ spy = fixtures.Spy()
+ self.assertEqual(spy.success, sut.language_check(input, spy.call))
+ self.assertEqual(expected, spy.arg['language'])
+
+ l = 'language'
+ f = 'file'
+ i = 'c++'
+ test('c', {f: 'file.c', l: 'c', i: False})
+ test('c++', {f: 'file.c', l: 'c++', i: False})
+ test('c++', {f: 'file.c', i: True})
+ test('c', {f: 'file.c', i: False})
+ test('c++', {f: 'file.cxx', i: False})
+ test('c-cpp-output', {f: 'file.i', i: False})
+ test('c++-cpp-output', {f: 'file.i', i: True})
+ test('c-cpp-output', {f: 'f.i', l: 'c-cpp-output', i: True})
+
+ def test_arch_loop(self):
+ def test(input):
+ spy = fixtures.Spy()
+ sut.arch_check(input, spy.call)
+ return spy.arg
+
+ input = {'key': 'value'}
+ self.assertEqual(input, test(input))
+
+ input = {'archs_seen': ['i386']}
+ self.assertEqual({'arch': 'i386'}, test(input))
+
+ input = {'archs_seen': ['ppc']}
+ self.assertEqual(None, test(input))
+
+ input = {'archs_seen': ['i386', 'ppc']}
+ self.assertEqual({'arch': 'i386'}, test(input))
+
+ input = {'archs_seen': ['i386', 'sparc']}
+ result = test(input)
+ self.assertTrue(result == {'arch': 'i386'} or
+ result == {'arch': 'sparc'})
+
+
+@sut.require([])
+def method_without_expecteds(opts):
+ return 0
+
+
+@sut.require(['this', 'that'])
+def method_with_expecteds(opts):
+ return 0
+
+
+@sut.require([])
+def method_exception_from_inside(opts):
+ raise Exception('here is one')
+
+
+class RequireDecoratorTest(unittest.TestCase):
+
+ def test_method_without_expecteds(self):
+ self.assertEqual(method_without_expecteds(dict()), 0)
+ self.assertEqual(method_without_expecteds({}), 0)
+ self.assertEqual(method_without_expecteds({'this': 2}), 0)
+ self.assertEqual(method_without_expecteds({'that': 3}), 0)
+
+ def test_method_with_expecteds(self):
+ self.assertRaises(KeyError, method_with_expecteds, dict())
+ self.assertRaises(KeyError, method_with_expecteds, {})
+ self.assertRaises(KeyError, method_with_expecteds, {'this': 2})
+ self.assertRaises(KeyError, method_with_expecteds, {'that': 3})
+ self.assertEqual(method_with_expecteds({'this': 0, 'that': 3}), 0)
+
+ def test_method_exception_not_caught(self):
+ self.assertRaises(Exception, method_exception_from_inside, dict())
diff --git a/tools/scan-build-py/tests/unit/test_shell.py b/tools/scan-build-py/tests/unit/test_shell.py
new file mode 100644
index 000000000000..a2904b07f5bc
--- /dev/null
+++ b/tools/scan-build-py/tests/unit/test_shell.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+
+import libscanbuild.shell as sut
+import unittest
+
+
+class ShellTest(unittest.TestCase):
+
+ def test_encode_decode_are_same(self):
+ def test(value):
+ self.assertEqual(sut.encode(sut.decode(value)), value)
+
+ test("")
+ test("clang")
+ test("clang this and that")
+
+ def test_decode_encode_are_same(self):
+ def test(value):
+ self.assertEqual(sut.decode(sut.encode(value)), value)
+
+ test([])
+ test(['clang'])
+ test(['clang', 'this', 'and', 'that'])
+ test(['clang', 'this and', 'that'])
+ test(['clang', "it's me", 'again'])
+ test(['clang', 'some "words" are', 'quoted'])
+
+ def test_encode(self):
+ self.assertEqual(sut.encode(['clang', "it's me", 'again']),
+ 'clang "it\'s me" again')
+ self.assertEqual(sut.encode(['clang', "it(s me", 'again)']),
+ 'clang "it(s me" "again)"')
+ self.assertEqual(sut.encode(['clang', 'redirect > it']),
+ 'clang "redirect > it"')
+ self.assertEqual(sut.encode(['clang', '-DKEY="VALUE"']),
+ 'clang -DKEY=\\"VALUE\\"')
+ self.assertEqual(sut.encode(['clang', '-DKEY="value with spaces"']),
+ 'clang -DKEY=\\"value with spaces\\"')
diff --git a/unittests/AST/SourceLocationTest.cpp b/unittests/AST/SourceLocationTest.cpp
index 4c77def61bc4..9fae8d862aef 100644
--- a/unittests/AST/SourceLocationTest.cpp
+++ b/unittests/AST/SourceLocationTest.cpp
@@ -542,5 +542,43 @@ TEST(ObjCMessageExpr, CXXConstructExprRange) {
cxxConstructExpr(), Lang_OBJCXX));
}
+TEST(FunctionDecl, FunctionDeclWithThrowSpecification) {
+ RangeVerifier<FunctionDecl> Verifier;
+ Verifier.expectRange(1, 1, 1, 16);
+ EXPECT_TRUE(Verifier.match(
+ "void f() throw();\n",
+ functionDecl()));
+}
+
+TEST(FunctionDecl, FunctionDeclWithNoExceptSpecification) {
+ RangeVerifier<FunctionDecl> Verifier;
+ Verifier.expectRange(1, 1, 1, 24);
+ EXPECT_TRUE(Verifier.match(
+ "void f() noexcept(false);\n",
+ functionDecl(),
+ Language::Lang_CXX11));
+}
+
+TEST(CXXMethodDecl, CXXMethodDeclWithThrowSpecification) {
+ RangeVerifier<FunctionDecl> Verifier;
+ Verifier.expectRange(2, 1, 2, 16);
+ EXPECT_TRUE(Verifier.match(
+ "class A {\n"
+ "void f() throw();\n"
+ "};\n",
+ functionDecl()));
+}
+
+TEST(CXXMethodDecl, CXXMethodDeclWithNoExceptSpecification) {
+ RangeVerifier<FunctionDecl> Verifier;
+ Verifier.expectRange(2, 1, 2, 24);
+ EXPECT_TRUE(Verifier.match(
+ "class A {\n"
+ "void f() noexcept(false);\n"
+ "};\n",
+ functionDecl(),
+ Language::Lang_CXX11));
+}
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/unittests/Basic/VirtualFileSystemTest.cpp b/unittests/Basic/VirtualFileSystemTest.cpp
index ac07035d3e1f..7abc549292e2 100644
--- a/unittests/Basic/VirtualFileSystemTest.cpp
+++ b/unittests/Basic/VirtualFileSystemTest.cpp
@@ -370,14 +370,6 @@ TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
EXPECT_EQ(1, Counts[3]); // d
}
-template <typename T, size_t N>
-std::vector<StringRef> makeStringRefVector(const T (&Arr)[N]) {
- std::vector<StringRef> Vec;
- for (size_t i = 0; i != N; ++i)
- Vec.push_back(Arr[i]);
- return Vec;
-}
-
template <typename DirIter>
static void checkContents(DirIter I, ArrayRef<StringRef> Expected) {
std::error_code EC;
@@ -405,20 +397,14 @@ TEST(VirtualFileSystemTest, OverlayIteration) {
checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
Upper->addRegularFile("/file2");
- {
- const char *Contents[] = {"/file2", "/file1"};
- checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
- }
+ checkContents(O->dir_begin("/", EC), {"/file2", "/file1"});
Lower->addDirectory("/dir1");
Lower->addRegularFile("/dir1/foo");
Upper->addDirectory("/dir2");
Upper->addRegularFile("/dir2/foo");
checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
- {
- const char *Contents[] = {"/dir2", "/file2", "/dir1", "/file1"};
- checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
- }
+ checkContents(O->dir_begin("/", EC), {"/dir2", "/file2", "/dir1", "/file1"});
}
TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
@@ -440,11 +426,8 @@ TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
Upper->addDirectory("/dir");
Upper->addRegularFile("/dir/file2");
- {
- const char *Contents[] = {"/dir", "/dir/file2", "/file1"};
- checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
- makeStringRefVector(Contents));
- }
+ checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
+ {"/dir", "/dir/file2", "/file1"});
Lower->addDirectory("/dir1");
Lower->addRegularFile("/dir1/foo");
@@ -460,13 +443,10 @@ TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
Upper->addRegularFile("/hiddenByUp");
checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
ArrayRef<StringRef>("/dir2/foo"));
- {
- const char *Contents[] = { "/dir", "/dir/file2", "/dir2", "/dir2/foo",
- "/hiddenByUp", "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
- "/dir1/a/b", "/dir1/foo", "/file1" };
- checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
- makeStringRefVector(Contents));
- }
+ checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
+ {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
+ "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
+ "/dir1/a/b", "/dir1/foo", "/file1"});
}
TEST(VirtualFileSystemTest, ThreeLevelIteration) {
@@ -486,10 +466,7 @@ TEST(VirtualFileSystemTest, ThreeLevelIteration) {
Lower->addRegularFile("/file1");
Upper->addRegularFile("/file3");
- {
- const char *Contents[] = {"/file3", "/file2", "/file1"};
- checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
- }
+ checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"});
}
TEST(VirtualFileSystemTest, HiddenInIteration) {
@@ -510,11 +487,9 @@ TEST(VirtualFileSystemTest, HiddenInIteration) {
Middle->addRegularFile("/hiddenByUp", sys::fs::owner_write);
Upper->addRegularFile("/onlyInUp", sys::fs::owner_all);
Upper->addRegularFile("/hiddenByUp", sys::fs::owner_all);
- {
- const char *Contents[] = {"/hiddenByUp", "/onlyInUp", "/hiddenByMid",
- "/onlyInMid", "/onlyInLow"};
- checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
- }
+ checkContents(
+ O->dir_begin("/", EC),
+ {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
// Make sure we get the top-most entry
{
@@ -657,6 +632,18 @@ TEST_F(InMemoryFileSystemTest, WorkingDirectory) {
Stat = FS.status("c");
ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+
+ auto ReplaceBackslashes = [](std::string S) {
+ std::replace(S.begin(), S.end(), '\\', '/');
+ return S;
+ };
+ NormalizedFS.setCurrentWorkingDirectory("/b/c");
+ NormalizedFS.setCurrentWorkingDirectory(".");
+ ASSERT_EQ("/b/c", ReplaceBackslashes(
+ NormalizedFS.getCurrentWorkingDirectory().get()));
+ NormalizedFS.setCurrentWorkingDirectory("..");
+ ASSERT_EQ("/b", ReplaceBackslashes(
+ NormalizedFS.getCurrentWorkingDirectory().get()));
}
// NOTE: in the tests below, we use '//root/' as our root directory, since it is
@@ -1067,15 +1054,9 @@ TEST_F(VFSFromYAMLTest, DirectoryIteration) {
O->pushOverlay(FS);
std::error_code EC;
- {
- const char *Contents[] = {"//root/file1", "//root/file2", "//root/file3",
- "//root/foo"};
- checkContents(O->dir_begin("//root/", EC), makeStringRefVector(Contents));
- }
+ checkContents(O->dir_begin("//root/", EC),
+ {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
- {
- const char *Contents[] = {"//root/foo/bar/a", "//root/foo/bar/b"};
- checkContents(O->dir_begin("//root/foo/bar", EC),
- makeStringRefVector(Contents));
- }
+ checkContents(O->dir_begin("//root/foo/bar", EC),
+ {"//root/foo/bar/a", "//root/foo/bar/b"});
}
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index c940bc75c80e..30fd6030dcc8 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -1022,6 +1022,15 @@ TEST_F(FormatTest, UnderstandsSingleLineComments) {
" lineWith(); // comment\n"
" // at start\n"
"}"));
+ EXPECT_EQ("int xy; // a\n"
+ "int z; // b",
+ format("int xy; // a\n"
+ "int z; //b"));
+ EXPECT_EQ("int xy; // a\n"
+ "int z; // bb",
+ format("int xy; // a\n"
+ "int z; //bb",
+ getLLVMStyleWithColumns(12)));
verifyFormat("#define A \\\n"
" int i; /* iiiiiiiiiiiiiiiiiiiii */ \\\n"
@@ -3607,6 +3616,7 @@ TEST_F(FormatTest, ConstructorInitializers) {
FormatStyle OnePerLine = getLLVMStyle();
OnePerLine.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
+ OnePerLine.AllowAllParametersOfDeclarationOnNextLine = false;
verifyFormat("SomeClass::Constructor()\n"
" : aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
" aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
@@ -3633,6 +3643,13 @@ TEST_F(FormatTest, ConstructorInitializers) {
" : aaaaa(aaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaa,\n"
" aaaaaaaaaaaaaaaaaaaaaa) {}",
OnePerLine);
+ OnePerLine.BinPackParameters = false;
+ verifyFormat(
+ "Constructor()\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaa().aaa(),\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}",
+ OnePerLine);
OnePerLine.ColumnLimit = 60;
verifyFormat("Constructor()\n"
" : aaaaaaaaaaaaaaaaaaaa(a),\n"
@@ -4054,6 +4071,23 @@ TEST_F(FormatTest, FormatsDeclarationsOnePerLine) {
" int aaaaaaaaaaaaaaaaaaaa,\n"
" int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}",
NoBinPacking);
+
+ NoBinPacking.AllowAllParametersOfDeclarationOnNextLine = false;
+ verifyFormat("void aaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " vector<int> bbbbbbbbbbbbbbb);",
+ NoBinPacking);
+ // FIXME: This behavior difference is probably not wanted. However, currently
+ // we cannot distinguish BreakBeforeParameter being set because of the wrapped
+ // template arguments from BreakBeforeParameter being set because of the
+ // one-per-line formatting.
+ verifyFormat(
+ "void fffffffffff(aaaaaaaaaaaaaaaaaaaaaaaaaaa<aaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaa> aaaaaaaaaa);",
+ NoBinPacking);
+ verifyFormat(
+ "void fffffffffff(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa<aaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaa>\n"
+ " aaaaaaaaaa);");
}
TEST_F(FormatTest, FormatsOneParameterPerLineIfNecessary) {
@@ -5450,6 +5484,7 @@ TEST_F(FormatTest, UnderstandsOverloadedOperators) {
verifyFormat("bool operator!=();");
verifyFormat("int operator+();");
verifyFormat("int operator++();");
+ verifyFormat("bool operator,();");
verifyFormat("bool operator();");
verifyFormat("bool operator()();");
verifyFormat("bool operator[]();");
@@ -5465,6 +5500,8 @@ TEST_F(FormatTest, UnderstandsOverloadedOperators) {
verifyFormat("void operator delete[](void *ptr);");
verifyFormat("template <typename AAAAAAA, typename BBBBBBB>\n"
"AAAAAAA operator/(const AAAAAAA &a, BBBBBBB &b);");
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaa operator,(\n"
+ " aaaaaaaaaaaaaaaaaaaaa &aaaaaaaaaaaaaaaaaaaaaaaaaa) const;");
verifyFormat(
"ostream &operator<<(ostream &OutputStream,\n"
@@ -7726,7 +7763,12 @@ TEST_F(FormatTest, ObjCArrayLiterals) {
" aaaa == bbbbbbbbbbb ? @\"aaaaaaaaaaaa\" : @\"aaaaaaaaaaaaaa\",\n"
" @\"aaaaaaaaaaaaaaaaa\",\n"
" @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\"\n"
+ " @\"aaaaaaaaaaaaaaaaa\",\n"
+ "];");
+ verifyFormat(
+ "NSArray *some_variable = @[\n"
+ " aaaa == bbbbbbbbbbb ? @\"aaaaaaaaaaaa\" : @\"aaaaaaaaaaaaaa\",\n"
+ " @\"aaaaaaaaaaaaaaaa\", @\"aaaaaaaaaaaaaaaa\", @\"aaaaaaaaaaaaaaaa\"\n"
"];");
verifyFormat("NSArray *some_variable = @[\n"
" @\"aaaaaaaaaaaaaaaaa\",\n"
@@ -7734,12 +7776,6 @@ TEST_F(FormatTest, ObjCArrayLiterals) {
" @\"aaaaaaaaaaaaaaaaa\",\n"
" @\"aaaaaaaaaaaaaaaaa\",\n"
"];");
- verifyGoogleFormat("NSArray *some_variable = @[\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\",\n"
- " @\"aaaaaaaaaaaaaaaaa\"\n"
- "];");
verifyFormat("NSArray *array = @[\n"
" @\"a\",\n"
" @\"a\",\n" // Trailing comma -> one per line.
@@ -10630,6 +10666,7 @@ TEST_F(FormatTest, FormatsLambdas) {
// Lambdas created through weird macros.
verifyFormat("void f() {\n"
" MACRO((const AA &a) { return 1; });\n"
+ " MACRO((AA &a) { return 1; });\n"
"}");
verifyFormat("if (blah_blah(whatever, whatever, [] {\n"
diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp
index 2f67bdf549ca..0e0f64a31ac6 100644
--- a/unittests/Format/FormatTestJS.cpp
+++ b/unittests/Format/FormatTestJS.cpp
@@ -284,13 +284,16 @@ TEST_F(FormatTestJS, ArrayLiterals) {
verifyFormat("var aaaaa: List<SomeThing> =\n"
" [new SomeThingAAAAAAAAAAAA(), new SomeThingBBBBBBBBB()];");
verifyFormat("return [\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
" ccccccccccccccccccccccccccc\n"
"];");
+ verifyFormat("return [\n"
+ " aaaa().bbbbbbbb('A'),\n"
+ " aaaa().bbbbbbbb('B'),\n"
+ " aaaa().bbbbbbbb('C'),\n"
+ "];");
verifyFormat("var someVariable = SomeFunction([\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
" ccccccccccccccccccccccccccc\n"
"]);");
verifyFormat("var someVariable = SomeFunction([\n"
@@ -298,16 +301,14 @@ TEST_F(FormatTestJS, ArrayLiterals) {
"]);",
getGoogleJSStyleWithColumns(51));
verifyFormat("var someVariable = SomeFunction(aaaa, [\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
" ccccccccccccccccccccccccccc\n"
"]);");
verifyFormat("var someVariable = SomeFunction(\n"
" aaaa,\n"
" [\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
- " ccccccccccccccccccccccccccc\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
+ " cccccccccccccccccccccccccc\n"
" ],\n"
" aaaa);");
verifyFormat("var aaaa = aaaaa || // wrap\n"
@@ -525,6 +526,12 @@ TEST_F(FormatTestJS, MultipleFunctionLiterals) {
verifyFormat("getSomeLongPromise()\n"
" .then(function(value) { body(); })\n"
" .thenCatch(function(error) { body(); });");
+
+ verifyFormat("return [aaaaaaaaaaaaaaaaaaaaaa]\n"
+ " .aaaaaaa(function() {\n"
+ " //\n"
+ " })\n"
+ " .bbbbbb();");
}
TEST_F(FormatTestJS, ArrowFunctions) {
@@ -726,15 +733,22 @@ TEST_F(FormatTestJS, RegexLiteralExamples) {
TEST_F(FormatTestJS, TypeAnnotations) {
verifyFormat("var x: string;");
+ verifyFormat("var x: {a: string; b: number;} = {};");
verifyFormat("function x(): string {\n return 'x';\n}");
verifyFormat("function x(): {x: string} {\n return {x: 'x'};\n}");
verifyFormat("function x(y: string): string {\n return 'x';\n}");
verifyFormat("for (var y: string in x) {\n x();\n}");
+ verifyFormat("function x(y: {a?: number;} = {}): number {\n"
+ " return 12;\n"
+ "}");
verifyFormat("((a: string, b: number): string => a + b);");
verifyFormat("var x: (y: number) => string;");
verifyFormat("var x: P<string, (a: number) => string>;");
verifyFormat("var x = {y: function(): z { return 1; }};");
verifyFormat("var x = {y: function(): {a: number} { return 1; }};");
+ verifyFormat("function someFunc(args: string[]):\n"
+ " {longReturnValue: string[]} {}",
+ getGoogleJSStyleWithColumns(60));
}
TEST_F(FormatTestJS, ClassDeclarations) {
@@ -750,6 +764,16 @@ TEST_F(FormatTestJS, ClassDeclarations) {
" aaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaaa):\n"
" aaaaaaaaaaaaaaaaaaaaaa {}\n"
"}");
+ verifyFormat("foo = class Name {\n"
+ " constructor() {}\n"
+ "};");
+ verifyFormat("foo = class {\n"
+ " constructor() {}\n"
+ "};");
+ verifyFormat("class C {\n"
+ " x: {y: Z;} = {};\n"
+ " private y: {y: Z;} = {};\n"
+ "}");
// ':' is not a type declaration here.
verifyFormat("class X {\n"
@@ -812,6 +836,7 @@ TEST_F(FormatTestJS, MetadataAnnotations) {
TEST_F(FormatTestJS, Modules) {
verifyFormat("import SomeThing from 'some/module.js';");
verifyFormat("import {X, Y} from 'some/module.js';");
+ verifyFormat("import a, {X, Y} from 'some/module.js';");
verifyFormat("import {\n"
" VeryLongImportsAreAnnoying,\n"
" VeryLongImportsAreAnnoying,\n"
@@ -849,6 +874,7 @@ TEST_F(FormatTestJS, Modules) {
" y: string;\n"
"}");
verifyFormat("export class X { y: number; }");
+ verifyFormat("export abstract class X { y: number; }");
verifyFormat("export default class X { y: number }");
verifyFormat("export default function() {\n return 1;\n}");
verifyFormat("export var x = 12;");
@@ -871,6 +897,10 @@ TEST_F(FormatTestJS, Modules) {
"];");
verifyFormat("export default [];");
verifyFormat("export default () => {};");
+ verifyFormat("export interface Foo { foo: number; }\n"
+ "export class Bar {\n"
+ " blah(): string { return this.blah; };\n"
+ "}");
}
TEST_F(FormatTestJS, TemplateStrings) {
@@ -933,6 +963,9 @@ TEST_F(FormatTestJS, TemplateStrings) {
"var y;");
verifyFormat("var x = `\"`; // comment with matching quote \"\n"
"var y;");
+ EXPECT_EQ("it(`'aaaaaaaaaaaaaaa `, aaaaaaaaa);",
+ format("it(`'aaaaaaaaaaaaaaa `, aaaaaaaaa) ;",
+ getGoogleJSStyleWithColumns(40)));
// Backticks in a comment - not a template string.
EXPECT_EQ("var x = 1 // `/*a`;\n"
" ;",
@@ -1018,5 +1051,15 @@ TEST_F(FormatTestJS, WrapAfterParen) {
" bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}");
}
+TEST_F(FormatTestJS, JSDocAnnotations) {
+ EXPECT_EQ("/**\n"
+ " * @export {this.is.a.long.path.to.a.Type}\n"
+ " */",
+ format("/**\n"
+ " * @export {this.is.a.long.path.to.a.Type}\n"
+ " */",
+ getGoogleJSStyleWithColumns(20)));
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/unittests/Format/FormatTestSelective.cpp b/unittests/Format/FormatTestSelective.cpp
index d53d1c042921..699600c42d9f 100644
--- a/unittests/Format/FormatTestSelective.cpp
+++ b/unittests/Format/FormatTestSelective.cpp
@@ -162,6 +162,13 @@ TEST_F(FormatTestSelective, FormatsCommentsLocally) {
"// This is\n"
"// not formatted. ",
0, 0));
+ EXPECT_EQ("int x; // Format this line.\n"
+ "int xx; //\n"
+ "int xxxxx; //",
+ format("int x; // Format this line.\n"
+ "int xx; //\n"
+ "int xxxxx; //",
+ 0, 0));
}
TEST_F(FormatTestSelective, IndividualStatementsOfNestedBlocks) {