From 3145dc1db9b00410439cc74c67c67a98620c20d6 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 10 Dec 2020 13:54:22 -0800 Subject: [PATCH 1/3] Salvage debug info for function arguments in coro-split funclets. This patch improves the availability for variables stored in the coroutine frame by emitting an alloca to hold the pointer to the frame object and rewriting dbg.declare intrinsics to point inside the frame object using salvaged DIExpressions. rdar://71866936 --- llvm/lib/Transforms/Coroutines/CoroFrame.cpp | 71 +++++++++++++++++-- llvm/lib/Transforms/Coroutines/CoroInternal.h | 5 ++ llvm/lib/Transforms/Coroutines/CoroSplit.cpp | 22 ++++++ .../Coroutines/coro-debug-frame-variable.ll | 8 +-- llvm/test/Transforms/Coroutines/coro-debug.ll | 4 +- 5 files changed, 99 insertions(+), 11 deletions(-) diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 14f4daa925e14..799fff597d07e 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -804,6 +804,7 @@ static Instruction *insertSpills(const SpillInfo &Spills, coro::Shape &Shape) { CurrentValue->getName() + Twine(".reload")); }; + SmallDenseMap DbgPtrAllocaCache; Value *GEP = nullptr, *CurrentGEP = nullptr; for (auto const &E : Spills) { // If we have not seen the value, generate a spill. @@ -896,12 +897,21 @@ static Instruction *insertSpills(const SpillInfo &Spills, coro::Shape &Shape) { if (CurrentGEP != GEP) { CurrentGEP = GEP; TinyPtrVector DIs = FindDbgDeclareUses(CurrentValue); - if (!DIs.empty()) - DIBuilder(*CurrentBlock->getParent()->getParent(), - /*AllowUnresolved*/ false) - .insertDeclare(CurrentGEP, DIs.front()->getVariable(), - DIs.front()->getExpression(), - DIs.front()->getDebugLoc(), DIs.front()); + if (!DIs.empty()) { + auto *DDI = DIs.front(); + bool AllowUnresolved = false; + // This dbg.declare is preserved for all coro-split function + // fragments. It will be unreachable in the main function, and + // processed by coro::salvageDebugInfo() by CoroCloner. + DIBuilder(*CurrentBlock->getParent()->getParent(), AllowUnresolved) + .insertDeclare(CurrentGEP, DDI->getVariable(), + DDI->getExpression(), + DDI->getDebugLoc(), + &*Builder.GetInsertPoint()); + // This dbg.declare is for the main function entry point. It + // will be deleted in all coro-split functions. + coro::salvageDebugInfo(DbgPtrAllocaCache, DDI); + } } // Replace all uses of CurrentValue in the current instruction with reload. @@ -1633,6 +1643,55 @@ static void sinkLifetimeStartMarkers(Function &F, coro::Shape &Shape, } } +void coro::salvageDebugInfo( + SmallDenseMap &DbgPtrAllocaCache, + DbgDeclareInst *DDI, bool LoadFromFramePtr) { + Function *F = DDI->getFunction(); + IRBuilder<> Builder(F->getContext()); + auto InsertPt = F->getEntryBlock().getFirstInsertionPt(); + while (isa(InsertPt)) + ++InsertPt; + Builder.SetInsertPoint(&F->getEntryBlock(), InsertPt); + DIExpression *Expr = DDI->getExpression(); + // Follow the pointer arithmetic all the way to the incoming + // function argument and convert into a DIExpression. + Value *Storage = DDI->getAddress(); + while (Storage) { + if (auto *LdInst = dyn_cast(Storage)) { + Storage = LdInst->getOperand(0); + } else if (auto *GEPInst = dyn_cast(Storage)) { + Expr = llvm::salvageDebugInfoImpl(*GEPInst, Expr, + /*WithStackValue=*/false); + Storage = GEPInst->getOperand(0); + } else if (auto *BCInst = dyn_cast(Storage)) + Storage = BCInst->getOperand(0); + else + break; + } + // Store a pointer to the coroutine frame object in an alloca so it + // is available throughout the function when producing unoptimized + // code. Extending the lifetime this way is correct because the + // variable has been declared by a dbg.declare intrinsic. + if (auto Arg = dyn_cast_or_null(Storage)) { + auto &Cached = DbgPtrAllocaCache[Storage]; + if (!Cached) { + Cached = Builder.CreateAlloca(Storage->getType(), 0, nullptr, + Arg->getName() + ".debug"); + Builder.CreateStore(Storage, Cached); + } + Storage = Cached; + Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore); + } + // The FramePtr object adds one extra layer of indirection that + // needs to be unwrapped. + if (LoadFromFramePtr) + Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore); + auto &VMContext = DDI->getFunction()->getContext(); + DDI->setOperand( + 0, MetadataAsValue::get(VMContext, ValueAsMetadata::get(Storage))); + DDI->setOperand(2, MetadataAsValue::get(VMContext, Expr)); +} + void coro::buildCoroutineFrame(Function &F, Shape &Shape) { eliminateSwiftError(F, Shape); diff --git a/llvm/lib/Transforms/Coroutines/CoroInternal.h b/llvm/lib/Transforms/Coroutines/CoroInternal.h index 49dc3172f66eb..cd1bc6010137f 100644 --- a/llvm/lib/Transforms/Coroutines/CoroInternal.h +++ b/llvm/lib/Transforms/Coroutines/CoroInternal.h @@ -52,6 +52,11 @@ void replaceAllCoroFrees(CoroBeginInst *CB, Value *Replacement); void replaceCoroFree(CoroIdInst *CoroId, bool Elide); void updateCallGraph(Function &Caller, ArrayRef Funcs, CallGraph &CG, CallGraphSCC &SCC); +/// Recover a dbg.declare prepared by the frontend and emit an alloca +/// holding a pointer to the coroutine frame. +void salvageDebugInfo( + SmallDenseMap &DbgPtrAllocaCache, + DbgDeclareInst *DDI, bool LoadFromCoroFrame = false); // Keeps data and helper functions for lowering coroutine intrinsics. struct LowererBase { diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp index 8f698e0a4b625..6eeb89290513b 100644 --- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp @@ -159,6 +159,7 @@ class CoroCloner { void replaceCoroSuspends(); void replaceCoroEnds(); void replaceSwiftErrorOps(); + void salvageDebugInfo(); void handleFinalSuspend(); void maybeFreeContinuationStorage(); }; @@ -584,6 +585,24 @@ void CoroCloner::replaceSwiftErrorOps() { ::replaceSwiftErrorOps(*NewF, Shape, &VMap); } +void CoroCloner::salvageDebugInfo() { + SmallVector Worklist; + SmallDenseMap DbgPtrAllocaCache; + for (auto &BB : *NewF) + for (auto &I : BB) + if (auto *DDI = dyn_cast(&I)) + Worklist.push_back(DDI); + for (DbgDeclareInst *DDI : Worklist) { + // Remove the allocas inserted by CoroFrame for the sake of the + // cloned function. + if (isa(DDI->getAddress())) + DDI->eraseFromParent(); + else + coro::salvageDebugInfo(DbgPtrAllocaCache, DDI, + /*LoadFromFramePointer*/ true); + } +} + void CoroCloner::replaceEntryBlock() { // In the original function, the AllocaSpillBlock is a block immediately // following the allocation of the frame object which defines GEPs for @@ -853,6 +872,9 @@ void CoroCloner::create() { // Remove coro.end intrinsics. replaceCoroEnds(); + // Salvage debug info that points into the coroutine frame. + salvageDebugInfo(); + // Eliminate coro.free from the clones, replacing it with 'null' in cleanup, // to suppress deallocation code. if (Shape.ABI == coro::ABI::Switch) diff --git a/llvm/test/Transforms/Coroutines/coro-debug-frame-variable.ll b/llvm/test/Transforms/Coroutines/coro-debug-frame-variable.ll index ed6b95879e8a5..05d1d3d58bbc7 100644 --- a/llvm/test/Transforms/Coroutines/coro-debug-frame-variable.ll +++ b/llvm/test/Transforms/Coroutines/coro-debug-frame-variable.ll @@ -33,12 +33,12 @@ ; CHECK: call void @llvm.dbg.declare(metadata i32* [[JGEP]], metadata ![[JVAR:[0-9]+]], metadata !DIExpression()), !dbg ![[JDBGLOC:[0-9]+]] ; ; CHECK-LABEL: define internal fastcc void @f.resume({{.*}}) { +; CHECK: %[[DBG_PTR:.*]] = alloca %f.Frame* +; CHECK: store %f.Frame* {{.*}}, %f.Frame** %[[DBG_PTR]] ; CHECK: init.ready: -; CHECK: [[IGEP_RESUME:%.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 -; CHECK: call void @llvm.dbg.declare(metadata i32* [[IGEP_RESUME]], metadata ![[IVAR_RESUME:[0-9]+]], metadata !DIExpression()), !dbg ![[IDBGLOC_RESUME:[0-9]+]] +; CHECK: call void @llvm.dbg.declare(metadata %f.Frame** %[[DBG_PTR]], metadata ![[IVAR_RESUME:[0-9]+]], metadata !DIExpression(DW_OP_deref, DW_OP_deref, DW_OP_plus_uconst, 20)), !dbg ![[IDBGLOC_RESUME:[0-9]+]] ; CHECK: await.ready: -; CHECK: [[JGEP_RESUME:%.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 -; CHECK: call void @llvm.dbg.declare(metadata i32* [[JGEP_RESUME]], metadata ![[JVAR_RESUME:[0-9]+]], metadata !DIExpression()), !dbg ![[JDBGLOC_RESUME:[0-9]+]] +; CHECK: call void @llvm.dbg.declare(metadata %f.Frame** %[[DBG_PTR]], metadata ![[JVAR_RESUME:[0-9]+]], metadata !DIExpression(DW_OP_deref, DW_OP_deref, DW_OP_plus_uconst, 24)), !dbg ![[JDBGLOC_RESUME:[0-9]+]] ; ; CHECK: ![[IVAR]] = !DILocalVariable(name: "i" ; CHECK: ![[SCOPE:[0-9]+]] = distinct !DILexicalBlock(scope: !8, file: !1, line: 23, column: 12) diff --git a/llvm/test/Transforms/Coroutines/coro-debug.ll b/llvm/test/Transforms/Coroutines/coro-debug.ll index b624c88f99ff0..102248359860c 100644 --- a/llvm/test/Transforms/Coroutines/coro-debug.ll +++ b/llvm/test/Transforms/Coroutines/coro-debug.ll @@ -130,8 +130,10 @@ attributes #7 = { noduplicate } ; CHECK: define i8* @f(i32 %x) #0 !dbg ![[ORIG:[0-9]+]] ; CHECK: define internal fastcc void @f.resume(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 !dbg ![[RESUME:[0-9]+]] ; CHECK: entry.resume: +; CHECK-NEXT: %[[DBG_PTR:.*]] = alloca %f.Frame* +; CHECK-NEXT: store %f.Frame* {{.*}}, %f.Frame** %[[DBG_PTR]] ; CHECK-NEXT: call void @coro.devirt.trigger(i8* null) -; CHECK-NEXT: call void @llvm.dbg.declare(metadata i32* %x.addr.reload.addr, metadata ![[RESUME_VAR:[0-9]+]] +; CHECK: call void @llvm.dbg.declare(metadata %f.Frame** %[[DBG_PTR]], metadata ![[RESUME_VAR:[0-9]+]], metadata !DIExpression(DW_OP_deref, DW_OP_deref, DW_OP_plus_uconst, ; CHECK: define internal fastcc void @f.destroy(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 !dbg ![[DESTROY:[0-9]+]] ; CHECK: define internal fastcc void @f.cleanup(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 !dbg ![[CLEANUP:[0-9]+]] From 2eb70c1180a348bbdf318a8db403913fde4ac45a Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Fri, 11 Dec 2020 16:15:53 +0100 Subject: [PATCH 2/3] [lldb] Avoid enum as unordered_map key in TypeSystemClang This apparently doesn't work with the GCC used on Swift CI's Linux bots. --- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp | 5 +++-- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index eba962472b1fc..714df4209bff5 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -9695,14 +9695,15 @@ GetSpecializedASTName(ScratchTypeSystemClang::IsolatedASTKind feature) { } TypeSystemClang &ScratchTypeSystemClang::GetIsolatedAST( - ScratchTypeSystemClang::IsolatedASTKind feature) { + ScratchTypeSystemClang::IsolatedASTKind feature_enum) { + int feature = static_cast(feature_enum); auto found_ast = m_isolated_asts.find(feature); if (found_ast != m_isolated_asts.end()) return *found_ast->second; // Couldn't find the requested sub-AST, so create it now. std::unique_ptr new_ast; - new_ast.reset(new SpecializedScratchAST(GetSpecializedASTName(feature), + new_ast.reset(new SpecializedScratchAST(GetSpecializedASTName(feature_enum), m_triple, CreateASTSource())); m_isolated_asts[feature] = std::move(new_ast); return *m_isolated_asts[feature]; diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index d772447676f31..8abb6f0c5f57e 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -1228,7 +1228,7 @@ class ScratchTypeSystemClang : public TypeSystemClang { /// Map from IsolatedASTKind to their actual TypeSystemClang instance. /// This map is lazily filled with sub-ASTs and should be accessed via /// `GetSubAST` (which lazily fills this map). - std::unordered_map> + std::unordered_map> m_isolated_asts; }; From e6329a0358bc0ed23a5d2c0e7b9788b8b1a7a990 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 7 Oct 2020 14:27:55 -0400 Subject: [PATCH 3/3] [clang] Don't look into for C++ headers if they are found alongside the toolchain Currently, Clang looks for libc++ headers alongside the installation directory of Clang, and it also adds a search path for headers in the -isysroot. This is problematic if headers are found in both the toolchain and in the sysroot, since #include_next will end up finding the libc++ headers in the sysroot instead of the intended system headers. This patch changes the logic such that if the toolchain contains libc++ headers, no C++ header paths are added in the sysroot. However, if the toolchain does *not* contain libc++ headers, the sysroot is searched as usual. This should not be a breaking change, since any code that previously relied on some libc++ headers being found in the sysroot suffered from the #include_next issue described above, which renders any libc++ header basically useless. Differential Revision: https://reviews.llvm.org/D89001 --- clang/lib/Driver/ToolChains/Darwin.cpp | 47 +++++--- .../usr/include/c++/v1/.keep | 0 .../basic_darwin_sdk_usr_cxx_v1/usr/lib/.keep | 0 .../Driver/darwin-header-search-libcxx.cpp | 101 ++++++++++++++---- 4 files changed, 112 insertions(+), 36 deletions(-) create mode 100644 clang/test/Driver/Inputs/basic_darwin_sdk_usr_cxx_v1/usr/include/c++/v1/.keep create mode 100644 clang/test/Driver/Inputs/basic_darwin_sdk_usr_cxx_v1/usr/lib/.keep diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 71a15c26d6928..5c6e2fb942dee 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -2098,21 +2098,42 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs( switch (GetCXXStdlibType(DriverArgs)) { case ToolChain::CST_Libcxx: { - // On Darwin, libc++ is installed alongside the compiler in - // include/c++/v1, so get from '/bin' to '/include/c++/v1'. - { - llvm::SmallString<128> P = llvm::StringRef(getDriver().getInstalledDir()); - // Note that P can be relative, so we have to '..' and not parent_path. - llvm::sys::path::append(P, "..", "include", "c++", "v1"); - addSystemInclude(DriverArgs, CC1Args, P); + // On Darwin, libc++ can be installed in one of the following two places: + // 1. Alongside the compiler in /include/c++/v1 + // 2. In a SDK (or a custom sysroot) in /usr/include/c++/v1 + // + // The precendence of paths is as listed above, i.e. we take the first path + // that exists. Also note that we never include libc++ twice -- we take the + // first path that exists and don't send the other paths to CC1 (otherwise + // include_next could break). + + // Check for (1) + // Get from '/bin' to '/include/c++/v1'. + // Note that InstallBin can be relative, so we use '..' instead of + // parent_path. + llvm::SmallString<128> InstallBin = + llvm::StringRef(getDriver().getInstalledDir()); // /bin + llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1"); + if (getVFS().exists(InstallBin)) { + addSystemInclude(DriverArgs, CC1Args, InstallBin); + return; + } else if (DriverArgs.hasArg(options::OPT_v)) { + llvm::errs() << "ignoring nonexistent directory \"" << InstallBin + << "\"\n"; } - // Also add /usr/include/c++/v1 unless -nostdinc is used, - // to match the legacy behavior in CC1. - if (!DriverArgs.hasArg(options::OPT_nostdinc)) { - llvm::SmallString<128> P = Sysroot; - llvm::sys::path::append(P, "usr", "include", "c++", "v1"); - addSystemInclude(DriverArgs, CC1Args, P); + + // Otherwise, check for (2) + llvm::SmallString<128> SysrootUsr = Sysroot; + llvm::sys::path::append(SysrootUsr, "usr", "include", "c++", "v1"); + if (getVFS().exists(SysrootUsr)) { + addSystemInclude(DriverArgs, CC1Args, SysrootUsr); + return; + } else if (DriverArgs.hasArg(options::OPT_v)) { + llvm::errs() << "ignoring nonexistent directory \"" << SysrootUsr + << "\"\n"; } + + // Otherwise, don't add any path. break; } diff --git a/clang/test/Driver/Inputs/basic_darwin_sdk_usr_cxx_v1/usr/include/c++/v1/.keep b/clang/test/Driver/Inputs/basic_darwin_sdk_usr_cxx_v1/usr/include/c++/v1/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/basic_darwin_sdk_usr_cxx_v1/usr/lib/.keep b/clang/test/Driver/Inputs/basic_darwin_sdk_usr_cxx_v1/usr/lib/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/darwin-header-search-libcxx.cpp b/clang/test/Driver/darwin-header-search-libcxx.cpp index 6bdbbd11908a1..4824525f1cf41 100644 --- a/clang/test/Driver/darwin-header-search-libcxx.cpp +++ b/clang/test/Driver/darwin-header-search-libcxx.cpp @@ -13,39 +13,57 @@ // RUN: | FileCheck --check-prefix=CHECK-LIBCXX-NONE %s // CHECK-LIBCXX-NONE: "{{[^"]*}}clang{{[^"]*}}" "-cc1" -// Check with only headers alongside the installation (those should be used, -// but we should still add /usr/include/c++/v1 after to preserve legacy). +// Check with only headers alongside the installation (those should be used). // // RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \ // RUN: -target x86_64-apple-darwin \ // RUN: -stdlib=libc++ \ // RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ // RUN: --sysroot="" \ -// RUN: | FileCheck -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain --check-prefix=CHECK-LIBCXX-TOOLCHAIN-1 %s +// RUN: | FileCheck -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \ +// RUN: --check-prefix=CHECK-LIBCXX-TOOLCHAIN-1 %s // CHECK-LIBCXX-TOOLCHAIN-1: "{{[^"]*}}clang{{[^"]*}}" "-cc1" // CHECK-LIBCXX-TOOLCHAIN-1: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" -// CHECK-LIBCXX-TOOLCHAIN-1: "-internal-isystem" "/usr/include/c++/v1" +// CHECK-LIBCXX-TOOLCHAIN-1-NOT: "-internal-isystem" "/usr/include/c++/v1" // // RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \ // RUN: -target x86_64-apple-darwin \ // RUN: -stdlib=libc++ \ // RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ // RUN: -isysroot %S/Inputs/basic_darwin_sdk_no_libcxx \ -// RUN: | FileCheck -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain --check-prefix=CHECK-LIBCXX-TOOLCHAIN-2 %s +// RUN: | FileCheck -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \ +// RUN: -DSYSROOT=%S/Inputs/basic_darwin_sdk_no_libcxx \ +// RUN: --check-prefix=CHECK-LIBCXX-TOOLCHAIN-2 %s // CHECK-LIBCXX-TOOLCHAIN-2: "{{[^"]*}}clang{{[^"]*}}" "-cc1" // CHECK-LIBCXX-TOOLCHAIN-2: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" +// CHECK-LIBCXX-TOOLCHAIN-2-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" + +// Check with only headers in the sysroot (those should be used). +// +// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \ +// RUN: -target x86_64-apple-darwin \ +// RUN: -stdlib=libc++ \ +// RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain_no_libcxx/usr/bin \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ +// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ +// RUN: -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain_no_libcxx \ +// RUN: --check-prefix=CHECK-LIBCXX-SYSROOT-1 %s +// CHECK-LIBCXX-SYSROOT-1: "{{[^"]*}}clang{{[^"]*}}" "-cc1" +// CHECK-LIBCXX-SYSROOT-1: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" +// CHECK-LIBCXX-SYSROOT-1-NOT: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" // Check with both headers in the sysroot and headers alongside the installation -// (the headers in should be added after the toolchain headers). -// Ensure that both -isysroot and --sysroot work, and that isysroot has precedence. +// (the headers in the toolchain should be preferred over the headers). +// Ensure that both -isysroot and --sysroot work, and that isysroot has precedence +// over --sysroot. // // RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \ // RUN: -target x86_64-apple-darwin \ // RUN: -stdlib=libc++ \ // RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ // RUN: -resource-dir=%S/Inputs/resource_dir \ -// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr \ -// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ +// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ // RUN: -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \ // RUN: --check-prefix=CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1 %s // @@ -54,8 +72,8 @@ // RUN: -stdlib=libc++ \ // RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ // RUN: -resource-dir=%S/Inputs/resource_dir \ -// RUN: --sysroot %S/Inputs/basic_darwin_sdk_usr \ -// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr \ +// RUN: --sysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ +// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ // RUN: -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \ // RUN: --check-prefix=CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1 %s // @@ -64,32 +82,46 @@ // RUN: -stdlib=libc++ \ // RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ // RUN: -resource-dir=%S/Inputs/resource_dir \ -// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ // RUN: --sysroot %S/Inputs/basic_darwin_sdk_no_libcxx \ -// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr \ +// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ // RUN: -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \ // RUN: --check-prefix=CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1 %s // // CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1: "{{[^"]*}}clang{{[^"]*}}" "-cc1" // CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" -// CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" +// CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" -// Make sure that using -nostdinc will drop the sysroot C++ library include -// path, but not the toolchain one. +// Make sure that using -nostdinc does not drop any C++ library include path. +// This behavior is strange, but it is compatible with the legacy CC1 behavior. // // RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \ // RUN: -target x86_64-apple-darwin16 \ // RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ // RUN: -resource-dir=%S/Inputs/resource_dir \ -// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ // RUN: -stdlib=platform \ // RUN: -nostdinc \ -// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr \ +// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ // RUN: -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \ -// RUN: --check-prefix=CHECK-LIBCXX-NOSTDINC %s -// CHECK-LIBCXX-NOSTDINC: "{{[^"]*}}clang{{[^"]*}}" "-cc1" -// CHECK-LIBCXX-NOSTDINC: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" -// CHECK-LIBCXX-NOSTDINC-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" +// RUN: --check-prefix=CHECK-LIBCXX-NOSTDINC-1 %s +// CHECK-LIBCXX-NOSTDINC-1: "{{[^"]*}}clang{{[^"]*}}" "-cc1" +// CHECK-LIBCXX-NOSTDINC-1-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" +// CHECK-LIBCXX-NOSTDINC-1: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" +// +// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \ +// RUN: -target x86_64-apple-darwin16 \ +// RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ +// RUN: -resource-dir=%S/Inputs/resource_dir \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_no_libcxx \ +// RUN: -stdlib=platform \ +// RUN: -nostdinc \ +// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_no_libcxx \ +// RUN: -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \ +// RUN: --check-prefix=CHECK-LIBCXX-NOSTDINC-2 %s +// CHECK-LIBCXX-NOSTDINC-2: "{{[^"]*}}clang{{[^"]*}}" "-cc1" +// CHECK-LIBCXX-NOSTDINC-2: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" +// CHECK-LIBCXX-NOSTDINC-2-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" // Make sure that using -nostdinc++ or -nostdlib will drop both the toolchain // C++ include path and the sysroot one. @@ -98,7 +130,7 @@ // RUN: -target x86_64-apple-darwin16 \ // RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ // RUN: -resource-dir=%S/Inputs/resource_dir \ -// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ // RUN: -stdlib=platform \ // RUN: -nostdinc++ \ // RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr \ @@ -121,3 +153,26 @@ // CHECK-LIBCXX-NOSTDLIBINC: "{{[^"]*}}clang{{[^"]*}}" "-cc1" // CHECK-LIBCXX-NOSTDLIBINC-NOT: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" // CHECK-LIBCXX-NOSTDLIBINC-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" + +// Make sure we explain that we considered a path but didn't add it when it +// doesn't exist. +// +// RUN: %clang -no-canonical-prefixes %s -fsyntax-only -v 2>&1 \ +// RUN: -target x86_64-apple-darwin \ +// RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain_no_libcxx/usr/bin \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk \ +// RUN: -stdlib=libc++ \ +// RUN: | FileCheck -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain_no_libcxx \ +// RUN: --check-prefix=CHECK-LIBCXX-MISSING-TOOLCHAIN %s +// CHECK-LIBCXX-MISSING-TOOLCHAIN: ignoring nonexistent directory "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" +// +// RUN: %clang -no-canonical-prefixes %s -fsyntax-only -v 2>&1 \ +// RUN: -target x86_64-apple-darwin \ +// RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain_no_libcxx/usr/bin \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_no_libcxx \ +// RUN: -stdlib=libc++ \ +// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_no_libcxx \ +// RUN: -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain_no_libcxx \ +// RUN: --check-prefix=CHECK-LIBCXX-MISSING-BOTH %s +// CHECK-LIBCXX-MISSING-BOTH: ignoring nonexistent directory "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" +// CHECK-LIBCXX-MISSING-BOTH: ignoring nonexistent directory "[[SYSROOT]]/usr/include/c++/v1"