From f4502ab59c7b68d9e97b6a7f95e788535ab526cd Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 20 Oct 2017 04:11:28 +0000 Subject: [PATCH 0001/1682] Basic: restore {,u}intptr_t on NetBSD/ARM NetBSD uses `long int` for `intptr_t` on ARM. This was changed in SVN r316046, referenced against other compilers. However, NetBSD's reference was incorrect as the current clang behaviour is more up-to-date. Restore the original behaviour for that target. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316204 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Basic/Targets/ARM.cpp | 7 ++++--- test/Preprocessor/init.c | 12 ++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/Basic/Targets/ARM.cpp b/lib/Basic/Targets/ARM.cpp index 992cfbde36..1b236dd220 100644 --- a/lib/Basic/Targets/ARM.cpp +++ b/lib/Basic/Targets/ARM.cpp @@ -236,9 +236,10 @@ ARMTargetInfo::ARMTargetInfo(const llvm::Triple &Triple, break; } - IntPtrType = (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::OpenBSD) - ? SignedLong - : SignedInt; + bool IsOpenBSD = Triple.getOS() == llvm::Triple::OpenBSD; + bool IsNetBSD = Triple.getOS() == llvm::Triple::NetBSD; + IntPtrType = + (Triple.isOSDarwin() || IsOpenBSD || IsNetBSD) ? SignedLong : SignedInt; // Cache arch related info. setArchInfo(); diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c index bb5c00122d..293a3d6ad0 100644 --- a/test/Preprocessor/init.c +++ b/test/Preprocessor/init.c @@ -2446,10 +2446,10 @@ // ARM-NETBSD:#define __INTMAX_MAX__ 9223372036854775807LL // ARM-NETBSD:#define __INTMAX_TYPE__ long long int // ARM-NETBSD:#define __INTMAX_WIDTH__ 64 -// ARM-NETBSD:#define __INTPTR_FMTd__ "d" -// ARM-NETBSD:#define __INTPTR_FMTi__ "i" -// ARM-NETBSD:#define __INTPTR_MAX__ 2147483647 -// ARM-NETBSD:#define __INTPTR_TYPE__ int +// ARM-NETBSD:#define __INTPTR_FMTd__ "ld" +// ARM-NETBSD:#define __INTPTR_FMTi__ "li" +// ARM-NETBSD:#define __INTPTR_MAX__ 2147483647L +// ARM-NETBSD:#define __INTPTR_TYPE__ long int // ARM-NETBSD:#define __INTPTR_WIDTH__ 32 // ARM-NETBSD:#define __INT_FAST16_FMTd__ "hd" // ARM-NETBSD:#define __INT_FAST16_FMTi__ "hi" @@ -2541,8 +2541,8 @@ // ARM-NETBSD:#define __UINTMAX_MAX__ 18446744073709551615ULL // ARM-NETBSD:#define __UINTMAX_TYPE__ long long unsigned int // ARM-NETBSD:#define __UINTMAX_WIDTH__ 64 -// ARM-NETBSD:#define __UINTPTR_MAX__ 4294967295U -// ARM-NETBSD:#define __UINTPTR_TYPE__ unsigned int +// ARM-NETBSD:#define __UINTPTR_MAX__ 4294967295UL +// ARM-NETBSD:#define __UINTPTR_TYPE__ long unsigned int // ARM-NETBSD:#define __UINTPTR_WIDTH__ 32 // ARM-NETBSD:#define __UINT_FAST16_MAX__ 65535 // ARM-NETBSD:#define __UINT_FAST16_TYPE__ unsigned short -- GitLab From a312801e78a7627965158838eae1fb9a10487af7 Mon Sep 17 00:00:00 2001 From: "Ivan A. Kosarev" Date: Fri, 20 Oct 2017 12:35:17 +0000 Subject: [PATCH 0002/1682] [CodeGen] Fix generation of TBAA info for array-to-pointer conversions Resolves: Fatal error: Offset not zero at the point of scalar access. http://llvm.org/PR34992 Differential Revision: https://reviews.llvm.org/D39083 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316211 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGExpr.cpp | 10 ++++++++-- test/CodeGen/tbaa-array.cpp | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 test/CodeGen/tbaa-array.cpp diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 158baf7586..2eb6d0a0c0 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -3072,8 +3072,6 @@ Address CodeGenFunction::EmitArrayToPointerDecay(const Expr *E, // Expressions of array type can't be bitfields or vector elements. LValue LV = EmitLValue(E); Address Addr = LV.getAddress(); - if (BaseInfo) *BaseInfo = LV.getBaseInfo(); - if (TBAAInfo) *TBAAInfo = LV.getTBAAInfo(); // If the array type was an incomplete type, we need to make sure // the decay ends up being the right type. @@ -3088,7 +3086,15 @@ Address CodeGenFunction::EmitArrayToPointerDecay(const Expr *E, Addr = Builder.CreateStructGEP(Addr, 0, CharUnits::Zero(), "arraydecay"); } + // The result of this decay conversion points to an array element within the + // base lvalue. However, since TBAA currently does not support representing + // accesses to elements of member arrays, we conservatively represent accesses + // to the pointee object as if it had no any base lvalue specified. + // TODO: Support TBAA for member arrays. QualType EltType = E->getType()->castAsArrayTypeUnsafe()->getElementType(); + if (BaseInfo) *BaseInfo = LV.getBaseInfo(); + if (TBAAInfo) *TBAAInfo = CGM.getTBAAAccessInfo(EltType); + return Builder.CreateElementBitCast(Addr, ConvertTypeForMem(EltType)); } diff --git a/test/CodeGen/tbaa-array.cpp b/test/CodeGen/tbaa-array.cpp new file mode 100644 index 0000000000..86ca5ccb40 --- /dev/null +++ b/test/CodeGen/tbaa-array.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s \ +// RUN: -emit-llvm -o - | FileCheck %s +// +// Check that we generate correct TBAA information for accesses to array +// elements. + +struct A { int i; }; +struct B { A a[1]; }; + +int foo(B *b) { +// CHECK-LABEL: _Z3fooP1B +// CHECK: load i32, {{.*}}, !tbaa [[TAG_A_i:!.*]] + return b->a->i; +} + +// CHECK-DAG: [[TAG_A_i]] = !{[[TYPE_A:!.*]], [[TYPE_int:!.*]], i64 0} +// CHECK-DAG: [[TYPE_A]] = !{!"_ZTS1A", !{{.*}}, i64 0} +// CHECK-DAG: [[TYPE_int]] = !{!"int", !{{.*}}, i64 0} -- GitLab From d6aede0fad127fa8eedd339e9594bf30cbd98294 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Fri, 20 Oct 2017 12:37:16 +0000 Subject: [PATCH 0003/1682] [clang-refactor] Add "-Inplace" option to the commandline tool. Summary: Change clang-refactor default behavior to print the new code after refactoring (instead of editing the source files), which would make it easier to use and debug the refactoring action. Reviewers: arphaman, ioeric Reviewed By: arphaman Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D39092 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316212 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/Refactor/tool-apply-replacements.cpp | 12 +++++------- tools/clang-refactor/ClangRefactor.cpp | 22 ++++++++++++++++------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/test/Refactor/tool-apply-replacements.cpp b/test/Refactor/tool-apply-replacements.cpp index 9f4595089c..59b0991dd2 100644 --- a/test/Refactor/tool-apply-replacements.cpp +++ b/test/Refactor/tool-apply-replacements.cpp @@ -1,10 +1,8 @@ -// RUN: rm -f %t.cp.cpp -// RUN: cp %s %t.cp.cpp -// RUN: clang-refactor local-rename -selection=%t.cp.cpp:9:7 -new-name=test %t.cp.cpp -- -// RUN: grep -v CHECK %t.cp.cpp | FileCheck %t.cp.cpp -// RUN: cp %s %t.cp.cpp -// RUN: clang-refactor local-rename -selection=%t.cp.cpp:9:7-9:15 -new-name=test %t.cp.cpp -- -// RUN: grep -v CHECK %t.cp.cpp | FileCheck %t.cp.cpp +// RUN: sed -e 's#//.*$##' %s > %t.cpp +// RUN: clang-refactor local-rename -selection=%t.cpp:7:7 -new-name=test %t.cpp -- | FileCheck %s +// RUN: clang-refactor local-rename -selection=%t.cpp:7:7-7:15 -new-name=test %t.cpp -- | FileCheck %s +// RUN: clang-refactor local-rename -i -selection=%t.cpp:7:7 -new-name=test %t.cpp -- +// RUN: FileCheck -input-file=%t.cpp %s class RenameMe { // CHECK: class test { diff --git a/tools/clang-refactor/ClangRefactor.cpp b/tools/clang-refactor/ClangRefactor.cpp index ed9bf5ed28..523c3a6220 100644 --- a/tools/clang-refactor/ClangRefactor.cpp +++ b/tools/clang-refactor/ClangRefactor.cpp @@ -40,6 +40,11 @@ static cl::OptionCategory CommonRefactorOptions("Refactoring options"); static cl::opt Verbose("v", cl::desc("Use verbose output"), cl::cat(cl::GeneralCategory), cl::sub(*cl::AllSubCommands)); + +static cl::opt Inplace("i", cl::desc("Inplace edit s"), + cl::cat(cl::GeneralCategory), + cl::sub(*cl::AllSubCommands)); + } // end namespace opts namespace { @@ -436,13 +441,18 @@ public: return true; } - std::error_code EC; - llvm::raw_fd_ostream OS(File, EC, llvm::sys::fs::F_Text); - if (EC) { - llvm::errs() << EC.message() << "\n"; - return true; + if (opts::Inplace) { + std::error_code EC; + llvm::raw_fd_ostream OS(File, EC, llvm::sys::fs::F_Text); + if (EC) { + llvm::errs() << EC.message() << "\n"; + return true; + } + OS << *Result; + continue; } - OS << *Result; + + llvm::outs() << *Result; } return false; } -- GitLab From 44c160f916a1b080098b17b466b026aa07475ec2 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Fri, 20 Oct 2017 19:18:30 +0000 Subject: [PATCH 0004/1682] Allow /showIncludes with /P r213589 was checked in as a solution to https://bugs.llvm.org/show_bug.cgi?id=20336. However, it is possible to use /EP with /P to suppress #line directives AND output to a file. There is no reason in that case to suppress /showIncludes. This was reported here: https://bugs.llvm.org/show_bug.cgi?id=34997 Differential Revision: https://reviews.llvm.org/D39104 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316225 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Driver/ToolChains/Clang.cpp | 4 +++- test/Driver/cl-options.c | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index 12713f8be2..8e5f3b9573 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -4873,7 +4873,9 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, // Both /showIncludes and /E (and /EP) write to stdout. Allowing both // would produce interleaved output, so ignore /showIncludes in such cases. - if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_EP)) + if ((!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_EP)) || + (Args.hasArg(options::OPT__SLASH_P) && + Args.hasArg(options::OPT__SLASH_EP) && !Args.hasArg(options::OPT_E))) if (Arg *A = Args.getLastArg(options::OPT_show_includes)) A->render(Args, CmdArgs); diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c index b78bb9d8b5..115b21963b 100644 --- a/test/Driver/cl-options.c +++ b/test/Driver/cl-options.c @@ -197,8 +197,12 @@ // RUN: %clang_cl /E /showIncludes -### -- %s 2>&1 | FileCheck -check-prefix=showIncludes_E %s // RUN: %clang_cl /EP /showIncludes -### -- %s 2>&1 | FileCheck -check-prefix=showIncludes_E %s +// RUN: %clang_cl /E /EP /showIncludes -### -- %s 2>&1 | FileCheck -check-prefix=showIncludes_E %s // showIncludes_E: warning: argument unused during compilation: '--show-includes' +// RUN: %clang_cl /EP /P /showIncludes -### -- %s 2>&1 | FileCheck -check-prefix=showIncludes_E_And_P %s +// showIncludes_E_And_P-NOT: warning: argument unused during compilation: '--show-includes' + // /source-charset: should warn on everything except UTF-8. // RUN: %clang_cl /source-charset:utf-16 -### -- %s 2>&1 | FileCheck -check-prefix=source-charset-utf-16 %s // source-charset-utf-16: invalid value 'utf-16' -- GitLab From f20a280b3ba367e83e1c21cfd4366cd55b8d20cb Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Fri, 20 Oct 2017 19:40:40 +0000 Subject: [PATCH 0005/1682] [OpenMP] Avoid VLAs for some reductions on array sections In some cases the compiler can deduce the length of an array section as constants. With this information, VLAs can be avoided in place of a constant sized array or even a scalar value if the length is 1. Example: int a[4], b[2]; pragma omp parallel reduction(+: a[1:2], b[1:1]) { } For chained array sections, this optimization is restricted to cases where all array sections except the last have a constant length 1. This trivially guarantees that there are no holes in the memory region that needs to be privatized. Example: int c[3][4]; pragma omp parallel reduction(+: c[1:1][1:2]) { } Differential Revision: https://reviews.llvm.org/D39136 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316229 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGOpenMPRuntime.cpp | 10 +- lib/CodeGen/CGStmtOpenMP.cpp | 7 +- lib/Sema/SemaOpenMP.cpp | 83 ++++++- test/OpenMP/for_reduction_codegen.cpp | 289 ++++++++++++++++++---- test/OpenMP/for_reduction_codegen_UDR.cpp | 133 ++++++---- 5 files changed, 413 insertions(+), 109 deletions(-) diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index f98ff85565..3396c63cd6 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -925,7 +925,7 @@ void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N) { cast(cast(ClausesData[N].Private)->getDecl()); QualType PrivateType = PrivateVD->getType(); bool AsArraySection = isa(ClausesData[N].Ref); - if (!AsArraySection && !PrivateType->isVariablyModifiedType()) { + if (!PrivateType->isVariablyModifiedType()) { Sizes.emplace_back( CGF.getTypeSize( SharedAddresses[N].first.getType().getNonReferenceType()), @@ -963,10 +963,9 @@ void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N, auto *PrivateVD = cast(cast(ClausesData[N].Private)->getDecl()); QualType PrivateType = PrivateVD->getType(); - bool AsArraySection = isa(ClausesData[N].Ref); - if (!AsArraySection && !PrivateType->isVariablyModifiedType()) { + if (!PrivateType->isVariablyModifiedType()) { assert(!Size && !Sizes[N].second && - "Size should be nullptr for non-variably modified redution " + "Size should be nullptr for non-variably modified reduction " "items."); return; } @@ -994,8 +993,7 @@ void ReductionCodeGen::emitInitialization( CGF.ConvertTypeForMem(SharedType)), SharedType, SharedAddresses[N].first.getBaseInfo(), CGF.CGM.getTBAAAccessInfo(SharedType)); - if (isa(ClausesData[N].Ref) || - CGF.getContext().getAsArrayType(PrivateVD->getType())) { + if (CGF.getContext().getAsArrayType(PrivateVD->getType())) { emitAggregateInitialization(CGF, N, PrivateAddr, SharedLVal, DRD); } else if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) { emitInitWithReductionInitializer(CGF, DRD, ClausesData[N].ReductionOp, diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index cdec3e35f9..0e5ea798eb 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -996,7 +996,9 @@ void CodeGenFunction::EmitOMPReductionClauseInit( auto *LHSVD = cast(cast(*ILHS)->getDecl()); auto *RHSVD = cast(cast(*IRHS)->getDecl()); - if (isa(IRef)) { + QualType Type = PrivateVD->getType(); + bool isaOMPArraySectionExpr = isa(IRef); + if (isaOMPArraySectionExpr && Type->isVariablyModifiedType()) { // Store the address of the original variable associated with the LHS // implicit variable. PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() -> Address { @@ -1005,7 +1007,8 @@ void CodeGenFunction::EmitOMPReductionClauseInit( PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address { return GetAddrOfLocalVar(PrivateVD); }); - } else if (isa(IRef)) { + } else if ((isaOMPArraySectionExpr && Type->isScalarType()) || + isa(IRef)) { // Store the address of the original variable associated with the LHS // implicit variable. PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() -> Address { diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index a024888fbf..bf89eb0b2f 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -9330,6 +9330,68 @@ struct ReductionData { }; } // namespace +static bool CheckOMPArraySectionConstantForReduction( + ASTContext &Context, const OMPArraySectionExpr *OASE, bool &SingleElement, + SmallVectorImpl &ArraySizes) { + const Expr *Length = OASE->getLength(); + if (Length == nullptr) { + // For array sections of the form [1:] or [:], we would need to analyze + // the lower bound... + if (OASE->getColonLoc().isValid()) + return false; + + // This is an array subscript which has implicit length 1! + SingleElement = true; + ArraySizes.push_back(llvm::APSInt::get(1)); + } else { + llvm::APSInt ConstantLengthValue; + if (!Length->EvaluateAsInt(ConstantLengthValue, Context)) + return false; + + SingleElement = (ConstantLengthValue.getSExtValue() == 1); + ArraySizes.push_back(ConstantLengthValue); + } + + // Get the base of this array section and walk up from there. + const Expr *Base = OASE->getBase()->IgnoreParenImpCasts(); + + // We require length = 1 for all array sections except the right-most to + // guarantee that the memory region is contiguous and has no holes in it. + while (const auto *TempOASE = dyn_cast(Base)) { + Length = TempOASE->getLength(); + if (Length == nullptr) { + // For array sections of the form [1:] or [:], we would need to analyze + // the lower bound... + if (OASE->getColonLoc().isValid()) + return false; + + // This is an array subscript which has implicit length 1! + ArraySizes.push_back(llvm::APSInt::get(1)); + } else { + llvm::APSInt ConstantLengthValue; + if (!Length->EvaluateAsInt(ConstantLengthValue, Context) || + ConstantLengthValue.getSExtValue() != 1) + return false; + + ArraySizes.push_back(ConstantLengthValue); + } + Base = TempOASE->getBase()->IgnoreParenImpCasts(); + } + + // If we have a single element, we don't need to add the implicit lengths. + if (!SingleElement) { + while (const auto *TempASE = dyn_cast(Base)) { + // Has implicit length 1! + ArraySizes.push_back(llvm::APSInt::get(1)); + Base = TempASE->getBase()->IgnoreParenImpCasts(); + } + } + + // This array section can be privatized as a single value or as a constant + // sized array. + return true; +} + static bool ActOnOMPReductionKindClause( Sema &S, DSAStackTy *Stack, OpenMPClauseKind ClauseKind, ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -9628,7 +9690,26 @@ static bool ActOnOMPReductionKindClause( auto *RHSVD = buildVarDecl(S, ELoc, Type, D->getName(), D->hasAttrs() ? &D->getAttrs() : nullptr); auto PrivateTy = Type; - if (OASE || + + // Try if we can determine constant lengths for all array sections and avoid + // the VLA. + bool ConstantLengthOASE = false; + if (OASE) { + bool SingleElement; + llvm::SmallVector ArraySizes; + ConstantLengthOASE = CheckOMPArraySectionConstantForReduction( + Context, OASE, SingleElement, ArraySizes); + + // If we don't have a single element, we must emit a constant array type. + if (ConstantLengthOASE && !SingleElement) { + for (auto &Size : ArraySizes) { + PrivateTy = Context.getConstantArrayType( + PrivateTy, Size, ArrayType::Normal, /*IndexTypeQuals=*/0); + } + } + } + + if ((OASE && !ConstantLengthOASE) || (!ASE && D->getType().getNonReferenceType()->isVariablyModifiedType())) { // For arrays/array sections only: diff --git a/test/OpenMP/for_reduction_codegen.cpp b/test/OpenMP/for_reduction_codegen.cpp index d5afae990b..2c49022ff0 100644 --- a/test/OpenMP/for_reduction_codegen.cpp +++ b/test/OpenMP/for_reduction_codegen.cpp @@ -27,7 +27,7 @@ struct S { // CHECK-DAG: [[REDUCTION_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 18, i32 0, i32 0, i8* // CHECK-DAG: [[REDUCTION_LOCK:@.+]] = common global [8 x i32] zeroinitializer -template +template T tmain() { T t; S test; @@ -36,6 +36,7 @@ T tmain() { S s_arr[] = {1, 2}; S &var = test; S var1; + S arr[length]; #pragma omp parallel #pragma omp for reduction(+:t_var) reduction(&:var) reduction(&& : var1) reduction(min: t_var1) nowait for (int i = 0; i < 2; ++i) { @@ -48,6 +49,12 @@ T tmain() { vec[i] = t_var; s_arr[i] = var; } +#pragma omp parallel +#pragma omp for reduction(+ : arr[1:length-2]) + for (int i = 0; i < 2; ++i) { + vec[i] = t_var; + s_arr[i] = var; + } return T(); } @@ -180,12 +187,12 @@ int main() { S test; float t_var = 0, t_var1; int vec[] = {1, 2}; - S s_arr[] = {1, 2}; + S s_arr[] = {1, 2, 3, 4}; S &var = test; S var1, arrs[10][4]; S **var2 = foo(); - S vvar2[2]; - S (&var3)[2] = s_arr; + S vvar2[5]; + S (&var3)[4] = s_arr; #pragma omp parallel #pragma omp for reduction(+:t_var) reduction(&:var) reduction(&& : var1) reduction(min: t_var1) for (int i = 0; i < 2; ++i) { @@ -205,6 +212,18 @@ int main() { for (int i = 0; i < 10; ++i) ; #pragma omp parallel +#pragma omp for reduction(& : var2[1][1 : 6]) + for (int i = 0; i < 10; ++i) + ; +#pragma omp parallel +#pragma omp for reduction(& : var2[1 : 1][1 : 6]) + for (int i = 0; i < 10; ++i) + ; +#pragma omp parallel +#pragma omp for reduction(& : var2[1 : 1][1]) + for (int i = 0; i < 10; ++i) + ; +#pragma omp parallel #pragma omp for reduction(& : vvar2[0 : 5]) for (int i = 0; i < 10; ++i) ; @@ -213,28 +232,42 @@ int main() { for (int i = 0; i < 10; ++i) ; #pragma omp parallel +#pragma omp for reduction(& : var3[ : 2]) + for (int i = 0; i < 10; ++i) + ; + // TODO: The compiler should also be able to generate a constant sized array in this case! +#pragma omp parallel +#pragma omp for reduction(& : var3[2 : ]) + for (int i = 0; i < 10; ++i) + ; +#pragma omp parallel #pragma omp for reduction(& : var3) for (int i = 0; i < 10; ++i) ; - return tmain(); + return tmain(); #endif } // CHECK: define {{.*}}i{{[0-9]+}} @main() // CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]], // CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]]) -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [2 x i32]*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK1:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK2:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK3:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK4:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK5:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK6:@.+]] to void -// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]() +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK4:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK5:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK6:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [5 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK7:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK8:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK9:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK10:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK11:@.+]] to void +// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT_42:@.+]]() // CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]* // CHECK: ret // -// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}}) // CHECK: [[T_VAR_PRIV:%.+]] = alloca float, // CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]], // CHECK: [[VAR1_PRIV:%.+]] = alloca [[S_FLOAT_TY]], @@ -910,44 +943,183 @@ int main() { // CHECK: store [[S_FLOAT_TY]]* [[PSEUDO_VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]] // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[S_FLOAT_TY]]*** dereferenceable(8) %{{.+}}) -// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR2_ORIG_ADDR:%.+]] = alloca [[S_FLOAT_TY]]***, +// CHECK: [[VAR2_PRIV:%.+]] = alloca [1 x [6 x [[S_FLOAT_TY]]]], // Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*], +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VVAR2_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]], +// CHECK: [[VAR2_ORIG:%.+]] = load [[S_FLOAT_TY]]***, [[S_FLOAT_TY]]**** [[VAR2_ORIG_ADDR]], -// CHECK: [[LOW:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0 -// CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64 -// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 -// CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]] -// CHECK: [[DIF:%.+]] = sdiv exact i64 [[BYTE_DIF]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) -// CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1 -// CHECK: call i8* @llvm.stacksave() -// CHECK: [[VVAR2_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]], -// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], +// CHECK: [[ARRIDX:%.+]] = getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], i64 1 +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[ARRIDX]], +// CHECK: [[LOW:%.+]] = getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[LD]], i64 1 +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], + +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], +// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], // CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 // CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 // CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] // CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) -// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VVAR2_PRIV]], i64 [[OFFSET]] -// CHECK: [[VVAR2_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VVAR2_PRIV]] to [2 x [[S_FLOAT_TY]]]* +// CHECK: [[PSEUDO_VAR2_PRIV:%.+]] = getelementptr [1 x [6 x [[S_FLOAT_TY]]]], [1 x [6 x [[S_FLOAT_TY]]]]* [[VAR2_PRIV]], i64 [[OFFSET]] +// CHECK: store [[S_FLOAT_TY]]** [[REF:.+]], [[S_FLOAT_TY]]*** % +// CHECK: [[VAR2_PRIV:%.+]] = bitcast [1 x [6 x [[S_FLOAT_TY]]]]* [[PSEUDO_VAR2_PRIV]] to [[S_FLOAT_TY]]* +// CHECK: store [[S_FLOAT_TY]]* [[VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]] // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[S_FLOAT_TY]]*** dereferenceable(8) %{{.+}}) -// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR2_ORIG_ADDR:%.+]] = alloca [[S_FLOAT_TY]]***, +// CHECK: [[VAR2_PRIV:%.+]] = alloca [1 x [6 x [[S_FLOAT_TY]]]], // Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*], +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], +// CHECK: [[VAR2_ORIG:%.+]] = load [[S_FLOAT_TY]]***, [[S_FLOAT_TY]]**** [[VAR2_ORIG_ADDR]], + +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], +// CHECK: [[ARRIDX:%.+]] = getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], i64 1 +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[ARRIDX]], +// CHECK: [[LOW:%.+]] = getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[LD]], i64 1 +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], + +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], +// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], +// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 +// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 +// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] +// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) +// CHECK: [[PSEUDO_VAR2_PRIV:%.+]] = getelementptr [1 x [6 x [[S_FLOAT_TY]]]], [1 x [6 x [[S_FLOAT_TY]]]]* [[VAR2_PRIV]], i64 [[OFFSET]] +// CHECK: store [[S_FLOAT_TY]]** [[REF:.+]], [[S_FLOAT_TY]]*** % +// CHECK: [[VAR2_PRIV:%.+]] = bitcast [1 x [6 x [[S_FLOAT_TY]]]]* [[PSEUDO_VAR2_PRIV]] to [[S_FLOAT_TY]]* +// CHECK: store [[S_FLOAT_TY]]* [[VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]] +// CHECK: ret void + +// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[S_FLOAT_TY]]*** dereferenceable(8) %{{.+}}) + +// CHECK: [[VAR2_ORIG_ADDR:%.+]] = alloca [[S_FLOAT_TY]]***, +// CHECK: [[VAR2_PRIV:%.+]] = alloca [[S_FLOAT_TY]], + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], + +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], +// CHECK: [[VAR2_ORIG:%.+]] = load [[S_FLOAT_TY]]***, [[S_FLOAT_TY]]**** [[VAR2_ORIG_ADDR]], + +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], +// CHECK: [[ARRIDX:%.+]] = getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], i64 1 +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[ARRIDX]], +// CHECK: [[LOW:%.+]] = getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[LD]], i64 1 +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], + +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], +// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], +// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 +// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 +// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] +// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) +// CHECK: [[PSEUDO_VAR2_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VAR2_PRIV]], i64 [[OFFSET]] +// CHECK: store [[S_FLOAT_TY]]** [[REF:.+]], [[S_FLOAT_TY]]*** % +// CHECK: store [[S_FLOAT_TY]]* [[PSEUDO_VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]] +// CHECK: ret void + +// CHECK: define internal void [[MAIN_MICROTASK7]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [5 x [[S_FLOAT_TY]]]* dereferenceable(20) %{{.+}}) + +// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [5 x [[S_FLOAT_TY]]]*, +// CHECK: [[VVAR2_PRIV:%.+]] = alloca [5 x [[S_FLOAT_TY]]], + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], + +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], +// CHECK: [[VVAR2_ORIG:%.+]] = load [5 x [[S_FLOAT_TY]]]*, [5 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]], + +// CHECK: [[LOW:%.+]] = getelementptr inbounds [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0 +// CHECK: [[ORIG_START:%.+]] = bitcast [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 +// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 +// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] +// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) +// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_PRIV]], i64 [[OFFSET]] +// CHECK: ret void + +// CHECK: define internal void [[MAIN_MICROTASK8]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}}) + +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], + +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], + +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], + +// CHECK: [[LOW:%.+]] = getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 1 +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], + +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 +// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 +// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] +// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) +// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i64 [[OFFSET]] +// CHECK: [[VAR3_PRIV:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]* + +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % + +// CHECK: ret void + +// CHECK: define internal void [[MAIN_MICROTASK9]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}}) + +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], + +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], + +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], + +// CHECK: [[LOW:%.+]] = getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 0 +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], + +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 +// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 +// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] +// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) +// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i64 [[OFFSET]] +// CHECK: [[VAR3_PRIV:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]* + +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % + +// CHECK: ret void + +// CHECK: define internal void [[MAIN_MICROTASK10]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}}) + +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*], + +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], // CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64 // CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW:%.+]] to i64 // CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]] @@ -955,44 +1127,47 @@ int main() { // CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1 // CHECK: call i8* @llvm.stacksave() // CHECK: [[VAR3_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* // CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 // CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 // CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] // CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) // CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VAR3_PRIV]], i64 [[OFFSET]] -// CHECK: [[VAR3_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VAR3_PRIV]] to [2 x [[S_FLOAT_TY]]]* +// CHECK: [[VAR3_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]* -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** % +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK11]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}}) -// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, -// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR3_PRIV:%.+]] = alloca [4 x [[S_FLOAT_TY]]], // Reduction list for runtime. // CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0 -// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 2 +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0 +// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 4 -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** % -// CHECK: bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % +// CHECK: bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* // CHECK: ret void -// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]() +// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT_42]]() // CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]], // CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]]) // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i32*, [[S_INT_TY]]*, [[S_INT_TY]]*, i32*, [2 x i32]*, [2 x [[S_INT_TY]]]*)* [[TMAIN_MICROTASK:@.+]] to void +// Not interested in this one: +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [42 x [[S_INT_TY]]]*, [2 x i32]*, i32*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]*)* [[TMAIN_MICROTASK2:@.+]] to void // CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]* // CHECK: ret // @@ -1226,5 +1401,27 @@ int main() { // CHECK: store i{{[0-9]+}} [[UP]], i{{[0-9]+}}* [[T_VAR1_LHS]], // CHECK: ret void +// CHECK: define internal void [[TMAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [42 x [[S_INT_TY]]]* dereferenceable(168) %{{.*}}, [2 x i32]* dereferenceable(8) %{{.*}}, i32* dereferenceable(4) %{{.*}}, [2 x [[S_INT_TY]]]* dereferenceable(8) %{{.*}}, [[S_INT_TY]]* dereferenceable(4) %{{.*}}) + +// CHECK: [[ARR_ORIG_ADDR:%.+]] = alloca [42 x [[S_INT_TY]]]*, +// CHECK: [[ARR_PRIV:%.+]] = alloca [40 x [[S_INT_TY]]], + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], + +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], + +// CHECK: [[ARR_ORIG:%.+]] = load [42 x [[S_INT_TY]]]*, [42 x [[S_INT_TY]]]** [[ARR_ORIG_ADDR]], +// CHECK: [[LOW:%.+]] = getelementptr inbounds [42 x [[S_INT_TY]]], [42 x [[S_INT_TY]]]* [[ARR_ORIG]], i64 0, i64 1 +// CHECK: [[ORIG_START:%.+]] = bitcast [42 x [[S_INT_TY]]]* [[ARR_ORIG]] to [[S_INT_TY]]* +// CHECK: [[START:%.+]] = ptrtoint [[S_INT_TY]]* [[ORIG_START]] to i64 +// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_INT_TY]]* [[LOW]] to i64 +// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] +// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (i32* getelementptr (i32, i32* null, i32 1) to i64) +// CHECK: [[PSEUDO_ARR_PRIV:%.+]] = getelementptr [40 x [[S_INT_TY]]], [40 x [[S_INT_TY]]]* [[ARR_PRIV]], i64 [[OFFSET]] +// CHECK: [[ARR_PRIV:%.+]] = bitcast [40 x [[S_INT_TY]]]* [[PSEUDO_ARR_PRIV]] to [42 x [[S_INT_TY]]]* + +// CHECK: ret void + #endif diff --git a/test/OpenMP/for_reduction_codegen_UDR.cpp b/test/OpenMP/for_reduction_codegen_UDR.cpp index 95b04f44d4..d78e515f30 100644 --- a/test/OpenMP/for_reduction_codegen_UDR.cpp +++ b/test/OpenMP/for_reduction_codegen_UDR.cpp @@ -40,7 +40,7 @@ void init_plus(BaseS1&, const BaseS1&); // CHECK-DAG: [[REDUCTION_LOCK:@.+]] = common global [8 x i32] zeroinitializer #pragma omp declare reduction(operator&& : int : omp_out = 111 & omp_in) -template +template T tmain() { T t; S test; @@ -49,6 +49,7 @@ T tmain() { S s_arr[] = {1, 2}; S &var = test; S var1; + S arr[length]; #pragma omp declare reduction(operator& : T : omp_out = 15 + omp_in) #pragma omp declare reduction(operator+ : T : omp_out = 1513 + omp_in) initializer(omp_priv = 321) #pragma omp declare reduction(min : T : omp_out = 47 - omp_in) initializer(omp_priv = 432 / omp_orig) @@ -66,6 +67,12 @@ T tmain() { vec[i] = t_var; s_arr[i] = var; } +#pragma omp parallel +#pragma omp for reduction(+ : arr[1:length-2]) + for (int i = 0; i < 2; ++i) { + vec[i] = t_var; + s_arr[i] = var; + } return T(); } @@ -78,12 +85,12 @@ int main() { S test; float t_var = 0, t_var1; int vec[] = {1, 2}; - S s_arr[] = {1, 2}; + S s_arr[] = {1, 2, 3, 4}; S &var = test; S var1, arrs[10][4]; S **var2 = foo(); - S vvar2[2]; - S(&var3)[2] = s_arr; + S vvar2[5]; + S(&var3)[4] = s_arr; #pragma omp declare reduction(operator+ : int : omp_out = 555 * omp_in) initializer(omp_priv = 888) #pragma omp parallel #pragma omp for reduction(+ : t_var) reduction(& : var) reduction(&& : var1) reduction(min : t_var1) @@ -115,24 +122,24 @@ int main() { #pragma omp for reduction(& : var3) for (int i = 0; i < 10; ++i) ; - return tmain(); + return tmain(); } // CHECK: define {{.*}}i{{[0-9]+}} @main() // CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]], // CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]]) -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [2 x i32]*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK1:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK2:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK3:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK4:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK5:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK6:@.+]] to void -// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]() +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [5 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK4:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK5:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK6:@.+]] to void +// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT_42:@.+]]() // CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]* // CHECK: ret // -// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [4 x [[S_FLOAT_TY]]]* dereferenceable(48) %{{.+}}) // CHECK: [[T_VAR_PRIV:%.+]] = alloca float, // CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]], // CHECK: [[VAR1_PRIV:%.+]] = alloca [[S_FLOAT_TY]], @@ -711,89 +718,85 @@ int main() { // CHECK: store [[S_FLOAT_TY]]* [[PSEUDO_VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]] // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [5 x [[S_FLOAT_TY]]]* dereferenceable(60) %{{.+}}) -// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, +// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [5 x [[S_FLOAT_TY]]]*, +// CHECK: [[VVAR2_PRIV:%.+]] = alloca [5 x [[S_FLOAT_TY]]], // Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*], +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VVAR2_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]], +// CHECK: [[VVAR2_ORIG:%.+]] = load [5 x [[S_FLOAT_TY]]]*, [5 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]], -// CHECK: [[LOW:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0 -// CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64 -// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 -// CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]] -// CHECK: [[DIF:%.+]] = sdiv exact i64 [[BYTE_DIF]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64) -// CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1 -// CHECK: call i8* @llvm.stacksave() -// CHECK: [[VVAR2_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]], -// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[LOW:%.+]] = getelementptr inbounds [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0 +// CHECK: [[ORIG_START:%.+]] = bitcast [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]* // CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 // CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 // CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] // CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64) -// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VVAR2_PRIV]], i64 [[OFFSET]] -// CHECK: [[VVAR2_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VVAR2_PRIV]] to [2 x [[S_FLOAT_TY]]]* +// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_PRIV]], i64 [[OFFSET]] // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(48) %{{.+}}) -// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], // Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*], +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], -// CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64 -// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW:%.+]] to i64 -// CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]] -// CHECK: [[DIF:%.+]] = sdiv exact i64 [[BYTE_DIF]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64) -// CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1 -// CHECK: call i8* @llvm.stacksave() -// CHECK: [[VAR3_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], + +// CHECK: [[LOW:%.+]] = getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 1 +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], + +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* // CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 // CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 // CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] // CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64) -// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VAR3_PRIV]], i64 [[OFFSET]] -// CHECK: [[VAR3_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VAR3_PRIV]] to [2 x [[S_FLOAT_TY]]]* +// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i64 [[OFFSET]] +// CHECK: [[VAR3_PRIV:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]* -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** % +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(48) %{{.+}}) -// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, -// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR3_PRIV:%.+]] = alloca [4 x [[S_FLOAT_TY]]], // Reduction list for runtime. // CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0 -// CHECK: bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* -// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 2 +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0 +// CHECK: bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 4 -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** % +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % // CHECK: ret void -// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]() +// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT_42]]() // CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]], // CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]]) // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i32*, [[S_INT_TY]]*, [[S_INT_TY]]*, i32*, [2 x i32]*, [2 x [[S_INT_TY]]]*)* [[TMAIN_MICROTASK:@.+]] to void +// Not interested in this one: +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [42 x [[S_INT_TY]]]*, [2 x i32]*, i32*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]*)* [[TMAIN_MICROTASK2:@.+]] to void +// CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]* // CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]* // CHECK: ret // @@ -964,5 +967,27 @@ int main() { // CHECK: sub nsw i32 47, % // CHECK: ret void +// CHECK: define internal void [[TMAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [42 x [[S_INT_TY]]]* dereferenceable(504) %{{.*}}, [2 x i32]* dereferenceable(8) %{{.*}}, i32* dereferenceable(4) %{{.*}}, [2 x [[S_INT_TY]]]* dereferenceable(24) %{{.*}}, [[S_INT_TY]]* dereferenceable(12) %{{.*}}) + +// CHECK: [[ARR_ORIG_ADDR:%.+]] = alloca [42 x [[S_INT_TY]]]*, +// CHECK: [[ARR_PRIV:%.+]] = alloca [40 x [[S_INT_TY]]], + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], + +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], + +// CHECK: [[ARR_ORIG:%.+]] = load [42 x [[S_INT_TY]]]*, [42 x [[S_INT_TY]]]** [[ARR_ORIG_ADDR]], +// CHECK: [[LOW:%.+]] = getelementptr inbounds [42 x [[S_INT_TY]]], [42 x [[S_INT_TY]]]* [[ARR_ORIG]], i64 0, i64 1 +// CHECK: [[ORIG_START:%.+]] = bitcast [42 x [[S_INT_TY]]]* [[ARR_ORIG]] to [[S_INT_TY]]* +// CHECK: [[START:%.+]] = ptrtoint [[S_INT_TY]]* [[ORIG_START]] to i64 +// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_INT_TY]]* [[LOW]] to i64 +// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] +// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint ([[S_INT_TY]]* getelementptr ([[S_INT_TY]], [[S_INT_TY]]* null, i32 1) to i64) +// CHECK: [[PSEUDO_ARR_PRIV:%.+]] = getelementptr [40 x [[S_INT_TY]]], [40 x [[S_INT_TY]]]* [[ARR_PRIV]], i64 [[OFFSET]] +// CHECK: [[ARR_PRIV:%.+]] = bitcast [40 x [[S_INT_TY]]]* [[PSEUDO_ARR_PRIV]] to [42 x [[S_INT_TY]]]* + +// CHECK: ret void + #endif -- GitLab From d194f2aeb2ae7ac5e7e5c7b41638e042665b0d05 Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Fri, 20 Oct 2017 20:16:17 +0000 Subject: [PATCH 0006/1682] Revert "[OpenMP] Avoid VLAs for some reductions on array sections" This breaks at least two buildbots: http://lab.llvm.org:8011/builders/clang-cmake-x86_64-avx2-linux/builds/1175 http://lab.llvm.org:8011/builders/clang-atom-d525-fedora-rel/builds/10478 This reverts commit r316229 during local investigation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316235 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGOpenMPRuntime.cpp | 10 +- lib/CodeGen/CGStmtOpenMP.cpp | 7 +- lib/Sema/SemaOpenMP.cpp | 83 +------ test/OpenMP/for_reduction_codegen.cpp | 289 ++++------------------ test/OpenMP/for_reduction_codegen_UDR.cpp | 133 ++++------ 5 files changed, 109 insertions(+), 413 deletions(-) diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index 3396c63cd6..f98ff85565 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -925,7 +925,7 @@ void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N) { cast(cast(ClausesData[N].Private)->getDecl()); QualType PrivateType = PrivateVD->getType(); bool AsArraySection = isa(ClausesData[N].Ref); - if (!PrivateType->isVariablyModifiedType()) { + if (!AsArraySection && !PrivateType->isVariablyModifiedType()) { Sizes.emplace_back( CGF.getTypeSize( SharedAddresses[N].first.getType().getNonReferenceType()), @@ -963,9 +963,10 @@ void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N, auto *PrivateVD = cast(cast(ClausesData[N].Private)->getDecl()); QualType PrivateType = PrivateVD->getType(); - if (!PrivateType->isVariablyModifiedType()) { + bool AsArraySection = isa(ClausesData[N].Ref); + if (!AsArraySection && !PrivateType->isVariablyModifiedType()) { assert(!Size && !Sizes[N].second && - "Size should be nullptr for non-variably modified reduction " + "Size should be nullptr for non-variably modified redution " "items."); return; } @@ -993,7 +994,8 @@ void ReductionCodeGen::emitInitialization( CGF.ConvertTypeForMem(SharedType)), SharedType, SharedAddresses[N].first.getBaseInfo(), CGF.CGM.getTBAAAccessInfo(SharedType)); - if (CGF.getContext().getAsArrayType(PrivateVD->getType())) { + if (isa(ClausesData[N].Ref) || + CGF.getContext().getAsArrayType(PrivateVD->getType())) { emitAggregateInitialization(CGF, N, PrivateAddr, SharedLVal, DRD); } else if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) { emitInitWithReductionInitializer(CGF, DRD, ClausesData[N].ReductionOp, diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index 0e5ea798eb..cdec3e35f9 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -996,9 +996,7 @@ void CodeGenFunction::EmitOMPReductionClauseInit( auto *LHSVD = cast(cast(*ILHS)->getDecl()); auto *RHSVD = cast(cast(*IRHS)->getDecl()); - QualType Type = PrivateVD->getType(); - bool isaOMPArraySectionExpr = isa(IRef); - if (isaOMPArraySectionExpr && Type->isVariablyModifiedType()) { + if (isa(IRef)) { // Store the address of the original variable associated with the LHS // implicit variable. PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() -> Address { @@ -1007,8 +1005,7 @@ void CodeGenFunction::EmitOMPReductionClauseInit( PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address { return GetAddrOfLocalVar(PrivateVD); }); - } else if ((isaOMPArraySectionExpr && Type->isScalarType()) || - isa(IRef)) { + } else if (isa(IRef)) { // Store the address of the original variable associated with the LHS // implicit variable. PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() -> Address { diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index bf89eb0b2f..a024888fbf 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -9330,68 +9330,6 @@ struct ReductionData { }; } // namespace -static bool CheckOMPArraySectionConstantForReduction( - ASTContext &Context, const OMPArraySectionExpr *OASE, bool &SingleElement, - SmallVectorImpl &ArraySizes) { - const Expr *Length = OASE->getLength(); - if (Length == nullptr) { - // For array sections of the form [1:] or [:], we would need to analyze - // the lower bound... - if (OASE->getColonLoc().isValid()) - return false; - - // This is an array subscript which has implicit length 1! - SingleElement = true; - ArraySizes.push_back(llvm::APSInt::get(1)); - } else { - llvm::APSInt ConstantLengthValue; - if (!Length->EvaluateAsInt(ConstantLengthValue, Context)) - return false; - - SingleElement = (ConstantLengthValue.getSExtValue() == 1); - ArraySizes.push_back(ConstantLengthValue); - } - - // Get the base of this array section and walk up from there. - const Expr *Base = OASE->getBase()->IgnoreParenImpCasts(); - - // We require length = 1 for all array sections except the right-most to - // guarantee that the memory region is contiguous and has no holes in it. - while (const auto *TempOASE = dyn_cast(Base)) { - Length = TempOASE->getLength(); - if (Length == nullptr) { - // For array sections of the form [1:] or [:], we would need to analyze - // the lower bound... - if (OASE->getColonLoc().isValid()) - return false; - - // This is an array subscript which has implicit length 1! - ArraySizes.push_back(llvm::APSInt::get(1)); - } else { - llvm::APSInt ConstantLengthValue; - if (!Length->EvaluateAsInt(ConstantLengthValue, Context) || - ConstantLengthValue.getSExtValue() != 1) - return false; - - ArraySizes.push_back(ConstantLengthValue); - } - Base = TempOASE->getBase()->IgnoreParenImpCasts(); - } - - // If we have a single element, we don't need to add the implicit lengths. - if (!SingleElement) { - while (const auto *TempASE = dyn_cast(Base)) { - // Has implicit length 1! - ArraySizes.push_back(llvm::APSInt::get(1)); - Base = TempASE->getBase()->IgnoreParenImpCasts(); - } - } - - // This array section can be privatized as a single value or as a constant - // sized array. - return true; -} - static bool ActOnOMPReductionKindClause( Sema &S, DSAStackTy *Stack, OpenMPClauseKind ClauseKind, ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -9690,26 +9628,7 @@ static bool ActOnOMPReductionKindClause( auto *RHSVD = buildVarDecl(S, ELoc, Type, D->getName(), D->hasAttrs() ? &D->getAttrs() : nullptr); auto PrivateTy = Type; - - // Try if we can determine constant lengths for all array sections and avoid - // the VLA. - bool ConstantLengthOASE = false; - if (OASE) { - bool SingleElement; - llvm::SmallVector ArraySizes; - ConstantLengthOASE = CheckOMPArraySectionConstantForReduction( - Context, OASE, SingleElement, ArraySizes); - - // If we don't have a single element, we must emit a constant array type. - if (ConstantLengthOASE && !SingleElement) { - for (auto &Size : ArraySizes) { - PrivateTy = Context.getConstantArrayType( - PrivateTy, Size, ArrayType::Normal, /*IndexTypeQuals=*/0); - } - } - } - - if ((OASE && !ConstantLengthOASE) || + if (OASE || (!ASE && D->getType().getNonReferenceType()->isVariablyModifiedType())) { // For arrays/array sections only: diff --git a/test/OpenMP/for_reduction_codegen.cpp b/test/OpenMP/for_reduction_codegen.cpp index 2c49022ff0..d5afae990b 100644 --- a/test/OpenMP/for_reduction_codegen.cpp +++ b/test/OpenMP/for_reduction_codegen.cpp @@ -27,7 +27,7 @@ struct S { // CHECK-DAG: [[REDUCTION_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 18, i32 0, i32 0, i8* // CHECK-DAG: [[REDUCTION_LOCK:@.+]] = common global [8 x i32] zeroinitializer -template +template T tmain() { T t; S test; @@ -36,7 +36,6 @@ T tmain() { S s_arr[] = {1, 2}; S &var = test; S var1; - S arr[length]; #pragma omp parallel #pragma omp for reduction(+:t_var) reduction(&:var) reduction(&& : var1) reduction(min: t_var1) nowait for (int i = 0; i < 2; ++i) { @@ -49,12 +48,6 @@ T tmain() { vec[i] = t_var; s_arr[i] = var; } -#pragma omp parallel -#pragma omp for reduction(+ : arr[1:length-2]) - for (int i = 0; i < 2; ++i) { - vec[i] = t_var; - s_arr[i] = var; - } return T(); } @@ -187,12 +180,12 @@ int main() { S test; float t_var = 0, t_var1; int vec[] = {1, 2}; - S s_arr[] = {1, 2, 3, 4}; + S s_arr[] = {1, 2}; S &var = test; S var1, arrs[10][4]; S **var2 = foo(); - S vvar2[5]; - S (&var3)[4] = s_arr; + S vvar2[2]; + S (&var3)[2] = s_arr; #pragma omp parallel #pragma omp for reduction(+:t_var) reduction(&:var) reduction(&& : var1) reduction(min: t_var1) for (int i = 0; i < 2; ++i) { @@ -212,18 +205,6 @@ int main() { for (int i = 0; i < 10; ++i) ; #pragma omp parallel -#pragma omp for reduction(& : var2[1][1 : 6]) - for (int i = 0; i < 10; ++i) - ; -#pragma omp parallel -#pragma omp for reduction(& : var2[1 : 1][1 : 6]) - for (int i = 0; i < 10; ++i) - ; -#pragma omp parallel -#pragma omp for reduction(& : var2[1 : 1][1]) - for (int i = 0; i < 10; ++i) - ; -#pragma omp parallel #pragma omp for reduction(& : vvar2[0 : 5]) for (int i = 0; i < 10; ++i) ; @@ -232,42 +213,28 @@ int main() { for (int i = 0; i < 10; ++i) ; #pragma omp parallel -#pragma omp for reduction(& : var3[ : 2]) - for (int i = 0; i < 10; ++i) - ; - // TODO: The compiler should also be able to generate a constant sized array in this case! -#pragma omp parallel -#pragma omp for reduction(& : var3[2 : ]) - for (int i = 0; i < 10; ++i) - ; -#pragma omp parallel #pragma omp for reduction(& : var3) for (int i = 0; i < 10; ++i) ; - return tmain(); + return tmain(); #endif } // CHECK: define {{.*}}i{{[0-9]+}} @main() // CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]], // CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]]) -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [2 x i32]*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK1:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK2:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK3:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK4:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK5:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK6:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [5 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK7:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK8:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK9:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK10:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK11:@.+]] to void -// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT_42:@.+]]() +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK4:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK5:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK6:@.+]] to void +// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]() // CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]* // CHECK: ret // -// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}}) // CHECK: [[T_VAR_PRIV:%.+]] = alloca float, // CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]], // CHECK: [[VAR1_PRIV:%.+]] = alloca [[S_FLOAT_TY]], @@ -943,183 +910,44 @@ int main() { // CHECK: store [[S_FLOAT_TY]]* [[PSEUDO_VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]] // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[S_FLOAT_TY]]*** dereferenceable(8) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}}) -// CHECK: [[VAR2_ORIG_ADDR:%.+]] = alloca [[S_FLOAT_TY]]***, -// CHECK: [[VAR2_PRIV:%.+]] = alloca [1 x [6 x [[S_FLOAT_TY]]]], +// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, // Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], - -// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VAR2_ORIG:%.+]] = load [[S_FLOAT_TY]]***, [[S_FLOAT_TY]]**** [[VAR2_ORIG_ADDR]], - -// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], -// CHECK: [[ARRIDX:%.+]] = getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], i64 1 -// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[ARRIDX]], -// CHECK: [[LOW:%.+]] = getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[LD]], i64 1 -// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], - -// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], -// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], -// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 -// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 -// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] -// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) -// CHECK: [[PSEUDO_VAR2_PRIV:%.+]] = getelementptr [1 x [6 x [[S_FLOAT_TY]]]], [1 x [6 x [[S_FLOAT_TY]]]]* [[VAR2_PRIV]], i64 [[OFFSET]] -// CHECK: store [[S_FLOAT_TY]]** [[REF:.+]], [[S_FLOAT_TY]]*** % -// CHECK: [[VAR2_PRIV:%.+]] = bitcast [1 x [6 x [[S_FLOAT_TY]]]]* [[PSEUDO_VAR2_PRIV]] to [[S_FLOAT_TY]]* -// CHECK: store [[S_FLOAT_TY]]* [[VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]] -// CHECK: ret void - -// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[S_FLOAT_TY]]*** dereferenceable(8) %{{.+}}) - -// CHECK: [[VAR2_ORIG_ADDR:%.+]] = alloca [[S_FLOAT_TY]]***, -// CHECK: [[VAR2_PRIV:%.+]] = alloca [1 x [6 x [[S_FLOAT_TY]]]], - -// Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], - -// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VAR2_ORIG:%.+]] = load [[S_FLOAT_TY]]***, [[S_FLOAT_TY]]**** [[VAR2_ORIG_ADDR]], - -// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], -// CHECK: [[ARRIDX:%.+]] = getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], i64 1 -// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[ARRIDX]], -// CHECK: [[LOW:%.+]] = getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[LD]], i64 1 -// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], - -// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], -// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], -// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 -// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 -// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] -// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) -// CHECK: [[PSEUDO_VAR2_PRIV:%.+]] = getelementptr [1 x [6 x [[S_FLOAT_TY]]]], [1 x [6 x [[S_FLOAT_TY]]]]* [[VAR2_PRIV]], i64 [[OFFSET]] -// CHECK: store [[S_FLOAT_TY]]** [[REF:.+]], [[S_FLOAT_TY]]*** % -// CHECK: [[VAR2_PRIV:%.+]] = bitcast [1 x [6 x [[S_FLOAT_TY]]]]* [[PSEUDO_VAR2_PRIV]] to [[S_FLOAT_TY]]* -// CHECK: store [[S_FLOAT_TY]]* [[VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]] -// CHECK: ret void - -// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[S_FLOAT_TY]]*** dereferenceable(8) %{{.+}}) - -// CHECK: [[VAR2_ORIG_ADDR:%.+]] = alloca [[S_FLOAT_TY]]***, -// CHECK: [[VAR2_PRIV:%.+]] = alloca [[S_FLOAT_TY]], - -// Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], - -// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VAR2_ORIG:%.+]] = load [[S_FLOAT_TY]]***, [[S_FLOAT_TY]]**** [[VAR2_ORIG_ADDR]], - -// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], -// CHECK: [[ARRIDX:%.+]] = getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], i64 1 -// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[ARRIDX]], -// CHECK: [[LOW:%.+]] = getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[LD]], i64 1 -// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], - -// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], -// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], -// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 -// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 -// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] -// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) -// CHECK: [[PSEUDO_VAR2_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VAR2_PRIV]], i64 [[OFFSET]] -// CHECK: store [[S_FLOAT_TY]]** [[REF:.+]], [[S_FLOAT_TY]]*** % -// CHECK: store [[S_FLOAT_TY]]* [[PSEUDO_VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]] -// CHECK: ret void - -// CHECK: define internal void [[MAIN_MICROTASK7]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [5 x [[S_FLOAT_TY]]]* dereferenceable(20) %{{.+}}) - -// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [5 x [[S_FLOAT_TY]]]*, -// CHECK: [[VVAR2_PRIV:%.+]] = alloca [5 x [[S_FLOAT_TY]]], - -// Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], - -// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VVAR2_ORIG:%.+]] = load [5 x [[S_FLOAT_TY]]]*, [5 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]], - -// CHECK: [[LOW:%.+]] = getelementptr inbounds [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0 -// CHECK: [[ORIG_START:%.+]] = bitcast [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]* -// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 -// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 -// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] -// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) -// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_PRIV]], i64 [[OFFSET]] -// CHECK: ret void - -// CHECK: define internal void [[MAIN_MICROTASK8]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}}) - -// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, -// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], - -// Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], - -// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], - -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], - -// CHECK: [[LOW:%.+]] = getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 1 -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], - -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* -// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 -// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 -// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] -// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) -// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i64 [[OFFSET]] -// CHECK: [[VAR3_PRIV:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]* - -// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % - -// CHECK: ret void - -// CHECK: define internal void [[MAIN_MICROTASK9]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}}) - -// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, -// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], - -// Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], +// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], +// CHECK: [[VVAR2_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]], -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], - -// CHECK: [[LOW:%.+]] = getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 0 -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], - -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[LOW:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0 +// CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64 +// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 +// CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]] +// CHECK: [[DIF:%.+]] = sdiv exact i64 [[BYTE_DIF]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) +// CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1 +// CHECK: call i8* @llvm.stacksave() +// CHECK: [[VVAR2_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]], +// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]* // CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 // CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 // CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] // CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) -// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i64 [[OFFSET]] -// CHECK: [[VAR3_PRIV:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]* - -// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % - +// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VVAR2_PRIV]], i64 [[OFFSET]] +// CHECK: [[VVAR2_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VVAR2_PRIV]] to [2 x [[S_FLOAT_TY]]]* // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK10]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}}) -// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, // Reduction list for runtime. // CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*], -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], +// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], // CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64 // CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW:%.+]] to i64 // CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]] @@ -1127,47 +955,44 @@ int main() { // CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1 // CHECK: call i8* @llvm.stacksave() // CHECK: [[VAR3_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]], -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* // CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 // CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 // CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] // CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) // CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VAR3_PRIV]], i64 [[OFFSET]] -// CHECK: [[VAR3_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]* +// CHECK: [[VAR3_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VAR3_PRIV]] to [2 x [[S_FLOAT_TY]]]* -// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % +// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** % // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK11]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}}) -// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, -// CHECK: [[VAR3_PRIV:%.+]] = alloca [4 x [[S_FLOAT_TY]]], +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], // Reduction list for runtime. // CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0 -// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 4 +// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], +// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0 +// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 2 -// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % -// CHECK: bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** % +// CHECK: bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* // CHECK: ret void -// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT_42]]() +// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]() // CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]], // CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]]) // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i32*, [[S_INT_TY]]*, [[S_INT_TY]]*, i32*, [2 x i32]*, [2 x [[S_INT_TY]]]*)* [[TMAIN_MICROTASK:@.+]] to void -// Not interested in this one: -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [42 x [[S_INT_TY]]]*, [2 x i32]*, i32*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]*)* [[TMAIN_MICROTASK2:@.+]] to void // CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]* // CHECK: ret // @@ -1401,27 +1226,5 @@ int main() { // CHECK: store i{{[0-9]+}} [[UP]], i{{[0-9]+}}* [[T_VAR1_LHS]], // CHECK: ret void -// CHECK: define internal void [[TMAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [42 x [[S_INT_TY]]]* dereferenceable(168) %{{.*}}, [2 x i32]* dereferenceable(8) %{{.*}}, i32* dereferenceable(4) %{{.*}}, [2 x [[S_INT_TY]]]* dereferenceable(8) %{{.*}}, [[S_INT_TY]]* dereferenceable(4) %{{.*}}) - -// CHECK: [[ARR_ORIG_ADDR:%.+]] = alloca [42 x [[S_INT_TY]]]*, -// CHECK: [[ARR_PRIV:%.+]] = alloca [40 x [[S_INT_TY]]], - -// Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], - -// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], - -// CHECK: [[ARR_ORIG:%.+]] = load [42 x [[S_INT_TY]]]*, [42 x [[S_INT_TY]]]** [[ARR_ORIG_ADDR]], -// CHECK: [[LOW:%.+]] = getelementptr inbounds [42 x [[S_INT_TY]]], [42 x [[S_INT_TY]]]* [[ARR_ORIG]], i64 0, i64 1 -// CHECK: [[ORIG_START:%.+]] = bitcast [42 x [[S_INT_TY]]]* [[ARR_ORIG]] to [[S_INT_TY]]* -// CHECK: [[START:%.+]] = ptrtoint [[S_INT_TY]]* [[ORIG_START]] to i64 -// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_INT_TY]]* [[LOW]] to i64 -// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] -// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (i32* getelementptr (i32, i32* null, i32 1) to i64) -// CHECK: [[PSEUDO_ARR_PRIV:%.+]] = getelementptr [40 x [[S_INT_TY]]], [40 x [[S_INT_TY]]]* [[ARR_PRIV]], i64 [[OFFSET]] -// CHECK: [[ARR_PRIV:%.+]] = bitcast [40 x [[S_INT_TY]]]* [[PSEUDO_ARR_PRIV]] to [42 x [[S_INT_TY]]]* - -// CHECK: ret void - #endif diff --git a/test/OpenMP/for_reduction_codegen_UDR.cpp b/test/OpenMP/for_reduction_codegen_UDR.cpp index d78e515f30..95b04f44d4 100644 --- a/test/OpenMP/for_reduction_codegen_UDR.cpp +++ b/test/OpenMP/for_reduction_codegen_UDR.cpp @@ -40,7 +40,7 @@ void init_plus(BaseS1&, const BaseS1&); // CHECK-DAG: [[REDUCTION_LOCK:@.+]] = common global [8 x i32] zeroinitializer #pragma omp declare reduction(operator&& : int : omp_out = 111 & omp_in) -template +template T tmain() { T t; S test; @@ -49,7 +49,6 @@ T tmain() { S s_arr[] = {1, 2}; S &var = test; S var1; - S arr[length]; #pragma omp declare reduction(operator& : T : omp_out = 15 + omp_in) #pragma omp declare reduction(operator+ : T : omp_out = 1513 + omp_in) initializer(omp_priv = 321) #pragma omp declare reduction(min : T : omp_out = 47 - omp_in) initializer(omp_priv = 432 / omp_orig) @@ -67,12 +66,6 @@ T tmain() { vec[i] = t_var; s_arr[i] = var; } -#pragma omp parallel -#pragma omp for reduction(+ : arr[1:length-2]) - for (int i = 0; i < 2; ++i) { - vec[i] = t_var; - s_arr[i] = var; - } return T(); } @@ -85,12 +78,12 @@ int main() { S test; float t_var = 0, t_var1; int vec[] = {1, 2}; - S s_arr[] = {1, 2, 3, 4}; + S s_arr[] = {1, 2}; S &var = test; S var1, arrs[10][4]; S **var2 = foo(); - S vvar2[5]; - S(&var3)[4] = s_arr; + S vvar2[2]; + S(&var3)[2] = s_arr; #pragma omp declare reduction(operator+ : int : omp_out = 555 * omp_in) initializer(omp_priv = 888) #pragma omp parallel #pragma omp for reduction(+ : t_var) reduction(& : var) reduction(&& : var1) reduction(min : t_var1) @@ -122,24 +115,24 @@ int main() { #pragma omp for reduction(& : var3) for (int i = 0; i < 10; ++i) ; - return tmain(); + return tmain(); } // CHECK: define {{.*}}i{{[0-9]+}} @main() // CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]], // CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]]) -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [2 x i32]*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK1:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK2:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK3:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [5 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK4:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK5:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK6:@.+]] to void -// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT_42:@.+]]() +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK4:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK5:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK6:@.+]] to void +// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]() // CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]* // CHECK: ret // -// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [4 x [[S_FLOAT_TY]]]* dereferenceable(48) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}}) // CHECK: [[T_VAR_PRIV:%.+]] = alloca float, // CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]], // CHECK: [[VAR1_PRIV:%.+]] = alloca [[S_FLOAT_TY]], @@ -718,85 +711,89 @@ int main() { // CHECK: store [[S_FLOAT_TY]]* [[PSEUDO_VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]] // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [5 x [[S_FLOAT_TY]]]* dereferenceable(60) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}}) -// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [5 x [[S_FLOAT_TY]]]*, -// CHECK: [[VVAR2_PRIV:%.+]] = alloca [5 x [[S_FLOAT_TY]]], +// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, // Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], +// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VVAR2_ORIG:%.+]] = load [5 x [[S_FLOAT_TY]]]*, [5 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]], +// CHECK: [[VVAR2_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]], -// CHECK: [[LOW:%.+]] = getelementptr inbounds [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0 -// CHECK: [[ORIG_START:%.+]] = bitcast [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[LOW:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0 +// CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64 +// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 +// CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]] +// CHECK: [[DIF:%.+]] = sdiv exact i64 [[BYTE_DIF]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64) +// CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1 +// CHECK: call i8* @llvm.stacksave() +// CHECK: [[VVAR2_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]], +// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]* // CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 // CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 // CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] // CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64) -// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_PRIV]], i64 [[OFFSET]] +// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VVAR2_PRIV]], i64 [[OFFSET]] +// CHECK: [[VVAR2_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VVAR2_PRIV]] to [2 x [[S_FLOAT_TY]]]* // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(48) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}}) -// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, -// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, // Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], +// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], - -// CHECK: [[LOW:%.+]] = getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 1 -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], - -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], +// CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64 +// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW:%.+]] to i64 +// CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]] +// CHECK: [[DIF:%.+]] = sdiv exact i64 [[BYTE_DIF]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64) +// CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1 +// CHECK: call i8* @llvm.stacksave() +// CHECK: [[VAR3_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]], +// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* // CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 // CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 // CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] // CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64) -// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i64 [[OFFSET]] -// CHECK: [[VAR3_PRIV:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]* +// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VAR3_PRIV]], i64 [[OFFSET]] +// CHECK: [[VAR3_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VAR3_PRIV]] to [2 x [[S_FLOAT_TY]]]* -// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % +// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** % // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(48) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}}) -// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, -// CHECK: [[VAR3_PRIV:%.+]] = alloca [4 x [[S_FLOAT_TY]]], +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], // Reduction list for runtime. // CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0 -// CHECK: bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* -// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 4 +// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], +// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0 +// CHECK: bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 2 -// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % +// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** % // CHECK: ret void -// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT_42]]() +// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]() // CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]], // CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]]) // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i32*, [[S_INT_TY]]*, [[S_INT_TY]]*, i32*, [2 x i32]*, [2 x [[S_INT_TY]]]*)* [[TMAIN_MICROTASK:@.+]] to void -// Not interested in this one: -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [42 x [[S_INT_TY]]]*, [2 x i32]*, i32*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]*)* [[TMAIN_MICROTASK2:@.+]] to void -// CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]* // CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]* // CHECK: ret // @@ -967,27 +964,5 @@ int main() { // CHECK: sub nsw i32 47, % // CHECK: ret void -// CHECK: define internal void [[TMAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [42 x [[S_INT_TY]]]* dereferenceable(504) %{{.*}}, [2 x i32]* dereferenceable(8) %{{.*}}, i32* dereferenceable(4) %{{.*}}, [2 x [[S_INT_TY]]]* dereferenceable(24) %{{.*}}, [[S_INT_TY]]* dereferenceable(12) %{{.*}}) - -// CHECK: [[ARR_ORIG_ADDR:%.+]] = alloca [42 x [[S_INT_TY]]]*, -// CHECK: [[ARR_PRIV:%.+]] = alloca [40 x [[S_INT_TY]]], - -// Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], - -// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], - -// CHECK: [[ARR_ORIG:%.+]] = load [42 x [[S_INT_TY]]]*, [42 x [[S_INT_TY]]]** [[ARR_ORIG_ADDR]], -// CHECK: [[LOW:%.+]] = getelementptr inbounds [42 x [[S_INT_TY]]], [42 x [[S_INT_TY]]]* [[ARR_ORIG]], i64 0, i64 1 -// CHECK: [[ORIG_START:%.+]] = bitcast [42 x [[S_INT_TY]]]* [[ARR_ORIG]] to [[S_INT_TY]]* -// CHECK: [[START:%.+]] = ptrtoint [[S_INT_TY]]* [[ORIG_START]] to i64 -// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_INT_TY]]* [[LOW]] to i64 -// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] -// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint ([[S_INT_TY]]* getelementptr ([[S_INT_TY]], [[S_INT_TY]]* null, i32 1) to i64) -// CHECK: [[PSEUDO_ARR_PRIV:%.+]] = getelementptr [40 x [[S_INT_TY]]], [40 x [[S_INT_TY]]]* [[ARR_PRIV]], i64 [[OFFSET]] -// CHECK: [[ARR_PRIV:%.+]] = bitcast [40 x [[S_INT_TY]]]* [[PSEUDO_ARR_PRIV]] to [42 x [[S_INT_TY]]]* - -// CHECK: ret void - #endif -- GitLab From 7c9e1b206cf638c52f79705f3cd557546dc262cc Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 20 Oct 2017 22:56:25 +0000 Subject: [PATCH 0007/1682] Implement current CWG direction for support of arrays of unknown bounds in constant expressions. We permit array-to-pointer decay on such arrays, but disallow pointer arithmetic (since we do not know whether it will have defined behavior). This is based on r311970 and r301822 (the former by me and the latter by Robert Haberlach). Between then and now, two things have changed: we have committee feedback indicating that this is indeed the right direction, and the code broken by this change has been fixed. This is necessary in C++17 to continue accepting certain forms of non-type template argument involving arrays of unknown bound. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316245 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticASTKinds.td | 9 ++ include/clang/Basic/DiagnosticIDs.h | 2 +- lib/AST/ExprConstant.cpp | 93 +++++++++++++------ test/SemaCXX/constant-expression-cxx11.cpp | 35 ++++--- .../SemaCXX/constexpr-array-unknown-bound.cpp | 26 ++++++ test/SemaTemplate/temp_arg_nontype_cxx1z.cpp | 3 + 6 files changed, 128 insertions(+), 40 deletions(-) create mode 100644 test/SemaCXX/constexpr-array-unknown-bound.cpp diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index b3cba2066e..215580b2e9 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -127,6 +127,10 @@ def note_constexpr_access_null : Note< def note_constexpr_access_past_end : Note< "%select{read of|assignment to|increment of|decrement of}0 " "dereferenced one-past-the-end pointer is not allowed in a constant expression">; +def note_constexpr_access_unsized_array : Note< + "%select{read of|assignment to|increment of|decrement of}0 " + "pointer to element of array without known bound " + "is not allowed in a constant expression">; def note_constexpr_access_inactive_union_member : Note< "%select{read of|assignment to|increment of|decrement of}0 " "member %1 of union with %select{active member %3|no active member}2 " @@ -154,6 +158,11 @@ def note_constexpr_baa_insufficient_alignment : Note< def note_constexpr_baa_value_insufficient_alignment : Note< "value of the aligned pointer (%0) is not a multiple of the asserted %1 " "%plural{1:byte|:bytes}1">; +def note_constexpr_unsupported_unsized_array : Note< + "array-to-pointer decay of array member without known bound is not supported">; +def note_constexpr_unsized_array_indexed : Note< + "indexing of array without known bound is not allowed " + "in a constant expression">; def warn_integer_constant_overflow : Warning< "overflow in expression; result is %0 with type %1">, diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h index ca04ccacf6..a62d6af744 100644 --- a/include/clang/Basic/DiagnosticIDs.h +++ b/include/clang/Basic/DiagnosticIDs.h @@ -34,7 +34,7 @@ namespace clang { DIAG_SIZE_SERIALIZATION = 120, DIAG_SIZE_LEX = 400, DIAG_SIZE_PARSE = 500, - DIAG_SIZE_AST = 110, + DIAG_SIZE_AST = 150, DIAG_SIZE_COMMENT = 100, DIAG_SIZE_CROSSTU = 100, DIAG_SIZE_SEMA = 3500, diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index ecce50ed23..c25b3b6322 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -62,7 +62,13 @@ namespace { static QualType getType(APValue::LValueBase B) { if (!B) return QualType(); if (const ValueDecl *D = B.dyn_cast()) - return D->getType(); + // FIXME: It's unclear where we're supposed to take the type from, and + // this actually matters for arrays of unknown bound. Using the type of + // the most recent declaration isn't clearly correct in general. Eg: + // + // extern int arr[]; void f() { extern int arr[3]; }; + // constexpr int *p = &arr[1]; // valid? + return cast(D->getMostRecentDecl())->getType(); const Expr *Base = B.get(); @@ -141,6 +147,12 @@ namespace { return E && E->getType()->isPointerType() && tryUnwrapAllocSizeCall(E); } + /// The bound to claim that an array of unknown bound has. + /// The value in MostDerivedArraySize is undefined in this case. So, set it + /// to an arbitrary value that's likely to loudly break things if it's used. + static const uint64_t AssumedSizeForUnsizedArray = + std::numeric_limits::max() / 2; + /// Determines if an LValue with the given LValueBase will have an unsized /// array in its designator. /// Find the path length and type of the most-derived subobject in the given @@ -148,7 +160,8 @@ namespace { static unsigned findMostDerivedSubobject(ASTContext &Ctx, APValue::LValueBase Base, ArrayRef Path, - uint64_t &ArraySize, QualType &Type, bool &IsArray) { + uint64_t &ArraySize, QualType &Type, bool &IsArray, + bool &FirstEntryIsUnsizedArray) { // This only accepts LValueBases from APValues, and APValues don't support // arrays that lack size info. assert(!isBaseAnAllocSizeCall(Base) && @@ -158,12 +171,18 @@ namespace { for (unsigned I = 0, N = Path.size(); I != N; ++I) { if (Type->isArrayType()) { - const ConstantArrayType *CAT = - cast(Ctx.getAsArrayType(Type)); - Type = CAT->getElementType(); - ArraySize = CAT->getSize().getZExtValue(); + const ArrayType *AT = Ctx.getAsArrayType(Type); + Type = AT->getElementType(); MostDerivedLength = I + 1; IsArray = true; + + if (auto *CAT = dyn_cast(AT)) { + ArraySize = CAT->getSize().getZExtValue(); + } else { + assert(I == 0 && "unexpected unsized array designator"); + FirstEntryIsUnsizedArray = true; + ArraySize = AssumedSizeForUnsizedArray; + } } else if (Type->isAnyComplexType()) { const ComplexType *CT = Type->castAs(); Type = CT->getElementType(); @@ -246,10 +265,12 @@ namespace { Entries.insert(Entries.end(), VEntries.begin(), VEntries.end()); if (V.getLValueBase()) { bool IsArray = false; + bool FirstIsUnsizedArray = false; MostDerivedPathLength = findMostDerivedSubobject( Ctx, V.getLValueBase(), V.getLValuePath(), MostDerivedArraySize, - MostDerivedType, IsArray); + MostDerivedType, IsArray, FirstIsUnsizedArray); MostDerivedIsArrayElement = IsArray; + FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray; } } } @@ -318,7 +339,7 @@ namespace { // The value in MostDerivedArraySize is undefined in this case. So, set it // to an arbitrary value that's likely to loudly break things if it's // used. - MostDerivedArraySize = std::numeric_limits::max() / 2; + MostDerivedArraySize = AssumedSizeForUnsizedArray; MostDerivedPathLength = Entries.size(); } /// Update this designator to refer to the given base or member of this @@ -350,6 +371,7 @@ namespace { MostDerivedArraySize = 2; MostDerivedPathLength = Entries.size(); } + void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E); void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, const APSInt &N); /// Add N to the address of this subobject. @@ -357,6 +379,7 @@ namespace { if (Invalid || !N) return; uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue(); if (isMostDerivedAnUnsizedArray()) { + diagnoseUnsizedArrayPointerArithmetic(Info, E); // Can't verify -- trust that the user is doing the right thing (or if // not, trust that the caller will catch the bad behavior). // FIXME: Should we reject if this overflows, at least? @@ -1094,9 +1117,19 @@ bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E, setInvalid(); return false; } + // Note, we do not diagnose if isMostDerivedAnUnsizedArray(), because there + // must actually be at least one array element; even a VLA cannot have a + // bound of zero. And if our index is nonzero, we already had a CCEDiag. return true; } +void SubobjectDesignator::diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, + const Expr *E) { + Info.CCEDiag(E, diag::note_constexpr_unsized_array_indexed); + // Do not set the designator as invalid: we can represent this situation, + // and correct handling of __builtin_object_size requires us to do so. +} + void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, const APSInt &N) { @@ -1240,8 +1273,6 @@ namespace { IsNullPtr); else { assert(!InvalidBase && "APValues can't handle invalid LValue bases"); - assert(!Designator.FirstEntryIsAnUnsizedArray && - "Unsized array with a valid base?"); V = APValue(Base, Offset, Designator.Entries, Designator.IsOnePastTheEnd, CallIndex, IsNullPtr); } @@ -1314,10 +1345,14 @@ namespace { if (checkSubobject(Info, E, isa(D) ? CSK_Field : CSK_Base)) Designator.addDeclUnchecked(D, Virtual); } - void addUnsizedArray(EvalInfo &Info, QualType ElemTy) { - assert(Designator.Entries.empty() && getType(Base)->isPointerType()); - assert(isBaseAnAllocSizeCall(Base) && - "Only alloc_size bases can have unsized arrays"); + void addUnsizedArray(EvalInfo &Info, const Expr *E, QualType ElemTy) { + if (!Designator.Entries.empty()) { + Info.CCEDiag(E, diag::note_constexpr_unsupported_unsized_array); + Designator.setInvalid(); + return; + } + + assert(getType(Base)->isPointerType() || getType(Base)->isArrayType()); Designator.FirstEntryIsAnUnsizedArray = true; Designator.addUnsizedArrayUnchecked(ElemTy); } @@ -2624,10 +2659,12 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, if (Sub.Invalid) // A diagnostic will have already been produced. return handler.failed(); - if (Sub.isOnePastTheEnd()) { + if (Sub.isOnePastTheEnd() || Sub.isMostDerivedAnUnsizedArray()) { if (Info.getLangOpts().CPlusPlus11) - Info.FFDiag(E, diag::note_constexpr_access_past_end) - << handler.AccessKind; + Info.FFDiag(E, Sub.isOnePastTheEnd() + ? diag::note_constexpr_access_past_end + : diag::note_constexpr_access_unsized_array) + << handler.AccessKind; else Info.FFDiag(E); return handler.failed(); @@ -5487,7 +5524,7 @@ static bool evaluateLValueAsAllocSize(EvalInfo &Info, APValue::LValueBase Base, Result.setInvalid(E); QualType Pointee = E->getType()->castAs()->getPointeeType(); - Result.addUnsizedArray(Info, Pointee); + Result.addUnsizedArray(Info, E, Pointee); return true; } @@ -5697,7 +5734,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { return true; } } - case CK_ArrayToPointerDecay: + + case CK_ArrayToPointerDecay: { if (SubExpr->isGLValue()) { if (!evaluateLValue(SubExpr, Result)) return false; @@ -5708,12 +5746,13 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { return false; } // The result is a pointer to the first element of the array. - if (const ConstantArrayType *CAT - = Info.Ctx.getAsConstantArrayType(SubExpr->getType())) + auto *AT = Info.Ctx.getAsArrayType(SubExpr->getType()); + if (auto *CAT = dyn_cast(AT)) Result.addArray(Info, E, CAT); else - Result.Designator.setInvalid(); + Result.addUnsizedArray(Info, E, AT->getElementType()); return true; + } case CK_FunctionToPointerDecay: return evaluateLValue(SubExpr, Result); @@ -5780,7 +5819,7 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) { Result.setInvalid(E); QualType PointeeTy = E->getType()->castAs()->getPointeeType(); - Result.addUnsizedArray(Info, PointeeTy); + Result.addUnsizedArray(Info, E, PointeeTy); return true; } @@ -7341,7 +7380,8 @@ static const Expr *ignorePointerCastsAndParens(const Expr *E) { /// Please note: this function is specialized for how __builtin_object_size /// views "objects". /// -/// If this encounters an invalid RecordDecl, it will always return true. +/// If this encounters an invalid RecordDecl or otherwise cannot determine the +/// correct result, it will always return true. static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) { assert(!LVal.Designator.Invalid); @@ -7372,9 +7412,8 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) { unsigned I = 0; QualType BaseType = getType(Base); if (LVal.Designator.FirstEntryIsAnUnsizedArray) { - assert(isBaseAnAllocSizeCall(Base) && - "Unsized array in non-alloc_size call?"); - // If this is an alloc_size base, we should ignore the initial array index + // If we don't know the array bound, conservatively assume we're looking at + // the final array element. ++I; BaseType = BaseType->castAs()->getPointeeType(); } diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index e64f2d5a33..68b82c7d96 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -604,20 +604,31 @@ static_assert(NATDCArray{}[1][1].n == 0, ""); } -// Tests for indexes into arrays of unknown bounds. +// Per current CWG direction, we reject any cases where pointer arithmetic is +// not statically known to be valid. namespace ArrayOfUnknownBound { - // This is a corner case of the language where it's not clear whether this - // should be an error: When we see the initializer for Z::a, the bounds of - // Z::b aren't known yet, but they will be known by the end of the translation - // unit, so the compiler can in theory check the indexing into Z::b. - // For the time being, as long as this is unclear, we want to make sure that - // this compiles. - struct Z { - static const void *const a[]; - static const void *const b[]; + extern int arr[]; + constexpr int *a = arr; + constexpr int *b = &arr[0]; + static_assert(a == b, ""); + constexpr int *c = &arr[1]; // expected-error {{constant}} expected-note {{indexing of array without known bound}} + constexpr int *d = &a[1]; // expected-error {{constant}} expected-note {{indexing of array without known bound}} + constexpr int *e = a + 1; // expected-error {{constant}} expected-note {{indexing of array without known bound}} + + struct X { + int a; + int b[]; // expected-warning {{C99}} }; - constexpr const void *Z::a[] = {&b[0], &b[1]}; - constexpr const void *Z::b[] = {&a[0], &a[1]}; + extern X x; + constexpr int *xb = x.b; // expected-error {{constant}} expected-note {{not supported}} + + struct Y { int a; }; + extern Y yarr[]; + constexpr Y *p = yarr; + constexpr int *q = &p->a; + + extern const int carr[]; // expected-note {{here}} + constexpr int n = carr[0]; // expected-error {{constant}} expected-note {{non-constexpr variable}} } namespace DependentValues { diff --git a/test/SemaCXX/constexpr-array-unknown-bound.cpp b/test/SemaCXX/constexpr-array-unknown-bound.cpp new file mode 100644 index 0000000000..395c4cbd12 --- /dev/null +++ b/test/SemaCXX/constexpr-array-unknown-bound.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 %s -Wno-uninitialized -std=c++1z -fsyntax-only -verify + +const extern int arr[]; +constexpr auto p = arr; // ok +constexpr int f(int i) {return p[i];} // expected-note {{read of dereferenced one-past-the-end pointer}} + +constexpr int arr[] {1, 2, 3}; +constexpr auto p2 = arr + 2; // ok +constexpr int x = f(2); // ok +constexpr int y = f(3); // expected-error {{constant expression}} +// expected-note-re@-1 {{in call to 'f({{.*}})'}} + +// FIXME: consider permitting this case +struct A {int m[];} a; +constexpr auto p3 = a.m; // expected-error {{constant expression}} expected-note {{without known bound}} +constexpr auto p4 = a.m + 1; // expected-error {{constant expression}} expected-note {{without known bound}} + +void g(int i) { + int arr[i]; + constexpr auto *p = arr + 2; // expected-error {{constant expression}} expected-note {{without known bound}} + + // FIXME: Give a better diagnostic here. The issue is that computing + // sizeof(*arr2) within the array indexing fails due to the VLA. + int arr2[2][i]; + constexpr int m = ((void)arr2[2], 0); // expected-error {{constant expression}} +} diff --git a/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp index c1fcedd58d..d0fb25c047 100644 --- a/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp +++ b/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp @@ -23,6 +23,9 @@ namespace Array { A h; // expected-error {{refers to subobject '&x + 1'}} A i; // expected-error {{not allowed in a converted constant}} A j; + + extern char aub[]; + A k; } namespace Function { -- GitLab From 4290aec8a46597a28a2ff921b4abcd63f62150a6 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Fri, 20 Oct 2017 23:29:59 +0000 Subject: [PATCH 0008/1682] [Analyzer] Correctly handle parameters passed by reference when bodyfarming std::call_once Explicitly not supporting functor objects. Differential Revision: https://reviews.llvm.org/D39031 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316249 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/BodyFarm.cpp | 58 ++++++++++++++++++++++++++++--------- test/Analysis/call_once.cpp | 41 ++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 14 deletions(-) diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp index 9568ec7519..6a8b529bba 100644 --- a/lib/Analysis/BodyFarm.cpp +++ b/lib/Analysis/BodyFarm.cpp @@ -264,11 +264,8 @@ static CallExpr *create_call_once_funcptr_call(ASTContext &C, ASTMaker M, static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M, const ParmVarDecl *Callback, - QualType CallbackType, + CXXRecordDecl *CallbackDecl, ArrayRef CallArgs) { - - CXXRecordDecl *CallbackDecl = CallbackType->getAsCXXRecordDecl(); - assert(CallbackDecl != nullptr); assert(CallbackDecl->isLambda()); FunctionDecl *callOperatorDecl = CallbackDecl->getLambdaCallOperator(); @@ -319,6 +316,9 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { const ParmVarDecl *Flag = D->getParamDecl(0); const ParmVarDecl *Callback = D->getParamDecl(1); QualType CallbackType = Callback->getType().getNonReferenceType(); + + // Nullable pointer, non-null iff function is a CXXRecordDecl. + CXXRecordDecl *CallbackRecordDecl = CallbackType->getAsCXXRecordDecl(); QualType FlagType = Flag->getType().getNonReferenceType(); auto *FlagRecordDecl = dyn_cast_or_null(FlagType->getAsTagDecl()); @@ -348,28 +348,58 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { return nullptr; } - bool isLambdaCall = CallbackType->getAsCXXRecordDecl() && - CallbackType->getAsCXXRecordDecl()->isLambda(); + bool isLambdaCall = CallbackRecordDecl && CallbackRecordDecl->isLambda(); + if (CallbackRecordDecl && !isLambdaCall) { + DEBUG(llvm::dbgs() << "Not supported: synthesizing body for functors when " + << "body farming std::call_once, ignoring the call."); + return nullptr; + } SmallVector CallArgs; + const FunctionProtoType *CallbackFunctionType; + if (isLambdaCall) { - if (isLambdaCall) // Lambda requires callback itself inserted as a first parameter. CallArgs.push_back( M.makeDeclRefExpr(Callback, /* RefersToEnclosingVariableOrCapture= */ true)); + CallbackFunctionType = CallbackRecordDecl->getLambdaCallOperator() + ->getType() + ->getAs(); + } else { + CallbackFunctionType = + CallbackType->getPointeeType()->getAs(); + } - // All arguments past first two ones are passed to the callback. - for (unsigned int i = 2; i < D->getNumParams(); i++) - CallArgs.push_back( - M.makeLvalueToRvalue(D->getParamDecl(i), - /* RefersToEnclosingVariableOrCapture= */ false)); + if (!CallbackFunctionType) + return nullptr; + + // First two arguments are used for the flag and for the callback. + if (D->getNumParams() != CallbackFunctionType->getNumParams() + 2) { + DEBUG(llvm::dbgs() << "Number of params of the callback does not match " + << "the number of params passed to std::call_once, " + << "ignoring the call"); + return nullptr; + } + + // All arguments past first two ones are passed to the callback, + // and we turn lvalues into rvalues if the argument is not passed by + // reference. + for (unsigned int ParamIdx = 2; ParamIdx < D->getNumParams(); ParamIdx++) { + const ParmVarDecl *PDecl = D->getParamDecl(ParamIdx); + Expr *ParamExpr = M.makeDeclRefExpr(PDecl); + if (!CallbackFunctionType->getParamType(ParamIdx - 2)->isReferenceType()) { + QualType PTy = PDecl->getType().getNonReferenceType(); + ParamExpr = M.makeLvalueToRvalue(ParamExpr, PTy); + } + CallArgs.push_back(ParamExpr); + } CallExpr *CallbackCall; if (isLambdaCall) { - CallbackCall = - create_call_once_lambda_call(C, M, Callback, CallbackType, CallArgs); + CallbackCall = create_call_once_lambda_call(C, M, Callback, + CallbackRecordDecl, CallArgs); } else { // Function pointer case. diff --git a/test/Analysis/call_once.cpp b/test/Analysis/call_once.cpp index befddca752..db701457f6 100644 --- a/test/Analysis/call_once.cpp +++ b/test/Analysis/call_once.cpp @@ -249,3 +249,44 @@ void g(); void test_no_segfault_on_different_impl() { std::call_once(g, false); // no-warning } + +void test_lambda_refcapture() { + static std::once_flag flag; + int a = 6; + std::call_once(flag, [&](int &a) { a = 42; }, a); + clang_analyzer_eval(a == 42); // expected-warning{{TRUE}} +} + +void test_lambda_refcapture2() { + static std::once_flag flag; + int a = 6; + std::call_once(flag, [=](int &a) { a = 42; }, a); + clang_analyzer_eval(a == 42); // expected-warning{{TRUE}} +} + +void test_lambda_fail_refcapture() { + static std::once_flag flag; + int a = 6; + std::call_once(flag, [=](int a) { a = 42; }, a); + clang_analyzer_eval(a == 42); // expected-warning{{FALSE}} +} + +void mutator(int ¶m) { + param = 42; +} +void test_reftypes_funcptr() { + static std::once_flag flag; + int a = 6; + std::call_once(flag, &mutator, a); + clang_analyzer_eval(a == 42); // expected-warning{{TRUE}} +} + +void fail_mutator(int param) { + param = 42; +} +void test_mutator_noref() { + static std::once_flag flag; + int a = 6; + std::call_once(flag, &fail_mutator, a); + clang_analyzer_eval(a == 42); // expected-warning{{FALSE}} +} -- GitLab From 0e806a85e1c72fb46fdf6efdf69618a3db20af63 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Fri, 20 Oct 2017 23:32:41 +0000 Subject: [PATCH 0009/1682] [CodeGen] add tests for __builtin_sqrt*; NFC I don't know if this is correct, but this is what we currently do. More discussion in PR27108 and PR27435 and D27618. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316250 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/CodeGen/builtins.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/CodeGen/builtins.c b/test/CodeGen/builtins.c index 3584585de8..86bee451ec 100644 --- a/test/CodeGen/builtins.c +++ b/test/CodeGen/builtins.c @@ -317,6 +317,15 @@ void test_float_builtin_ops(float F, double D, long double LD) { resld = __builtin_floorl(LD); // CHECK: call x86_fp80 @llvm.floor.f80 + resf = __builtin_sqrtf(F); + // CHECK: call float @sqrtf( + + resd = __builtin_sqrt(D); + // CHECK: call double @sqrt( + + resld = __builtin_sqrtl(LD); + // CHECK: call x86_fp80 @sqrtl( + resf = __builtin_truncf(F); // CHECK: call float @llvm.trunc.f32 -- GitLab From 3bddc261ddb5a58ab6dcb502d4889c4ccd5775c4 Mon Sep 17 00:00:00 2001 From: Masud Rahman Date: Sat, 21 Oct 2017 16:03:17 +0000 Subject: [PATCH 0010/1682] Test commit git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316263 91177308-0d34-0410-b5e6-96231b3b80d8 --- README.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.txt b/README.txt index 5477b9c8ba..b5f33bb66d 100644 --- a/README.txt +++ b/README.txt @@ -13,10 +13,10 @@ different source-level tools. One example of this is the Clang Static Analyzer. If you're interested in more (including how to build Clang) it is best to read the relevant web sites. Here are some pointers: -Information on Clang: http://clang.llvm.org/ -Building and using Clang: http://clang.llvm.org/get_started.html -Clang Static Analyzer: http://clang-analyzer.llvm.org/ -Information on the LLVM project: http://llvm.org/ +Information on Clang: http://clang.llvm.org/ +Building and using Clang: http://clang.llvm.org/get_started.html +Clang Static Analyzer: http://clang-analyzer.llvm.org/ +Information on the LLVM project: http://llvm.org/ If you have questions or comments about Clang, a great place to discuss them is on the Clang development mailing list: -- GitLab From a6d3ef724655a64ac137945615d3ff002c4f7993 Mon Sep 17 00:00:00 2001 From: Masud Rahman Date: Sat, 21 Oct 2017 16:13:41 +0000 Subject: [PATCH 0011/1682] [bindings] allow null strings in Python 3 Some API calls accept 'NULL' instead of a char array (e.g. the second argument to 'clang_ParseTranslationUnit'). For Python 3 compatibility, all strings are passed through 'c_interop_string' which expects to receive only 'bytes' or 'str' objects. This change extends this behavior to additionally allow 'None' to be supplied. A test case was added which breaks in Python 3, and is fixed by this change. All the test cases pass in both, Python 2 and Python 3. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316264 91177308-0d34-0410-b5e6-96231b3b80d8 --- bindings/python/clang/cindex.py | 3 +++ bindings/python/tests/cindex/test_index.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py index 1dc1760e4f..d72dd14ef9 100644 --- a/bindings/python/clang/cindex.py +++ b/bindings/python/clang/cindex.py @@ -94,6 +94,9 @@ if sys.version_info[0] == 3: return cls(param) if isinstance(param, bytes): return cls(param) + if param is None: + # Support passing null to C functions expecting char arrays + return None raise TypeError("Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__)) @staticmethod diff --git a/bindings/python/tests/cindex/test_index.py b/bindings/python/tests/cindex/test_index.py index dc173f04d2..ef76692a52 100644 --- a/bindings/python/tests/cindex/test_index.py +++ b/bindings/python/tests/cindex/test_index.py @@ -13,3 +13,5 @@ def test_parse(): assert isinstance(index, Index) tu = index.parse(os.path.join(kInputsDir, 'hello.cpp')) assert isinstance(tu, TranslationUnit) + tu = index.parse(None, ['-c', os.path.join(kInputsDir, 'hello.cpp')]) + assert isinstance(tu, TranslationUnit) -- GitLab From f8efbbb5411503a88259972c23373b68f77a8b46 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Sat, 21 Oct 2017 16:43:01 +0000 Subject: [PATCH 0012/1682] Fixing broken attribute documentation for __attribute__((noescape)); a code block was missing and the existing code block was missing a mandatory newline. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316267 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/AttrDocs.td | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td index 78a40c4693..ecff329c4c 100644 --- a/include/clang/Basic/AttrDocs.td +++ b/include/clang/Basic/AttrDocs.td @@ -142,6 +142,7 @@ annotated with ``noescape`` do not actuallly escape. For example: .. code-block:: c + int *gp; void nonescapingFunc(__attribute__((noescape)) int *p) { @@ -156,6 +157,8 @@ Additionally, when the parameter is a `block pointer `, the same restriction applies to copies of the block. For example: +.. code-block:: c + typedef void (^BlockTy)(); BlockTy g0, g1; -- GitLab From 7f6cbacea16f8b55438736825ca6a899819b82a8 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Sat, 21 Oct 2017 16:44:03 +0000 Subject: [PATCH 0013/1682] [Sema] Fixes for enum handling for tautological comparison diagnostics Summary: As Mattias Eriksson has reported in PR35009, in C, for enums, the underlying type should be used when checking for the tautological comparison, unlike C++, where the enumerator values define the value range. So if not in CPlusPlus mode, use the enum underlying type. Also, i have discovered a problem (a crash) when evaluating tautological-ness of the following comparison: ``` enum A { A_a = 0 }; if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; ``` This affects both the C and C++, but after the first fix, only C++ code was affected. That was also fixed, while preserving (i think?) the proper diagnostic output. And while there, attempt to enhance the test coverage. Yes, some tests got moved around, sorry about that :) Fixes PR35009 Reviewers: aaron.ballman, rsmith, rjmccall Reviewed By: aaron.ballman Subscribers: Rakete1111, efriedma, materi, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D39122 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316268 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaChecking.cpp | 29 +- test/Sema/outof-range-enum-constant-compare.c | 379 ++++++++++++++++ .../Sema/tautological-constant-enum-compare.c | 419 ++++++++++++++++++ .../tautological-unsigned-enum-zero-compare.c | 220 ++++++++- ...autological-unsigned-enum-zero-compare.cpp | 243 ++++++++-- 5 files changed, 1232 insertions(+), 58 deletions(-) create mode 100644 test/Sema/outof-range-enum-constant-compare.c create mode 100644 test/Sema/tautological-constant-enum-compare.c diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 79263f1e3a..53e710d7b7 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -8181,8 +8181,12 @@ struct IntRange { if (const AtomicType *AT = dyn_cast(T)) T = AT->getValueType().getTypePtr(); - // For enum types, use the known bit width of the enumerators. - if (const EnumType *ET = dyn_cast(T)) { + if (!C.getLangOpts().CPlusPlus) { + // For enum types in C code, use the underlying datatype. + if (const EnumType *ET = dyn_cast(T)) + T = ET->getDecl()->getIntegerType().getDesugaredType(C).getTypePtr(); + } else if (const EnumType *ET = dyn_cast(T)) { + // For enum types in C++, use the known bit width of the enumerators. EnumDecl *Enum = ET->getDecl(); // In C++11, enums without definitions can have an explicitly specified // underlying type. Use this type to compute the range. @@ -8584,8 +8588,10 @@ bool isNonBooleanUnsignedValue(Expr *E) { } enum class LimitType { - Max, // e.g. 32767 for short - Min // e.g. -32768 for short + Max = 1U << 0U, // e.g. 32767 for short + Min = 1U << 1U, // e.g. -32768 for short + Both = Max | Min // When the value is both the Min and the Max limit at the + // same time; e.g. in C++, A::a in enum A { a = 0 }; }; /// Checks whether Expr 'Constant' may be the @@ -8608,6 +8614,10 @@ llvm::Optional IsTypeLimit(Sema &S, Expr *Constant, Expr *Other, IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT); + // Special-case for C++ for enum with one enumerator with value of 0. + if (OtherRange.Width == 0) + return Value == 0 ? LimitType::Both : llvm::Optional(); + if (llvm::APSInt::isSameValue( llvm::APSInt::getMaxValue(OtherRange.Width, OtherT->isUnsignedIntegerType()), @@ -8620,7 +8630,7 @@ llvm::Optional IsTypeLimit(Sema &S, Expr *Constant, Expr *Other, Value)) return LimitType::Min; - return llvm::Optional(); + return llvm::None; } bool HasEnumType(Expr *E) { @@ -8655,9 +8665,12 @@ bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, Expr *Constant, bool ConstIsLowerBound = (Op == BO_LT || Op == BO_LE) ^ RhsConstant; bool ResultWhenConstEqualsOther = (Op == BO_LE || Op == BO_GE); - bool ResultWhenConstNeOther = - ConstIsLowerBound ^ (ValueType == LimitType::Max); - if (ResultWhenConstEqualsOther != ResultWhenConstNeOther) + if (ValueType != LimitType::Both) { + bool ResultWhenConstNeOther = + ConstIsLowerBound ^ (ValueType == LimitType::Max); + if (ResultWhenConstEqualsOther != ResultWhenConstNeOther) + return false; // The comparison is not tautological. + } else if (ResultWhenConstEqualsOther == ConstIsLowerBound) return false; // The comparison is not tautological. const bool Result = ResultWhenConstEqualsOther; diff --git a/test/Sema/outof-range-enum-constant-compare.c b/test/Sema/outof-range-enum-constant-compare.c new file mode 100644 index 0000000000..b9ce08f68c --- /dev/null +++ b/test/Sema/outof-range-enum-constant-compare.c @@ -0,0 +1,379 @@ +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -DSILENCE -Wno-tautological-constant-out-of-range-compare -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -DSILENCE -Wno-tautological-constant-out-of-range-compare -verify %s + +int main() { + enum A { A_a = 2 }; + enum A a; + +#ifdef SILENCE + // expected-no-diagnostics +#endif + +#ifdef UNSIGNED +#ifndef SILENCE + if (a < 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (4294967296 >= a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (a > 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (4294967296 <= a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (a <= 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (4294967296 > a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (a >= 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (4294967296 < a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (a == 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (4294967296 != a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (a != 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (4294967296 == a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + + if (a < 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (4294967296U >= a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (a > 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (4294967296U <= a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (a <= 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (4294967296U > a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (a >= 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (4294967296U < a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (a == 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (4294967296U != a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (a != 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (4294967296U == a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; +#else // SILENCE + if (a < 4294967296) + return 0; + if (4294967296 >= a) + return 0; + if (a > 4294967296) + return 0; + if (4294967296 <= a) + return 0; + if (a <= 4294967296) + return 0; + if (4294967296 > a) + return 0; + if (a >= 4294967296) + return 0; + if (4294967296 < a) + return 0; + if (a == 4294967296) + return 0; + if (4294967296 != a) + return 0; + if (a != 4294967296) + return 0; + if (4294967296 == a) + return 0; + + if (a < 4294967296U) + return 0; + if (4294967296U >= a) + return 0; + if (a > 4294967296U) + return 0; + if (4294967296U <= a) + return 0; + if (a <= 4294967296U) + return 0; + if (4294967296U > a) + return 0; + if (a >= 4294967296U) + return 0; + if (4294967296U < a) + return 0; + if (a == 4294967296U) + return 0; + if (4294967296U != a) + return 0; + if (a != 4294967296U) + return 0; + if (4294967296U == a) + return 0; +#endif +#elif defined(SIGNED) +#ifndef SILENCE + if (a < -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}} + return 0; + if (-2147483649 >= a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}} + return 0; + if (a > -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}} + return 0; + if (-2147483649 <= a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}} + return 0; + if (a <= -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}} + return 0; + if (-2147483649 > a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}} + return 0; + if (a >= -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}} + return 0; + if (-2147483649 < a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}} + return 0; + if (a == -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}} + return 0; + if (-2147483649 != a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}} + return 0; + if (a != -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}} + return 0; + if (-2147483649 == a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}} + return 0; + + if (a < 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}} + return 0; + if (2147483648 >= a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}} + return 0; + if (a > 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}} + return 0; + if (2147483648 <= a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}} + return 0; + if (a <= 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}} + return 0; + if (2147483648 > a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}} + return 0; + if (a >= 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}} + return 0; + if (2147483648 < a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}} + return 0; + if (a == 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}} + return 0; + if (2147483648 != a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}} + return 0; + if (a != 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}} + return 0; + if (2147483648 == a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}} + return 0; +#else // SILENCE + if (a < -2147483649) + return 0; + if (-2147483649 >= a) + return 0; + if (a > -2147483649) + return 0; + if (-2147483649 <= a) + return 0; + if (a <= -2147483649) + return 0; + if (-2147483649 > a) + return 0; + if (a >= -2147483649) + return 0; + if (-2147483649 < a) + return 0; + if (a == -2147483649) + return 0; + if (-2147483649 != a) + return 0; + if (a != -2147483649) + return 0; + if (-2147483649 == a) + return 0; + + if (a < 2147483648) + return 0; + if (2147483648 >= a) + return 0; + if (a > 2147483648) + return 0; + if (2147483648 <= a) + return 0; + if (a <= 2147483648) + return 0; + if (2147483648 > a) + return 0; + if (a >= 2147483648) + return 0; + if (2147483648 < a) + return 0; + if (a == 2147483648) + return 0; + if (2147483648 != a) + return 0; + if (a != 2147483648) + return 0; + if (2147483648 == a) + return 0; +#endif +#endif +} + +// https://bugs.llvm.org/show_bug.cgi?id=35009 +int PR35009() { + enum A { A_a = 2 }; + enum A a; + + // in C, this should not warn. + + if (a < 1) + return 0; + if (1 >= a) + return 0; + if (a > 1) + return 0; + if (1 <= a) + return 0; + if (a <= 1) + return 0; + if (1 > a) + return 0; + if (a >= 1) + return 0; + if (1 < a) + return 0; + if (a == 1) + return 0; + if (1 != a) + return 0; + if (a != 1) + return 0; + if (1 == a) + return 0; + + if (a < 1U) + return 0; + if (1U >= a) + return 0; + if (a > 1U) + return 0; + if (1U <= a) + return 0; + if (a <= 1U) + return 0; + if (1U > a) + return 0; + if (a >= 1U) + return 0; + if (1U < a) + return 0; + if (a == 1U) + return 0; + if (1U != a) + return 0; + if (a != 1U) + return 0; + if (1U == a) + return 0; + + if (a < 2) + return 0; + if (2 >= a) + return 0; + if (a > 2) + return 0; + if (2 <= a) + return 0; + if (a <= 2) + return 0; + if (2 > a) + return 0; + if (a >= 2) + return 0; + if (2 < a) + return 0; + if (a == 2) + return 0; + if (2 != a) + return 0; + if (a != 2) + return 0; + if (2 == a) + return 0; + + if (a < 2U) + return 0; + if (2U >= a) + return 0; + if (a > 2U) + return 0; + if (2U <= a) + return 0; + if (a <= 2U) + return 0; + if (2U > a) + return 0; + if (a >= 2U) + return 0; + if (2U < a) + return 0; + if (a == 2U) + return 0; + if (2U != a) + return 0; + if (a != 2U) + return 0; + if (2U == a) + return 0; + + if (a < 3) + return 0; + if (3 >= a) + return 0; + if (a > 3) + return 0; + if (3 <= a) + return 0; + if (a <= 3) + return 0; + if (3 > a) + return 0; + if (a >= 3) + return 0; + if (3 < a) + return 0; + if (a == 3) + return 0; + if (3 != a) + return 0; + if (a != 3) + return 0; + if (3 == a) + return 0; + + if (a < 3U) + return 0; + if (3U >= a) + return 0; + if (a > 3U) + return 0; + if (3U <= a) + return 0; + if (a <= 3U) + return 0; + if (3U > a) + return 0; + if (a >= 3U) + return 0; + if (3U < a) + return 0; + if (a == 3U) + return 0; + if (3U != a) + return 0; + if (a != 3U) + return 0; + if (3U == a) + return 0; + + return 1; +} diff --git a/test/Sema/tautological-constant-enum-compare.c b/test/Sema/tautological-constant-enum-compare.c new file mode 100644 index 0000000000..1f09865f13 --- /dev/null +++ b/test/Sema/tautological-constant-enum-compare.c @@ -0,0 +1,419 @@ +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -DSILENCE -Wno-tautological-constant-compare -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -DSILENCE -Wno-tautological-constant-compare -verify %s + +int main() { + enum A { A_a = 2 }; + enum A a; + +#ifdef SILENCE + // expected-no-diagnostics +#endif + +#ifdef UNSIGNED +#ifndef SILENCE + if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} + return 0; + if (0 >= a) + return 0; + if (a > 0) + return 0; + if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} + return 0; + if (a <= 0) + return 0; + if (0 > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + return 0; + if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0 < a) + return 0; + + if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} + return 0; + if (0U >= a) + return 0; + if (a > 0U) + return 0; + if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} + return 0; + if (a <= 0U) + return 0; + if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + return 0; + if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < a) + return 0; + + if (a < 4294967295) + return 0; + if (4294967295 >= a) // expected-warning {{comparison 4294967295 >= 'enum A' is always true}} + return 0; + if (a > 4294967295) // expected-warning {{comparison 'enum A' > 4294967295 is always false}} + return 0; + if (4294967295 <= a) + return 0; + if (a <= 4294967295) // expected-warning {{comparison 'enum A' <= 4294967295 is always true}} + return 0; + if (4294967295 > a) + return 0; + if (a >= 4294967295) + return 0; + if (4294967295 < a) // expected-warning {{comparison 4294967295 < 'enum A' is always false}} + return 0; + + if (a < 4294967295U) + return 0; + if (4294967295U >= a) // expected-warning {{comparison 4294967295 >= 'enum A' is always true}} + return 0; + if (a > 4294967295U) // expected-warning {{comparison 'enum A' > 4294967295 is always false}} + return 0; + if (4294967295U <= a) + return 0; + if (a <= 4294967295U) // expected-warning {{comparison 'enum A' <= 4294967295 is always true}} + return 0; + if (4294967295U > a) + return 0; + if (a >= 4294967295U) + return 0; + if (4294967295U < a) // expected-warning {{comparison 4294967295 < 'enum A' is always false}} + return 0; +#else // SILENCE + if (a < 0) + return 0; + if (0 >= a) + return 0; + if (a > 0) + return 0; + if (0 <= a) + return 0; + if (a <= 0) + return 0; + if (0 > a) + return 0; + if (a >= 0) + return 0; + if (0 < a) + return 0; + + if (a < 0U) + return 0; + if (0U >= a) + return 0; + if (a > 0U) + return 0; + if (0U <= a) + return 0; + if (a <= 0U) + return 0; + if (0U > a) + return 0; + if (a >= 0U) + return 0; + if (0U < a) + return 0; + + if (a < 4294967295) + return 0; + if (4294967295 >= a) + return 0; + if (a > 4294967295) + return 0; + if (4294967295 <= a) + return 0; + if (a <= 4294967295) + return 0; + if (4294967295 > a) + return 0; + if (a >= 4294967295) + return 0; + if (4294967295 < a) + return 0; + + if (a < 4294967295U) + return 0; + if (4294967295U >= a) + return 0; + if (a > 4294967295U) + return 0; + if (4294967295U <= a) + return 0; + if (a <= 4294967295U) + return 0; + if (4294967295U > a) + return 0; + if (a >= 4294967295U) + return 0; + if (4294967295U < a) + return 0; +#endif +#elif defined(SIGNED) +#ifndef SILENCE + if (a < -2147483648) // expected-warning {{comparison 'enum A' < -2147483648 is always false}} + return 0; + if (-2147483648 >= a) + return 0; + if (a > -2147483648) + return 0; + if (-2147483648 <= a) // expected-warning {{comparison -2147483648 <= 'enum A' is always true}} + return 0; + if (a <= -2147483648) + return 0; + if (-2147483648 > a) // expected-warning {{comparison -2147483648 > 'enum A' is always false}} + return 0; + if (a >= -2147483648) // expected-warning {{comparison 'enum A' >= -2147483648 is always true}} + return 0; + if (-2147483648 < a) + return 0; + + if (a < 2147483647) + return 0; + if (2147483647 >= a) // expected-warning {{comparison 2147483647 >= 'enum A' is always true}} + return 0; + if (a > 2147483647) // expected-warning {{comparison 'enum A' > 2147483647 is always false}} + return 0; + if (2147483647 <= a) + return 0; + if (a <= 2147483647) // expected-warning {{comparison 'enum A' <= 2147483647 is always true}} + return 0; + if (2147483647 > a) + return 0; + if (a >= 2147483647) + return 0; + if (2147483647 < a) // expected-warning {{comparison 2147483647 < 'enum A' is always false}} + return 0; + + if (a < 2147483647U) + return 0; + if (2147483647U >= a) // expected-warning {{comparison 2147483647 >= 'enum A' is always true}} + return 0; + if (a > 2147483647U) // expected-warning {{comparison 'enum A' > 2147483647 is always false}} + return 0; + if (2147483647U <= a) + return 0; + if (a <= 2147483647U) // expected-warning {{comparison 'enum A' <= 2147483647 is always true}} + return 0; + if (2147483647U > a) + return 0; + if (a >= 2147483647U) + return 0; + if (2147483647U < a) // expected-warning {{comparison 2147483647 < 'enum A' is always false}} + return 0; +#else // SILENCE + if (a < -2147483648) + return 0; + if (-2147483648 >= a) + return 0; + if (a > -2147483648) + return 0; + if (-2147483648 <= a) + return 0; + if (a <= -2147483648) + return 0; + if (-2147483648 > a) + return 0; + if (a >= -2147483648) + return 0; + if (-2147483648 < a) + return 0; + + if (a < 2147483647) + return 0; + if (2147483647 >= a) + return 0; + if (a > 2147483647) + return 0; + if (2147483647 <= a) + return 0; + if (a <= 2147483647) + return 0; + if (2147483647 > a) + return 0; + if (a >= 2147483647) + return 0; + if (2147483647 < a) + return 0; + + if (a < 2147483647U) + return 0; + if (2147483647U >= a) + return 0; + if (a > 2147483647U) + return 0; + if (2147483647U <= a) + return 0; + if (a <= 2147483647U) + return 0; + if (2147483647U > a) + return 0; + if (a >= 2147483647U) + return 0; + if (2147483647U < a) + return 0; +#endif +#endif + + return 1; +} + +// https://bugs.llvm.org/show_bug.cgi?id=35009 +int PR35009() { + enum A { A_a = 2 }; + enum A a; + + // in C, this should not warn. + + if (a < 1) + return 0; + if (1 >= a) + return 0; + if (a > 1) + return 0; + if (1 <= a) + return 0; + if (a <= 1) + return 0; + if (1 > a) + return 0; + if (a >= 1) + return 0; + if (1 < a) + return 0; + if (a == 1) + return 0; + if (1 != a) + return 0; + if (a != 1) + return 0; + if (1 == a) + return 0; + + if (a < 1U) + return 0; + if (1U >= a) + return 0; + if (a > 1U) + return 0; + if (1U <= a) + return 0; + if (a <= 1U) + return 0; + if (1U > a) + return 0; + if (a >= 1U) + return 0; + if (1U < a) + return 0; + if (a == 1U) + return 0; + if (1U != a) + return 0; + if (a != 1U) + return 0; + if (1U == a) + return 0; + + if (a < 2) + return 0; + if (2 >= a) + return 0; + if (a > 2) + return 0; + if (2 <= a) + return 0; + if (a <= 2) + return 0; + if (2 > a) + return 0; + if (a >= 2) + return 0; + if (2 < a) + return 0; + if (a == 2) + return 0; + if (2 != a) + return 0; + if (a != 2) + return 0; + if (2 == a) + return 0; + + if (a < 2U) + return 0; + if (2U >= a) + return 0; + if (a > 2U) + return 0; + if (2U <= a) + return 0; + if (a <= 2U) + return 0; + if (2U > a) + return 0; + if (a >= 2U) + return 0; + if (2U < a) + return 0; + if (a == 2U) + return 0; + if (2U != a) + return 0; + if (a != 2U) + return 0; + if (2U == a) + return 0; + + if (a < 3) + return 0; + if (3 >= a) + return 0; + if (a > 3) + return 0; + if (3 <= a) + return 0; + if (a <= 3) + return 0; + if (3 > a) + return 0; + if (a >= 3) + return 0; + if (3 < a) + return 0; + if (a == 3) + return 0; + if (3 != a) + return 0; + if (a != 3) + return 0; + if (3 == a) + return 0; + + if (a < 3U) + return 0; + if (3U >= a) + return 0; + if (a > 3U) + return 0; + if (3U <= a) + return 0; + if (a <= 3U) + return 0; + if (3U > a) + return 0; + if (a >= 3U) + return 0; + if (3U < a) + return 0; + if (a == 3U) + return 0; + if (3U != a) + return 0; + if (a != 3U) + return 0; + if (3U == a) + return 0; + + return 1; +} diff --git a/test/Sema/tautological-unsigned-enum-zero-compare.c b/test/Sema/tautological-unsigned-enum-zero-compare.c index 49982a9fd7..43b768433d 100644 --- a/test/Sema/tautological-unsigned-enum-zero-compare.c +++ b/test/Sema/tautological-unsigned-enum-zero-compare.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DALL_WARN -verify %s -// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGN_WARN -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s // RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -Wno-tautological-unsigned-enum-zero-compare -verify %s // Okay, this is where it gets complicated. @@ -7,62 +7,254 @@ // On windows, it is signed by default. We do not want to warn in that case. int main() { - enum A { A_foo, A_bar }; + enum A { A_a = 0 }; enum A a; + enum B { B_a = -1 }; + enum B b; -#ifdef ALL_WARN +#ifdef UNSIGNED if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0 >= a) + return 0; + if (a > 0) return 0; if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (a <= 0) + return 0; if (0 > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; + if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0 < a) + return 0; + if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0U >= a) + return 0; + if (a > 0U) return 0; if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (a <= 0U) + return 0; if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; -#elif defined(SIGN_WARN) - if (a < 0) // ok + if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < a) + return 0; + + if (b < 0) + return 0; + if (0 >= b) + return 0; + if (b > 0) + return 0; + if (0 <= b) + return 0; + if (b <= 0) + return 0; + if (0 > b) + return 0; + if (b >= 0) + return 0; + if (0 < b) + return 0; + + if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} + return 0; + if (0U >= b) + return 0; + if (b > 0U) + return 0; + if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} + return 0; + if (b <= 0U) + return 0; + if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + return 0; + if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} return 0; - if (a >= 0) // ok + if (0U < b) return 0; - if (0 <= a) // ok +#elif defined(SIGNED) + if (a < 0) + return 0; + if (0 >= a) + return 0; + if (a > 0) + return 0; + if (0 <= a) + return 0; + if (a <= 0) return 0; - if (0 > a) // ok + if (0 > a) return 0; + if (a >= 0) + return 0; + if (0 < a) + return 0; + if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0U >= a) + return 0; + if (a > 0U) return 0; if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (a <= 0U) + return 0; if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; + if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < a) + return 0; + + if (b < 0) + return 0; + if (0 >= b) + return 0; + if (b > 0) + return 0; + if (0 <= b) + return 0; + if (b <= 0) + return 0; + if (0 > b) + return 0; + if (b >= 0) + return 0; + if (0 < b) + return 0; + + if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} + return 0; + if (0U >= b) + return 0; + if (b > 0U) + return 0; + if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} + return 0; + if (b <= 0U) + return 0; + if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + return 0; + if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < b) + return 0; #else // expected-no-diagnostics + if (a < 0) return 0; - if (a >= 0) + if (0 >= a) + return 0; + if (a > 0) return 0; if (0 <= a) return 0; + if (a <= 0) + return 0; if (0 > a) return 0; + if (a >= 0) + return 0; + if (0 < a) + return 0; + if (a < 0U) return 0; - if (a >= 0U) + if (0U >= a) + return 0; + if (a > 0U) return 0; if (0U <= a) return 0; + if (a <= 0U) + return 0; if (0U > a) return 0; + if (a >= 0U) + return 0; + if (0U < a) + return 0; + + if (b < 0) + return 0; + if (0 >= b) + return 0; + if (b > 0) + return 0; + if (0 <= b) + return 0; + if (b <= 0) + return 0; + if (0 > b) + return 0; + if (b >= 0) + return 0; + if (0 < b) + return 0; + + if (b < 0U) + return 0; + if (0U >= b) + return 0; + if (b > 0U) + return 0; + if (0U <= b) + return 0; + if (b <= 0U) + return 0; + if (0U > b) + return 0; + if (b >= 0U) + return 0; + if (0U < b) + return 0; #endif + if (a == 0) + return 0; + if (0 != a) + return 0; + if (a != 0) + return 0; + if (0 == a) + return 0; + + if (a == 0U) + return 0; + if (0U != a) + return 0; + if (a != 0U) + return 0; + if (0U == a) + return 0; + + if (b == 0) + return 0; + if (0 != b) + return 0; + if (b != 0) + return 0; + if (0 == b) + return 0; + + if (b == 0U) + return 0; + if (0U != b) + return 0; + if (b != 0U) + return 0; + if (0U == b) + return 0; + return 1; } diff --git a/test/Sema/tautological-unsigned-enum-zero-compare.cpp b/test/Sema/tautological-unsigned-enum-zero-compare.cpp index 3e78626745..f8d4560ef2 100644 --- a/test/Sema/tautological-unsigned-enum-zero-compare.cpp +++ b/test/Sema/tautological-unsigned-enum-zero-compare.cpp @@ -1,176 +1,347 @@ -// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-linux-gnu -fsyntax-only -DALL_WARN -verify %s -// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only -DSIGN_WARN -verify %s -// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only -Wno-tautological-unsigned-enum-zero-compare -verify %s +// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s +// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s +// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only -DSILENCE -Wno-tautological-unsigned-enum-zero-compare -verify %s // Okay, this is where it gets complicated. // Then default enum sigdness is target-specific. // On windows, it is signed by default. We do not want to warn in that case. int main() { - enum A { A_foo, A_bar }; + enum A { A_foo = 0, A_bar, }; enum A a; - enum B : unsigned { B_foo, B_bar }; + enum B : unsigned { B_foo = 0, B_bar, }; enum B b; - enum C : signed { c_foo, c_bar }; + enum C : signed { C_foo = 0, C_bar, }; enum C c; -#ifdef ALL_WARN +#ifdef UNSIGNED if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0 >= a) + return 0; + if (a > 0) return 0; if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (a <= 0) + return 0; if (0 > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; + if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0 < a) + return 0; + if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0U >= a) + return 0; + if (a > 0U) return 0; if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (a <= 0U) + return 0; if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; + if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < a) + return 0; if (b < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (b >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0 >= b) + return 0; + if (b > 0) return 0; if (0 <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (b <= 0) + return 0; if (0 > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; + if (b >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0 < b) + return 0; + if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0U >= b) + return 0; + if (b > 0U) return 0; if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (b <= 0U) + return 0; if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; + if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < b) + return 0; - if (c < 0) // ok + if (c < 0) + return 0; + if (0 >= c) // expected-warning {{comparison 0 >= 'enum C' is always true}} + return 0; + if (c > 0) // expected-warning {{comparison 'enum C' > 0 is always false}} + return 0; + if (0 <= c) + return 0; + if (c <= 0) // expected-warning {{comparison 'enum C' <= 0 is always true}} return 0; - if (c >= 0) // ok + if (0 > c) return 0; - if (0 <= c) // ok + if (c >= 0) return 0; - if (0 > c) // ok + if (0 < c) // expected-warning {{0 < 'enum C' is always false}} return 0; + if (c < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0U >= c) + return 0; + if (c > 0U) return 0; if (0U <= c) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (c <= 0U) + return 0; if (0U > c) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; -#elif defined(SIGN_WARN) - if (a < 0) // ok + if (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} return 0; - if (a >= 0) // ok + if (0U < c) return 0; - if (0 <= a) // ok +#elif defined(SIGNED) + if (a < 0) + return 0; + if (0 >= a) // expected-warning {{comparison 0 >= 'enum A' is always true}} return 0; - if (0 > a) // ok + if (a > 0) // expected-warning {{comparison 'enum A' > 0 is always false}} + return 0; + if (0 <= a) return 0; + if (a <= 0) // expected-warning {{comparison 'enum A' <= 0 is always true}} + return 0; + if (0 > a) + return 0; + if (a >= 0) + return 0; + if (0 < a) // expected-warning {{comparison 0 < 'enum A' is always false}} + return 0; + if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0U >= a) + return 0; + if (a > 0U) return 0; if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (a <= 0U) + return 0; if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; + if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < a) + return 0; if (b < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (b >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0 >= b) + return 0; + if (b > 0) return 0; if (0 <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (b <= 0) + return 0; if (0 > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; + if (b >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0 < b) + return 0; + if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0U >= b) + return 0; + if (b > 0U) return 0; if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (b <= 0U) + return 0; if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; + if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < b) + return 0; - if (c < 0) // ok + if (c < 0) return 0; - if (c >= 0) // ok + if (0 >= c) // expected-warning {{comparison 0 >= 'enum C' is always true}} return 0; - if (0 <= c) // ok + if (c > 0) // expected-warning {{comparison 'enum C' > 0 is always false}} + return 0; + if (0 <= c) return 0; - if (0 > c) // ok + if (c <= 0) // expected-warning {{comparison 'enum C' <= 0 is always true}} + return 0; + if (0 > c) + return 0; + if (c >= 0) return 0; + if (0 < c) // expected-warning {{0 < 'enum C' is always false}} + return 0; + if (c < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0U >= c) + return 0; + if (c > 0U) return 0; if (0U <= c) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (c <= 0U) + return 0; if (0U > c) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; + if (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < c) + return 0; #else - // expected-no-diagnostics if (a < 0) return 0; - if (a >= 0) + if (0 >= a) // expected-warning {{comparison 0 >= 'enum A' is always true}} + return 0; + if (a > 0) // expected-warning {{comparison 'enum A' > 0 is always false}} return 0; if (0 <= a) return 0; + if (a <= 0) // expected-warning {{comparison 'enum A' <= 0 is always true}} + return 0; if (0 > a) return 0; + if (a >= 0) + return 0; + if (0 < a) // expected-warning {{comparison 0 < 'enum A' is always false}} + return 0; + if (a < 0U) return 0; - if (a >= 0U) + if (0U >= a) + return 0; + if (a > 0U) return 0; if (0U <= a) return 0; + if (a <= 0U) + return 0; if (0U > a) return 0; + if (a >= 0U) + return 0; + if (0U < a) + return 0; if (b < 0) return 0; - if (b >= 0) + if (0 >= b) + return 0; + if (b > 0) return 0; if (0 <= b) return 0; + if (b <= 0) + return 0; if (0 > b) return 0; + if (b >= 0) + return 0; + if (0 < b) + return 0; + if (b < 0U) return 0; - if (b >= 0U) + if (0U >= b) + return 0; + if (b > 0U) return 0; if (0U <= b) return 0; + if (b <= 0U) + return 0; if (0U > b) return 0; + if (b >= 0U) + return 0; + if (0U < b) + return 0; if (c < 0) return 0; - if (c >= 0) + if (0 >= c) // expected-warning {{comparison 0 >= 'enum C' is always true}} + return 0; + if (c > 0) // expected-warning {{comparison 'enum C' > 0 is always false}} return 0; if (0 <= c) return 0; + if (c <= 0) // expected-warning {{comparison 'enum C' <= 0 is always true}} + return 0; if (0 > c) return 0; + if (c >= 0) + return 0; + if (0 < c) // expected-warning {{0 < 'enum C' is always false}} + return 0; + if (c < 0U) return 0; - if (c >= 0U) + if (0U >= c) + return 0; + if (c > 0U) return 0; if (0U <= c) return 0; + if (c <= 0U) + return 0; if (0U > c) return 0; + if (c >= 0U) + return 0; + if (0U < c) + return 0; +#endif + + return 1; +} + +namespace crash_enum_zero_width { +int test() { + enum A : unsigned { + A_foo = 0 + }; + enum A a; + + // used to crash in llvm::APSInt::getMaxValue() +#ifndef SILENCE + if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} +#else + if (a > 0) #endif + return 0; return 1; } +} // namespace crash_enum_zero_width -- GitLab From caef7029e6dd8cfb6e92aaf2fa88ca154e0255a8 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Sat, 21 Oct 2017 16:45:08 +0000 Subject: [PATCH 0014/1682] Add release notes for the recent -fdouble-square-bracket-attributes and -fno-double-square-bracket-attributes compiler flags. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316269 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/ReleaseNotes.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst index 293144a832..698672e479 100644 --- a/docs/ReleaseNotes.rst +++ b/docs/ReleaseNotes.rst @@ -103,6 +103,13 @@ New Compiler Flags - --autocomplete was implemented to obtain a list of flags and its arguments. This is used for shell autocompletion. +- The ``-fdouble-square-bracket-attributes`` and corresponding + ``-fno-double-square-bracket-attributes`` flags were added to enable or + disable [[]] attributes in any language mode. Currently, only a limited + number of attributes are supported outside of C++ mode. See the Clang + attribute documentation for more information about which attributes are + supported for each syntax. + Deprecated Compiler Flags ------------------------- -- GitLab From 59611f54fa88ba639661d2e0e2e8b607bd48d4a7 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Sat, 21 Oct 2017 20:28:58 +0000 Subject: [PATCH 0015/1682] Fix a typo with -fno-double-square-bracket-attributes and add a test to demonstrate that it works as expected in C++11 mode. Additionally corrected the handling of -fdouble-square-bracket-attributes to be properly passed down to the cc1 option. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316275 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Driver/Options.td | 4 ++-- lib/Driver/ToolChains/Clang.cpp | 3 +++ test/SemaCXX/attr-cxx-disabled.cpp | 12 ++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 test/SemaCXX/attr-cxx-disabled.cpp diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 526b72f792..9f61521408 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -613,8 +613,8 @@ def fasynchronous_unwind_tables : Flag<["-"], "fasynchronous-unwind-tables">, Gr def fdouble_square_bracket_attributes : Flag<[ "-" ], "fdouble-square-bracket-attributes">, Group, Flags<[DriverOption, CC1Option]>, HelpText<"Enable '[[]]' attributes in all C and C++ language modes">; -def fno_double_square_bracket_attributes : Flag<[ "-" ], "fno-fdouble-square-bracket-attributes">, - Group, Flags<[DriverOption]>, +def fno_double_square_bracket_attributes : Flag<[ "-" ], "fno-double-square-bracket-attributes">, + Group, Flags<[DriverOption, CC1Option]>, HelpText<"Disable '[[]]' attributes in all C and C++ language modes">; def fautolink : Flag <["-"], "fautolink">, Group; diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index 8e5f3b9573..adaf39abc5 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -4010,6 +4010,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fcoroutines-ts"); } + Args.AddLastArg(CmdArgs, options::OPT_fdouble_square_bracket_attributes, + options::OPT_fno_double_square_bracket_attributes); + bool HaveModules = false; RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules); diff --git a/test/SemaCXX/attr-cxx-disabled.cpp b/test/SemaCXX/attr-cxx-disabled.cpp new file mode 100644 index 0000000000..a1a7533bd8 --- /dev/null +++ b/test/SemaCXX/attr-cxx-disabled.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -fsyntax-only -fno-double-square-bracket-attributes -verify -pedantic -std=c++11 -DERRORS %s +// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify -pedantic -std=c++11 %s + +struct [[]] S {}; + +#ifdef ERRORS +// expected-error@-3 {{declaration of anonymous struct must be a definition}} +// expected-warning@-4 {{declaration does not declare anything}} +#else +// expected-no-diagnostics +#endif + -- GitLab From d02b8c6579d1e6a51f6c5c289943ecba97e1a1f9 Mon Sep 17 00:00:00 2001 From: Masud Rahman Date: Sat, 21 Oct 2017 20:53:49 +0000 Subject: [PATCH 0016/1682] [libclang, bindings]: add spelling location o) Add a 'Location' class that represents the four properties of a physical location o) Enhance 'SourceLocation' to provide 'expansion' and 'spelling' locations, maintaining backwards compatibility with existing code by forwarding the four properties to 'expansion'. o) Update the implementation to use 'clang_getExpansionLocation' instead of the deprecated 'clang_getInstantiationLocation', which has been present since 2011. o) Update the implementation of 'clang_getSpellingLocation' to actually obtain spelling location instead of file location. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316278 91177308-0d34-0410-b5e6-96231b3b80d8 --- bindings/python/clang/cindex.py | 120 ++++++++++++++---- bindings/python/tests/cindex/test_location.py | 7 + tools/libclang/CXSourceLocation.cpp | 3 +- 3 files changed, 104 insertions(+), 26 deletions(-) diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py index d72dd14ef9..3f70bba493 100644 --- a/bindings/python/clang/cindex.py +++ b/bindings/python/clang/cindex.py @@ -214,25 +214,45 @@ class _CXString(Structure): assert isinstance(res, _CXString) return conf.lib.clang_getCString(res) +class Location(object): + """A Location is a specific kind of source location. A SourceLocation + refers to several kinds of locations (e.g. spelling location vs. expansion + location).""" + + def __init__(self, file, line, column, offset): + self._file = File(file) if file else None + self._line = int(line.value) + self._column = int(column.value) + self._offset = int(offset.value) + + + @property + def file(self): + """Get the file represented by this source location.""" + return self._file + + @property + def line(self): + """Get the line represented by this source location.""" + return self._line + + @property + def column(self): + """Get the column represented by this source location.""" + return self._column + + @property + def offset(self): + """Get the file offset represented by this source location.""" + return self._offset class SourceLocation(Structure): """ A SourceLocation represents a particular location within a source file. """ _fields_ = [("ptr_data", c_void_p * 2), ("int_data", c_uint)] - _data = None - - def _get_instantiation(self): - if self._data is None: - f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint() - conf.lib.clang_getInstantiationLocation(self, byref(f), byref(l), - byref(c), byref(o)) - if f: - f = File(f) - else: - f = None - self._data = (f, int(l.value), int(c.value), int(o.value)) - return self._data + _expansion = None + _spelling = None @staticmethod def from_position(tu, file, line, column): @@ -252,25 +272,73 @@ class SourceLocation(Structure): """ return conf.lib.clang_getLocationForOffset(tu, file, offset) + @property + def expansion(self): + """ + The source location where then entity this object is referring to is + expanded. + """ + if not self._expansion: + file = c_object_p() + line = c_uint() + column = c_uint() + offset = c_uint() + conf.lib.clang_getExpansionLocation(self, + byref(file), + byref(line), + byref(column), + byref(offset)) + + self._expansion = Location(file, line, column, offset) + return self._expansion + + @property + def spelling(self): + """ + The source location where then entity this object is referring to is + written. + """ + if not self._spelling: + file = c_object_p() + line = c_uint() + column = c_uint() + offset = c_uint() + conf.lib.clang_getSpellingLocation(self, + byref(file), + byref(line), + byref(column), + byref(offset)) + + self._spelling = Location(file, line, column, offset) + return self._spelling + @property def file(self): - """Get the file represented by this source location.""" - return self._get_instantiation()[0] + """Get the file represented by this source location. + + DEPRECATED: use expansion.file.""" + return self.expansion.file @property def line(self): - """Get the line represented by this source location.""" - return self._get_instantiation()[1] + """Get the line represented by this source location. + + DEPRECATED: use expansion.line.""" + return self.expansion.line @property def column(self): - """Get the column represented by this source location.""" - return self._get_instantiation()[2] + """Get the column represented by this source location. + + DEPRECATED: use expansion.column.""" + return self.expansion.column @property def offset(self): - """Get the file offset represented by this source location.""" - return self._get_instantiation()[3] + """Get the file offset represented by this source location. + + DEPRECATED: use expansion.offset.""" + return self.expansion.offset def __eq__(self, other): return conf.lib.clang_equalLocations(self, other) @@ -1543,8 +1611,7 @@ class Cursor(Structure): @property def location(self): """ - Return the source location (the starting character) of the entity - pointed at by the cursor. + Return the source locations of the entity pointed at by the cursor. """ if not hasattr(self, '_loc'): self._loc = conf.lib.clang_getCursorLocation(self) @@ -3692,7 +3759,11 @@ functionList = [ ("clang_getInclusions", [TranslationUnit, callbacks['translation_unit_includes'], py_object]), - ("clang_getInstantiationLocation", + ("clang_getExpansionLocation", + [SourceLocation, POINTER(c_object_p), POINTER(c_uint), POINTER(c_uint), + POINTER(c_uint)]), + + ("clang_getSpellingLocation", [SourceLocation, POINTER(c_object_p), POINTER(c_uint), POINTER(c_uint), POINTER(c_uint)]), @@ -4154,6 +4225,7 @@ __all__ = [ 'FixIt', 'Index', 'LinkageKind', + 'Location', 'SourceLocation', 'SourceRange', 'TLSKind', diff --git a/bindings/python/tests/cindex/test_location.py b/bindings/python/tests/cindex/test_location.py index 9e9ef487af..d6875330ec 100644 --- a/bindings/python/tests/cindex/test_location.py +++ b/bindings/python/tests/cindex/test_location.py @@ -93,3 +93,10 @@ def test_extent(): location3 = SourceLocation.from_position(tu, file, 1, 6) range3 = SourceRange.from_locations(location1, location3) assert range1 != range3 + +def test_spelling_location(): + tu = get_tu('''#define ONE int one +ONE;''') + one = get_cursor(tu, 'one') + assert one.location.spelling.line == 1 + assert one.location.expansion.line == 2 diff --git a/tools/libclang/CXSourceLocation.cpp b/tools/libclang/CXSourceLocation.cpp index 2e0ea4e440..b1637e01ab 100644 --- a/tools/libclang/CXSourceLocation.cpp +++ b/tools/libclang/CXSourceLocation.cpp @@ -318,8 +318,7 @@ void clang_getSpellingLocation(CXSourceLocation location, const SourceManager &SM = *static_cast(location.ptr_data[0]); - // FIXME: This should call SourceManager::getSpellingLoc(). - SourceLocation SpellLoc = SM.getFileLoc(Loc); + SourceLocation SpellLoc = SM.getSpellingLoc(Loc); std::pair LocInfo = SM.getDecomposedLoc(SpellLoc); FileID FID = LocInfo.first; unsigned FileOffset = LocInfo.second; -- GitLab From b99743553a954ef2e92d143890fe987500088ff8 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Sat, 21 Oct 2017 21:52:48 +0000 Subject: [PATCH 0017/1682] Reverting r316278 due to failing build bots. http://lab.llvm.org:8011/builders/clang-ppc64be-linux/builds/11896 http://lab.llvm.org:8011/builders/clang-s390x-linux/builds/12380 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316279 91177308-0d34-0410-b5e6-96231b3b80d8 --- bindings/python/clang/cindex.py | 120 ++++-------------- bindings/python/tests/cindex/test_location.py | 7 - tools/libclang/CXSourceLocation.cpp | 3 +- 3 files changed, 26 insertions(+), 104 deletions(-) diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py index 3f70bba493..d72dd14ef9 100644 --- a/bindings/python/clang/cindex.py +++ b/bindings/python/clang/cindex.py @@ -214,45 +214,25 @@ class _CXString(Structure): assert isinstance(res, _CXString) return conf.lib.clang_getCString(res) -class Location(object): - """A Location is a specific kind of source location. A SourceLocation - refers to several kinds of locations (e.g. spelling location vs. expansion - location).""" - - def __init__(self, file, line, column, offset): - self._file = File(file) if file else None - self._line = int(line.value) - self._column = int(column.value) - self._offset = int(offset.value) - - - @property - def file(self): - """Get the file represented by this source location.""" - return self._file - - @property - def line(self): - """Get the line represented by this source location.""" - return self._line - - @property - def column(self): - """Get the column represented by this source location.""" - return self._column - - @property - def offset(self): - """Get the file offset represented by this source location.""" - return self._offset class SourceLocation(Structure): """ A SourceLocation represents a particular location within a source file. """ _fields_ = [("ptr_data", c_void_p * 2), ("int_data", c_uint)] - _expansion = None - _spelling = None + _data = None + + def _get_instantiation(self): + if self._data is None: + f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint() + conf.lib.clang_getInstantiationLocation(self, byref(f), byref(l), + byref(c), byref(o)) + if f: + f = File(f) + else: + f = None + self._data = (f, int(l.value), int(c.value), int(o.value)) + return self._data @staticmethod def from_position(tu, file, line, column): @@ -272,73 +252,25 @@ class SourceLocation(Structure): """ return conf.lib.clang_getLocationForOffset(tu, file, offset) - @property - def expansion(self): - """ - The source location where then entity this object is referring to is - expanded. - """ - if not self._expansion: - file = c_object_p() - line = c_uint() - column = c_uint() - offset = c_uint() - conf.lib.clang_getExpansionLocation(self, - byref(file), - byref(line), - byref(column), - byref(offset)) - - self._expansion = Location(file, line, column, offset) - return self._expansion - - @property - def spelling(self): - """ - The source location where then entity this object is referring to is - written. - """ - if not self._spelling: - file = c_object_p() - line = c_uint() - column = c_uint() - offset = c_uint() - conf.lib.clang_getSpellingLocation(self, - byref(file), - byref(line), - byref(column), - byref(offset)) - - self._spelling = Location(file, line, column, offset) - return self._spelling - @property def file(self): - """Get the file represented by this source location. - - DEPRECATED: use expansion.file.""" - return self.expansion.file + """Get the file represented by this source location.""" + return self._get_instantiation()[0] @property def line(self): - """Get the line represented by this source location. - - DEPRECATED: use expansion.line.""" - return self.expansion.line + """Get the line represented by this source location.""" + return self._get_instantiation()[1] @property def column(self): - """Get the column represented by this source location. - - DEPRECATED: use expansion.column.""" - return self.expansion.column + """Get the column represented by this source location.""" + return self._get_instantiation()[2] @property def offset(self): - """Get the file offset represented by this source location. - - DEPRECATED: use expansion.offset.""" - return self.expansion.offset + """Get the file offset represented by this source location.""" + return self._get_instantiation()[3] def __eq__(self, other): return conf.lib.clang_equalLocations(self, other) @@ -1611,7 +1543,8 @@ class Cursor(Structure): @property def location(self): """ - Return the source locations of the entity pointed at by the cursor. + Return the source location (the starting character) of the entity + pointed at by the cursor. """ if not hasattr(self, '_loc'): self._loc = conf.lib.clang_getCursorLocation(self) @@ -3759,11 +3692,7 @@ functionList = [ ("clang_getInclusions", [TranslationUnit, callbacks['translation_unit_includes'], py_object]), - ("clang_getExpansionLocation", - [SourceLocation, POINTER(c_object_p), POINTER(c_uint), POINTER(c_uint), - POINTER(c_uint)]), - - ("clang_getSpellingLocation", + ("clang_getInstantiationLocation", [SourceLocation, POINTER(c_object_p), POINTER(c_uint), POINTER(c_uint), POINTER(c_uint)]), @@ -4225,7 +4154,6 @@ __all__ = [ 'FixIt', 'Index', 'LinkageKind', - 'Location', 'SourceLocation', 'SourceRange', 'TLSKind', diff --git a/bindings/python/tests/cindex/test_location.py b/bindings/python/tests/cindex/test_location.py index d6875330ec..9e9ef487af 100644 --- a/bindings/python/tests/cindex/test_location.py +++ b/bindings/python/tests/cindex/test_location.py @@ -93,10 +93,3 @@ def test_extent(): location3 = SourceLocation.from_position(tu, file, 1, 6) range3 = SourceRange.from_locations(location1, location3) assert range1 != range3 - -def test_spelling_location(): - tu = get_tu('''#define ONE int one -ONE;''') - one = get_cursor(tu, 'one') - assert one.location.spelling.line == 1 - assert one.location.expansion.line == 2 diff --git a/tools/libclang/CXSourceLocation.cpp b/tools/libclang/CXSourceLocation.cpp index b1637e01ab..2e0ea4e440 100644 --- a/tools/libclang/CXSourceLocation.cpp +++ b/tools/libclang/CXSourceLocation.cpp @@ -318,7 +318,8 @@ void clang_getSpellingLocation(CXSourceLocation location, const SourceManager &SM = *static_cast(location.ptr_data[0]); - SourceLocation SpellLoc = SM.getSpellingLoc(Loc); + // FIXME: This should call SourceManager::getSpellingLoc(). + SourceLocation SpellLoc = SM.getFileLoc(Loc); std::pair LocInfo = SM.getDecomposedLoc(SpellLoc); FileID FID = LocInfo.first; unsigned FileOffset = LocInfo.second; -- GitLab From f027325999d75572cbdb4dda2e475bd27bcc74da Mon Sep 17 00:00:00 2001 From: Faisal Vali Date: Sun, 22 Oct 2017 14:45:08 +0000 Subject: [PATCH 0018/1682] [C++17] Fix PR34970 - tweak overload resolution for class template deduction-guides in line with WG21's p0620r0. In order to identify the copy deduction candidate, I considered two approaches: - attempt to determine whether an implicit guide is a copy deduction candidate by checking certain properties of its subsituted parameter during overload-resolution. - using one of the many bits (WillHaveBody) from FunctionDecl (that CXXDeductionGuideDecl inherits from) that are otherwise irrelevant for deduction guides After some brittle gymnastics w the first strategy, I settled on the second, although to avoid confusion and to give that bit a better name, i turned it into a member of an anonymous union. Given this identification 'bit', the tweak to overload resolution was a simple reordering of the deduction guide checks (in SemaOverload.cpp::isBetterOverloadCandidate), in-line with Jason Merrill's p0620r0 drafting which made it into the working paper. Concordant with that, I made sure the copy deduction candidate is always added. References: See https://bugs.llvm.org/show_bug.cgi?id=34970 See http://wg21.link/p0620r0 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316292 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Decl.h | 16 ++++++-- include/clang/AST/DeclCXX.h | 10 +++++ lib/Sema/SemaOverload.cpp | 23 +++++++++--- lib/Sema/SemaTemplate.cpp | 21 ++++++----- lib/Sema/SemaTemplateInstantiateDecl.cpp | 10 +++-- lib/Serialization/ASTReaderDecl.cpp | 2 + lib/Serialization/ASTWriterDecl.cpp | 1 + .../over/over.match/over.match.best/p1.cpp | 6 +-- .../over.match.class.deduct/p2.cpp | 37 +++++++++++++++++-- 9 files changed, 96 insertions(+), 30 deletions(-) diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 51d53a4c59..875a21a538 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -1678,10 +1678,18 @@ private: /// skipped. unsigned HasSkippedBody : 1; - /// Indicates if the function declaration will have a body, once we're done - /// parsing it. - unsigned WillHaveBody : 1; - +protected: + // Since a Deduction Guide [C++17] will never have a body, we can share the + // storage, and use a different name. + union { + /// Indicates if the function declaration will have a body, once we're done + /// parsing it. + unsigned WillHaveBody : 1; + /// Indicates that the Deduction Guide is the implicitly generated 'copy + /// deduction candidate' (is used during overload resolution). + unsigned IsCopyDeductionCandidate : 1; + }; +private: /// \brief End part of this FunctionDecl's source range. /// /// We could compute the full range in getSourceRange(). However, when we're diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 1b9458fcfc..d9b8ac274d 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1881,6 +1881,10 @@ private: if (EndLocation.isValid()) setRangeEnd(EndLocation); IsExplicitSpecified = IsExplicit; + + // IsCopyDeductionCandidate is a union variant member, so ensure it is the + // active member by storing to it. + IsCopyDeductionCandidate = false; } public: @@ -1903,6 +1907,12 @@ public: return getDeclName().getCXXDeductionGuideTemplate(); } + void setIsCopyDeductionCandidate() { + IsCopyDeductionCandidate = true; + } + + bool isCopyDeductionCandidate() const { return IsCopyDeductionCandidate; } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == CXXDeductionGuide; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 0e53ffa83f..49e9126afc 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -8965,12 +8965,6 @@ bool clang::isBetterOverloadCandidate( // C++14 [over.match.best]p1 section 2 bullet 3. } - // -- F1 is generated from a deduction-guide and F2 is not - auto *Guide1 = dyn_cast_or_null(Cand1.Function); - auto *Guide2 = dyn_cast_or_null(Cand2.Function); - if (Guide1 && Guide2 && Guide1->isImplicit() != Guide2->isImplicit()) - return Guide2->isImplicit(); - // -- F1 is a non-template function and F2 is a function template // specialization, or, if not that, bool Cand1IsSpecialization = Cand1.Function && @@ -9015,6 +9009,23 @@ bool clang::isBetterOverloadCandidate( // Inherited from sibling base classes: still ambiguous. } + // Check C++17 tie-breakers for deduction guides. + { + auto *Guide1 = dyn_cast_or_null(Cand1.Function); + auto *Guide2 = dyn_cast_or_null(Cand2.Function); + if (Guide1 && Guide2) { + // -- F1 is generated from a deduction-guide and F2 is not + if (Guide1->isImplicit() != Guide2->isImplicit()) + return Guide2->isImplicit(); + + // -- F1 is the copy deduction candidate(16.3.1.8) and F2 is not + if (Guide1->isCopyDeductionCandidate()) + return true; + } + } + + + // FIXME: Work around a defect in the C++17 guaranteed copy elision wording, // as combined with the resolution to CWG issue 243. // diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 46cda5e9ac..0930fdd653 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1837,7 +1837,6 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, // for which some class template parameter without a default argument never // appears in a deduced context). bool AddedAny = false; - bool AddedCopyOrMove = false; for (NamedDecl *D : LookupConstructors(Transform.Primary)) { D = D->getUnderlyingDecl(); if (D->isInvalidDecl() || D->isImplicit()) @@ -1854,20 +1853,22 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, Transform.transformConstructor(FTD, CD); AddedAny = true; - - AddedCopyOrMove |= CD->isCopyOrMoveConstructor(); } - // Synthesize an X() -> X<...> guide if there were no declared constructors. - // FIXME: The standard doesn't say (how) to do this. + // C++17 [over.match.class.deduct] + // -- If C is not defined or does not declare any constructors, an + // additional function template derived as above from a hypothetical + // constructor C(). if (!AddedAny) Transform.buildSimpleDeductionGuide(None); - // Synthesize an X(X<...>) -> X<...> guide if there was no declared constructor - // resembling a copy or move constructor. - // FIXME: The standard doesn't say (how) to do this. - if (!AddedCopyOrMove) - Transform.buildSimpleDeductionGuide(Transform.DeducedType); + // -- An additional function template derived as above from a hypothetical + // constructor C(C), called the copy deduction candidate. + cast( + cast( + Transform.buildSimpleDeductionGuide(Transform.DeducedType)) + ->getTemplatedDecl()) + ->setIsCopyDeductionCandidate(); } /// \brief Diagnose the presence of a default template argument on a diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 186a618387..d93fbd7c83 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1651,11 +1651,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } FunctionDecl *Function; - if (auto *DGuide = dyn_cast(D)) + if (auto *DGuide = dyn_cast(D)) { Function = CXXDeductionGuideDecl::Create( - SemaRef.Context, DC, D->getInnerLocStart(), DGuide->isExplicit(), - D->getNameInfo(), T, TInfo, D->getSourceRange().getEnd()); - else { + SemaRef.Context, DC, D->getInnerLocStart(), DGuide->isExplicit(), + D->getNameInfo(), T, TInfo, D->getSourceRange().getEnd()); + if (DGuide->isCopyDeductionCandidate()) + cast(Function)->setIsCopyDeductionCandidate(); + } else { Function = FunctionDecl::Create( SemaRef.Context, DC, D->getInnerLocStart(), D->getNameInfo(), T, TInfo, D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(), diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index c3c6c3e3d8..654a9fa94d 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1863,6 +1863,8 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) { void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) { VisitFunctionDecl(D); + if (Record.readInt()) + D->setIsCopyDeductionCandidate(); } void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) { diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 7a3f2e34bb..803795887c 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -612,6 +612,7 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) { VisitFunctionDecl(D); + Record.push_back(D->isCopyDeductionCandidate()); Code = serialization::DECL_CXX_DEDUCTION_GUIDE; } diff --git a/test/CXX/over/over.match/over.match.best/p1.cpp b/test/CXX/over/over.match/over.match.best/p1.cpp index fad5bf9a72..a933f62a30 100644 --- a/test/CXX/over/over.match/over.match.best/p1.cpp +++ b/test/CXX/over/over.match/over.match.best/p1.cpp @@ -25,13 +25,13 @@ namespace deduction_guide_example { // FIXME: The standard's example is wrong; we add a remove_ref<...> here to // fix it. - template::value> A(T&&, int*) -> A; + template::value> A(T&&, int*) -> A; A a{1, 0}; extern A a; - A b{a, 0}; + A b{a, 0}; // uses the implicit ctor that is more specialized A *pa = &a; - A&> *pb = &b; + A *pb = &b; } // Partial ordering of function template specializations will be tested diff --git a/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp b/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp index cf925455ac..cb9541caad 100644 --- a/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp +++ b/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp @@ -6,9 +6,10 @@ namespace Explicit { template struct A { A(T); A(T*); + A(...); }; template A(T) -> A; - template explicit A(T*) -> A; // expected-note {{explicit}} + template explicit A(T*) -> A; // expected-note {{explicit}} int *p; A a(p); @@ -16,14 +17,15 @@ namespace Explicit { A c{p}; A d = {p}; // expected-error {{selected an explicit deduction guide}} - using X = A; - using Y = A; + using X = A; + using Y = A; // uses the implicit guide, being more specialized than the eligible user-defined deduction guides. using X = decltype(a); using Y = decltype(b); using X = decltype(c); } + namespace std { template struct initializer_list { const T *ptr; @@ -54,3 +56,32 @@ namespace p0702r1 { // between X and X. X xz = {z}; // expected-error {{no viable constructor or deduction guide}} } +namespace pr34970 { +//https://bugs.llvm.org/show_bug.cgi?id=34970 + +template struct IsSame { + static constexpr bool value = false; +}; + +template struct IsSame { + static constexpr bool value = true; +}; + +template struct Optional { + template Optional(U&&) { } +}; + +template Optional(A) -> Optional; + +int main() { + Optional opt(1729); + Optional dupe(opt); + + static_assert(IsSame>::value); + static_assert(IsSame>::value); + static_assert(!IsSame>>::value); + return 0; +} + + +} \ No newline at end of file -- GitLab From 54b80d198719fec69ce8e0c47e4bede7d56dae6d Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Sun, 22 Oct 2017 20:16:28 +0000 Subject: [PATCH 0019/1682] Create fewer copies of StringMaps. No functionality change intended. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316301 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Frontend/PrecompiledPreamble.cpp | 2 +- lib/Parse/ParseStmtAsm.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Frontend/PrecompiledPreamble.cpp b/lib/Frontend/PrecompiledPreamble.cpp index 81466d0c28..e44f55dbe1 100644 --- a/lib/Frontend/PrecompiledPreamble.cpp +++ b/lib/Frontend/PrecompiledPreamble.cpp @@ -445,7 +445,7 @@ PrecompiledPreamble::PrecompiledPreamble( TempPCHFile PCHFile, std::vector PreambleBytes, bool PreambleEndsAtStartOfLine, llvm::StringMap FilesInPreamble) - : PCHFile(std::move(PCHFile)), FilesInPreamble(FilesInPreamble), + : PCHFile(std::move(PCHFile)), FilesInPreamble(std::move(FilesInPreamble)), PreambleBytes(std::move(PreambleBytes)), PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {} diff --git a/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp index f38ad279bc..3bd7fcc5e3 100644 --- a/lib/Parse/ParseStmtAsm.cpp +++ b/lib/Parse/ParseStmtAsm.cpp @@ -558,7 +558,7 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString)) return StmtError(); - TargetOptions TO = Actions.Context.getTargetInfo().getTargetOpts(); + const TargetOptions &TO = Actions.Context.getTargetInfo().getTargetOpts(); std::string FeaturesStr = llvm::join(TO.Features.begin(), TO.Features.end(), ","); -- GitLab From 45fcc58b7d3b7aba80c42141035900ebc5c19dfd Mon Sep 17 00:00:00 2001 From: Faisal Vali Date: Sun, 22 Oct 2017 22:29:52 +0000 Subject: [PATCH 0020/1682] [c++2a] Update cxx_status w __VA_OPT__ marked as completed in SVN. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316304 91177308-0d34-0410-b5e6-96231b3b80d8 --- www/cxx_status.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/cxx_status.html b/www/cxx_status.html index 85c0abcf26..729915e7c2 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -813,7 +813,7 @@ as the draft C++2a standard evolves. __VA_OPT__ for preprocessor comma elision P0306R4 - No + SVN Designated initializers -- GitLab From ef34bcb258ffbf7a500bb715edced98fe6348676 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 23 Oct 2017 03:58:34 +0000 Subject: [PATCH 0021/1682] For better compatibility with C++11 and C++14, emit a nondiscardable definition of a static constexpr data member if it's defined 'constexpr' out of line, not only if it's defined 'constexpr' in the class. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316310 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/ASTContext.cpp | 6 +++--- test/CodeGenCXX/cxx1z-inline-variables.cpp | 18 ++++++++++++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 15aa4531b8..a7ff9e10e9 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -5635,14 +5635,14 @@ ASTContext::getInlineVariableDefinitionKind(const VarDecl *VD) const { // In almost all cases, it's a weak definition. auto *First = VD->getFirstDecl(); - if (!First->isConstexpr() || First->isInlineSpecified() || - !VD->isStaticDataMember()) + if (First->isInlineSpecified() || !First->isStaticDataMember()) return InlineVariableDefinitionKind::Weak; // If there's a file-context declaration in this translation unit, it's a // non-discardable definition. for (auto *D : VD->redecls()) - if (D->getLexicalDeclContext()->isFileContext()) + if (D->getLexicalDeclContext()->isFileContext() && + !D->isInlineSpecified() && (D->isConstexpr() || First->isConstexpr())) return InlineVariableDefinitionKind::Strong; // If we've not seen one yet, we don't know. diff --git a/test/CodeGenCXX/cxx1z-inline-variables.cpp b/test/CodeGenCXX/cxx1z-inline-variables.cpp index 183709373d..0d2ec92a7a 100644 --- a/test/CodeGenCXX/cxx1z-inline-variables.cpp +++ b/test/CodeGenCXX/cxx1z-inline-variables.cpp @@ -31,18 +31,28 @@ struct compat { static constexpr int b = 2; static constexpr int c = 3; static inline constexpr int d = 4; + static const int e = 5; + static const int f = 6; + static const int g = 7; }; const int &compat_use_before_redecl = compat::b; const int compat::a; const int compat::b; const int compat::c; const int compat::d; +const int compat::e; +constexpr int compat::f; +constexpr inline int compat::g; const int &compat_use_after_redecl1 = compat::c; const int &compat_use_after_redecl2 = compat::d; -// CHECK: @_ZN6compat1bE = weak_odr constant i32 2 -// CHECK: @_ZN6compat1aE = weak_odr constant i32 1 -// CHECK: @_ZN6compat1cE = weak_odr constant i32 3 -// CHECK: @_ZN6compat1dE = linkonce_odr constant i32 4 +const int &compat_use_after_redecl3 = compat::g; +// CHECK-DAG: @_ZN6compat1bE = weak_odr constant i32 2 +// CHECK-DAG: @_ZN6compat1aE = weak_odr constant i32 1 +// CHECK-DAG: @_ZN6compat1cE = weak_odr constant i32 3 +// CHECK-DAG: @_ZN6compat1dE = linkonce_odr constant i32 4 +// CHECK-DAG: @_ZN6compat1eE = constant i32 5 +// CHECK-DAG: @_ZN6compat1fE = weak_odr constant i32 6 +// CHECK-DAG: @_ZN6compat1gE = linkonce_odr constant i32 7 template struct X { static int a; -- GitLab From 4e7c0628623316fe522d2b2688d8c7d4a8047105 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Mon, 23 Oct 2017 08:58:50 +0000 Subject: [PATCH 0022/1682] [rename] Don't overwrite the template argument when renaming a template function. Reviewers: ioeric Reviewed By: ioeric Subscribers: cierpuchaw, cfe-commits, klimek Differential Revision: https://reviews.llvm.org/D39120 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316314 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Refactoring/Rename/USRLocFinder.cpp | 7 ++++++- unittests/Rename/RenameFunctionTest.cpp | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp b/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp index 265e3c2072..38b2a624ea 100644 --- a/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp +++ b/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp @@ -221,7 +221,12 @@ public: } auto StartLoc = Expr->getLocStart(); - auto EndLoc = Expr->getLocEnd(); + // For template function call expressions like `foo()`, we want to + // restrict the end of location to just before the `<` character. + SourceLocation EndLoc = Expr->hasExplicitTemplateArgs() + ? Expr->getLAngleLoc().getLocWithOffset(-1) + : Expr->getLocEnd(); + // In case of renaming an enum declaration, we have to explicitly handle // unscoped enum constants referenced in expressions (e.g. // "auto r = ns1::ns2::Green" where Green is an enum constant of an unscoped diff --git a/unittests/Rename/RenameFunctionTest.cpp b/unittests/Rename/RenameFunctionTest.cpp index ef84b4bdb7..b27bbe273a 100644 --- a/unittests/Rename/RenameFunctionTest.cpp +++ b/unittests/Rename/RenameFunctionTest.cpp @@ -220,6 +220,25 @@ TEST_F(RenameFunctionTest, RenameFunctionDecls) { CompareSnippets(Expected, After); } +TEST_F(RenameFunctionTest, RenameTemplateFunctions) { + std::string Before = R"( + namespace na { + template T X(); + } + namespace na { void f() { X(); } } + namespace nb { void g() { na::X (); } } + )"; + std::string Expected = R"( + namespace na { + template T Y(); + } + namespace na { void f() { nb::Y(); } } + namespace nb { void g() { Y(); } } + )"; + std::string After = runClangRenameOnCode(Before, "na::X", "nb::Y"); + CompareSnippets(Expected, After); +} + TEST_F(RenameFunctionTest, RenameOutOfLineFunctionDecls) { std::string Before = R"( namespace na { -- GitLab From c5924addeeea29249ddbf048d3860c9e2198d289 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 23 Oct 2017 15:54:44 +0000 Subject: [PATCH 0023/1682] clang-cl: Expose --version. This is for consistency with lld-link, see https://reviews.llvm.org/D38972 Also give --version a help text so it shows up in --help / /? output (for both clang-cl and regular clang). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316335 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Driver/Options.td | 3 ++- test/Driver/cl-options.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 9f61521408..819dbff288 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -2469,7 +2469,8 @@ def _rtlib : Separate<["--"], "rtlib">, Alias; def _serialize_diags : Separate<["-", "--"], "serialize-diagnostics">, Flags<[DriverOption]>, HelpText<"Serialize compiler diagnostics to a file">; // We give --version different semantics from -version. -def _version : Flag<["--"], "version">, Flags<[CC1Option]>; +def _version : Flag<["--"], "version">, Flags<[CoreOption, CC1Option]>, + HelpText<"Print version information">; def _signed_char : Flag<["--"], "signed-char">, Alias; def _std : Separate<["--"], "std">, Alias; def _stdlib : Separate<["--"], "stdlib">, Alias; diff --git a/test/Driver/cl-options.c b/test/Driver/cl-options.c index 115b21963b..2435ba2932 100644 --- a/test/Driver/cl-options.c +++ b/test/Driver/cl-options.c @@ -574,6 +574,7 @@ // RUN: -fstandalone-debug \ // RUN: -flimit-debug-info \ // RUN: -flto \ +// RUN: --version \ // RUN: -Werror /Zs -- %s 2>&1 -- GitLab From e2c4d8a5a4f436c567974f84e6ba519a30c4d7d8 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Mon, 23 Oct 2017 16:20:15 +0000 Subject: [PATCH 0024/1682] Pull X86 "CPUKind" checking into .cpp file. [NFC] Preparing to do a refactor of CPU/feature checking, this patch pulls the one CPU implementation from the .h file to the .cpp file. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316338 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Basic/Targets/X86.cpp | 72 +++++++++++++++++++++++++++++++++++++++ lib/Basic/Targets/X86.h | 72 +-------------------------------------- 2 files changed, 73 insertions(+), 71 deletions(-) diff --git a/lib/Basic/Targets/X86.cpp b/lib/Basic/Targets/X86.cpp index 6eee2facda..644cf467b0 100644 --- a/lib/Basic/Targets/X86.cpp +++ b/lib/Basic/Targets/X86.cpp @@ -1522,6 +1522,78 @@ std::string X86TargetInfo::convertConstraint(const char *&Constraint) const { } } +bool X86TargetInfo::checkCPUKind(CPUKind Kind) const { + // Perform any per-CPU checks necessary to determine if this CPU is + // acceptable. + // FIXME: This results in terrible diagnostics. Clang just says the CPU is + // invalid without explaining *why*. + switch (Kind) { + case CK_Generic: + // No processor selected! + return false; + + case CK_i386: + case CK_i486: + case CK_WinChipC6: + case CK_WinChip2: + case CK_C3: + case CK_i586: + case CK_Pentium: + case CK_PentiumMMX: + case CK_i686: + case CK_PentiumPro: + case CK_Pentium2: + case CK_Pentium3: + case CK_PentiumM: + case CK_Yonah: + case CK_C3_2: + case CK_Pentium4: + case CK_Lakemont: + case CK_Prescott: + case CK_K6: + case CK_K6_2: + case CK_K6_3: + case CK_Athlon: + case CK_AthlonXP: + case CK_Geode: + // Only accept certain architectures when compiling in 32-bit mode. + if (getTriple().getArch() != llvm::Triple::x86) + return false; + + LLVM_FALLTHROUGH; + case CK_Nocona: + case CK_Core2: + case CK_Penryn: + case CK_Bonnell: + case CK_Silvermont: + case CK_Goldmont: + case CK_Nehalem: + case CK_Westmere: + case CK_SandyBridge: + case CK_IvyBridge: + case CK_Haswell: + case CK_Broadwell: + case CK_SkylakeClient: + case CK_SkylakeServer: + case CK_Cannonlake: + case CK_KNL: + case CK_KNM: + case CK_K8: + case CK_K8SSE3: + case CK_AMDFAM10: + case CK_BTVER1: + case CK_BTVER2: + case CK_BDVER1: + case CK_BDVER2: + case CK_BDVER3: + case CK_BDVER4: + case CK_ZNVER1: + case CK_x86_64: + return true; + } + llvm_unreachable("Unhandled CPU kind"); +} + X86TargetInfo::CPUKind X86TargetInfo::getCPUKind(StringRef CPU) const { return llvm::StringSwitch(CPU) .Case("i386", CK_i386) diff --git a/lib/Basic/Targets/X86.h b/lib/Basic/Targets/X86.h index 3b405dc762..321ce65bd1 100644 --- a/lib/Basic/Targets/X86.h +++ b/lib/Basic/Targets/X86.h @@ -270,77 +270,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { //@} } CPU = CK_Generic; - bool checkCPUKind(CPUKind Kind) const { - // Perform any per-CPU checks necessary to determine if this CPU is - // acceptable. - // FIXME: This results in terrible diagnostics. Clang just says the CPU is - // invalid without explaining *why*. - switch (Kind) { - case CK_Generic: - // No processor selected! - return false; - - case CK_i386: - case CK_i486: - case CK_WinChipC6: - case CK_WinChip2: - case CK_C3: - case CK_i586: - case CK_Pentium: - case CK_PentiumMMX: - case CK_i686: - case CK_PentiumPro: - case CK_Pentium2: - case CK_Pentium3: - case CK_PentiumM: - case CK_Yonah: - case CK_C3_2: - case CK_Pentium4: - case CK_Lakemont: - case CK_Prescott: - case CK_K6: - case CK_K6_2: - case CK_K6_3: - case CK_Athlon: - case CK_AthlonXP: - case CK_Geode: - // Only accept certain architectures when compiling in 32-bit mode. - if (getTriple().getArch() != llvm::Triple::x86) - return false; - - LLVM_FALLTHROUGH; - case CK_Nocona: - case CK_Core2: - case CK_Penryn: - case CK_Bonnell: - case CK_Silvermont: - case CK_Goldmont: - case CK_Nehalem: - case CK_Westmere: - case CK_SandyBridge: - case CK_IvyBridge: - case CK_Haswell: - case CK_Broadwell: - case CK_SkylakeClient: - case CK_SkylakeServer: - case CK_Cannonlake: - case CK_KNL: - case CK_KNM: - case CK_K8: - case CK_K8SSE3: - case CK_AMDFAM10: - case CK_BTVER1: - case CK_BTVER2: - case CK_BDVER1: - case CK_BDVER2: - case CK_BDVER3: - case CK_BDVER4: - case CK_ZNVER1: - case CK_x86_64: - return true; - } - llvm_unreachable("Unhandled CPU kind"); - } + bool checkCPUKind(CPUKind Kind) const; CPUKind getCPUKind(StringRef CPU) const; -- GitLab From 8b07e281bf02e8cb4e598bc6cab958ee00d41a29 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Mon, 23 Oct 2017 16:48:46 +0000 Subject: [PATCH 0025/1682] [ASTMatchers] Expose forEachOverriden in dynamic AST matchers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316344 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ASTMatchers/Dynamic/Registry.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index 4bd7a520c8..83f2c0e33a 100644 --- a/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -196,6 +196,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(forEachArgumentWithParam); REGISTER_MATCHER(forEachConstructorInitializer); REGISTER_MATCHER(forEachDescendant); + REGISTER_MATCHER(forEachOverridden); REGISTER_MATCHER(forEachSwitchCase); REGISTER_MATCHER(forField); REGISTER_MATCHER(forFunction); -- GitLab From 5d089284208206e4a621f99513a8a8ede1f9ac7e Mon Sep 17 00:00:00 2001 From: Yaxun Liu Date: Mon, 23 Oct 2017 17:49:26 +0000 Subject: [PATCH 0026/1682] CodeGen: Fix invalid bitcast in partial initialization of automatic arrary variable Differential Revision: https://reviews.llvm.org/D39184 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316353 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGDecl.cpp | 2 +- test/CodeGenOpenCL/amdgcn-automatic-variable.cl | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 707f8a555c..44a6db4750 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -1266,7 +1266,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { llvm::ConstantInt::get(IntPtrTy, getContext().getTypeSizeInChars(type).getQuantity()); - llvm::Type *BP = Int8PtrTy; + llvm::Type *BP = AllocaInt8PtrTy; if (Loc.getType() != BP) Loc = Builder.CreateBitCast(Loc, BP); diff --git a/test/CodeGenOpenCL/amdgcn-automatic-variable.cl b/test/CodeGenOpenCL/amdgcn-automatic-variable.cl index 19287c7d89..fefe1c4a41 100644 --- a/test/CodeGenOpenCL/amdgcn-automatic-variable.cl +++ b/test/CodeGenOpenCL/amdgcn-automatic-variable.cl @@ -58,3 +58,11 @@ void func2(void) { const int lvc = 4; lv1 = lvc; } + +// CHECK-LABEL: define void @func3() +// CHECK: %a = alloca [16 x [1 x float]], align 4, addrspace(5) +// CHECK: %[[CAST:.+]] = bitcast [16 x [1 x float]] addrspace(5)* %a to i8 addrspace(5)* +// CHECK: call void @llvm.memset.p5i8.i64(i8 addrspace(5)* %[[CAST]], i8 0, i64 64, i32 4, i1 false) +void func3(void) { + float a[16][1] = {{0.}}; +} -- GitLab From 13f1a2dfa1b0dc79c12150dc5b9a1fea75ce540e Mon Sep 17 00:00:00 2001 From: Jonas Hahnfeld Date: Mon, 23 Oct 2017 19:01:35 +0000 Subject: [PATCH 0027/1682] [OpenMP] Avoid VLAs for some reductions on array sections In some cases the compiler can deduce the length of an array section as constants. With this information, VLAs can be avoided in place of a constant sized array or even a scalar value if the length is 1. Example: int a[4], b[2]; pragma omp parallel reduction(+: a[1:2], b[1:1]) { } For chained array sections, this optimization is restricted to cases where all array sections except the last have a constant length 1. This trivially guarantees that there are no holes in the memory region that needs to be privatized. Example: int c[3][4]; pragma omp parallel reduction(+: c[1:1][1:2]) { } This relands commit r316229 that I reverted in r316235 because it failed on some bots. During investigation I found that this was because Clang and GCC evaluate the two arguments to emplace_back() in ReductionCodeGen::emitSharedLValue() in a different order, hence leading to a different order of generated instructions in the final LLVM IR. Fix this by passing in the arguments from temporary variables that are evaluated in a defined order. Differential Revision: https://reviews.llvm.org/D39136 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316362 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGOpenMPRuntime.cpp | 15 +- lib/CodeGen/CGStmtOpenMP.cpp | 7 +- lib/Sema/SemaOpenMP.cpp | 83 ++++++- test/OpenMP/for_reduction_codegen.cpp | 289 ++++++++++++++++++---- test/OpenMP/for_reduction_codegen_UDR.cpp | 133 ++++++---- 5 files changed, 416 insertions(+), 111 deletions(-) diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index f98ff85565..b23d601eb8 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -916,8 +916,9 @@ ReductionCodeGen::ReductionCodeGen(ArrayRef Shareds, void ReductionCodeGen::emitSharedLValue(CodeGenFunction &CGF, unsigned N) { assert(SharedAddresses.size() == N && "Number of generated lvalues must be exactly N."); - SharedAddresses.emplace_back(emitSharedLValue(CGF, ClausesData[N].Ref), - emitSharedLValueUB(CGF, ClausesData[N].Ref)); + LValue First = emitSharedLValue(CGF, ClausesData[N].Ref); + LValue Second = emitSharedLValueUB(CGF, ClausesData[N].Ref); + SharedAddresses.emplace_back(First, Second); } void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N) { @@ -925,7 +926,7 @@ void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N) { cast(cast(ClausesData[N].Private)->getDecl()); QualType PrivateType = PrivateVD->getType(); bool AsArraySection = isa(ClausesData[N].Ref); - if (!AsArraySection && !PrivateType->isVariablyModifiedType()) { + if (!PrivateType->isVariablyModifiedType()) { Sizes.emplace_back( CGF.getTypeSize( SharedAddresses[N].first.getType().getNonReferenceType()), @@ -963,10 +964,9 @@ void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N, auto *PrivateVD = cast(cast(ClausesData[N].Private)->getDecl()); QualType PrivateType = PrivateVD->getType(); - bool AsArraySection = isa(ClausesData[N].Ref); - if (!AsArraySection && !PrivateType->isVariablyModifiedType()) { + if (!PrivateType->isVariablyModifiedType()) { assert(!Size && !Sizes[N].second && - "Size should be nullptr for non-variably modified redution " + "Size should be nullptr for non-variably modified reduction " "items."); return; } @@ -994,8 +994,7 @@ void ReductionCodeGen::emitInitialization( CGF.ConvertTypeForMem(SharedType)), SharedType, SharedAddresses[N].first.getBaseInfo(), CGF.CGM.getTBAAAccessInfo(SharedType)); - if (isa(ClausesData[N].Ref) || - CGF.getContext().getAsArrayType(PrivateVD->getType())) { + if (CGF.getContext().getAsArrayType(PrivateVD->getType())) { emitAggregateInitialization(CGF, N, PrivateAddr, SharedLVal, DRD); } else if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) { emitInitWithReductionInitializer(CGF, DRD, ClausesData[N].ReductionOp, diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index cdec3e35f9..0e5ea798eb 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -996,7 +996,9 @@ void CodeGenFunction::EmitOMPReductionClauseInit( auto *LHSVD = cast(cast(*ILHS)->getDecl()); auto *RHSVD = cast(cast(*IRHS)->getDecl()); - if (isa(IRef)) { + QualType Type = PrivateVD->getType(); + bool isaOMPArraySectionExpr = isa(IRef); + if (isaOMPArraySectionExpr && Type->isVariablyModifiedType()) { // Store the address of the original variable associated with the LHS // implicit variable. PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() -> Address { @@ -1005,7 +1007,8 @@ void CodeGenFunction::EmitOMPReductionClauseInit( PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address { return GetAddrOfLocalVar(PrivateVD); }); - } else if (isa(IRef)) { + } else if ((isaOMPArraySectionExpr && Type->isScalarType()) || + isa(IRef)) { // Store the address of the original variable associated with the LHS // implicit variable. PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() -> Address { diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index a024888fbf..bf89eb0b2f 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -9330,6 +9330,68 @@ struct ReductionData { }; } // namespace +static bool CheckOMPArraySectionConstantForReduction( + ASTContext &Context, const OMPArraySectionExpr *OASE, bool &SingleElement, + SmallVectorImpl &ArraySizes) { + const Expr *Length = OASE->getLength(); + if (Length == nullptr) { + // For array sections of the form [1:] or [:], we would need to analyze + // the lower bound... + if (OASE->getColonLoc().isValid()) + return false; + + // This is an array subscript which has implicit length 1! + SingleElement = true; + ArraySizes.push_back(llvm::APSInt::get(1)); + } else { + llvm::APSInt ConstantLengthValue; + if (!Length->EvaluateAsInt(ConstantLengthValue, Context)) + return false; + + SingleElement = (ConstantLengthValue.getSExtValue() == 1); + ArraySizes.push_back(ConstantLengthValue); + } + + // Get the base of this array section and walk up from there. + const Expr *Base = OASE->getBase()->IgnoreParenImpCasts(); + + // We require length = 1 for all array sections except the right-most to + // guarantee that the memory region is contiguous and has no holes in it. + while (const auto *TempOASE = dyn_cast(Base)) { + Length = TempOASE->getLength(); + if (Length == nullptr) { + // For array sections of the form [1:] or [:], we would need to analyze + // the lower bound... + if (OASE->getColonLoc().isValid()) + return false; + + // This is an array subscript which has implicit length 1! + ArraySizes.push_back(llvm::APSInt::get(1)); + } else { + llvm::APSInt ConstantLengthValue; + if (!Length->EvaluateAsInt(ConstantLengthValue, Context) || + ConstantLengthValue.getSExtValue() != 1) + return false; + + ArraySizes.push_back(ConstantLengthValue); + } + Base = TempOASE->getBase()->IgnoreParenImpCasts(); + } + + // If we have a single element, we don't need to add the implicit lengths. + if (!SingleElement) { + while (const auto *TempASE = dyn_cast(Base)) { + // Has implicit length 1! + ArraySizes.push_back(llvm::APSInt::get(1)); + Base = TempASE->getBase()->IgnoreParenImpCasts(); + } + } + + // This array section can be privatized as a single value or as a constant + // sized array. + return true; +} + static bool ActOnOMPReductionKindClause( Sema &S, DSAStackTy *Stack, OpenMPClauseKind ClauseKind, ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -9628,7 +9690,26 @@ static bool ActOnOMPReductionKindClause( auto *RHSVD = buildVarDecl(S, ELoc, Type, D->getName(), D->hasAttrs() ? &D->getAttrs() : nullptr); auto PrivateTy = Type; - if (OASE || + + // Try if we can determine constant lengths for all array sections and avoid + // the VLA. + bool ConstantLengthOASE = false; + if (OASE) { + bool SingleElement; + llvm::SmallVector ArraySizes; + ConstantLengthOASE = CheckOMPArraySectionConstantForReduction( + Context, OASE, SingleElement, ArraySizes); + + // If we don't have a single element, we must emit a constant array type. + if (ConstantLengthOASE && !SingleElement) { + for (auto &Size : ArraySizes) { + PrivateTy = Context.getConstantArrayType( + PrivateTy, Size, ArrayType::Normal, /*IndexTypeQuals=*/0); + } + } + } + + if ((OASE && !ConstantLengthOASE) || (!ASE && D->getType().getNonReferenceType()->isVariablyModifiedType())) { // For arrays/array sections only: diff --git a/test/OpenMP/for_reduction_codegen.cpp b/test/OpenMP/for_reduction_codegen.cpp index d5afae990b..2c49022ff0 100644 --- a/test/OpenMP/for_reduction_codegen.cpp +++ b/test/OpenMP/for_reduction_codegen.cpp @@ -27,7 +27,7 @@ struct S { // CHECK-DAG: [[REDUCTION_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 18, i32 0, i32 0, i8* // CHECK-DAG: [[REDUCTION_LOCK:@.+]] = common global [8 x i32] zeroinitializer -template +template T tmain() { T t; S test; @@ -36,6 +36,7 @@ T tmain() { S s_arr[] = {1, 2}; S &var = test; S var1; + S arr[length]; #pragma omp parallel #pragma omp for reduction(+:t_var) reduction(&:var) reduction(&& : var1) reduction(min: t_var1) nowait for (int i = 0; i < 2; ++i) { @@ -48,6 +49,12 @@ T tmain() { vec[i] = t_var; s_arr[i] = var; } +#pragma omp parallel +#pragma omp for reduction(+ : arr[1:length-2]) + for (int i = 0; i < 2; ++i) { + vec[i] = t_var; + s_arr[i] = var; + } return T(); } @@ -180,12 +187,12 @@ int main() { S test; float t_var = 0, t_var1; int vec[] = {1, 2}; - S s_arr[] = {1, 2}; + S s_arr[] = {1, 2, 3, 4}; S &var = test; S var1, arrs[10][4]; S **var2 = foo(); - S vvar2[2]; - S (&var3)[2] = s_arr; + S vvar2[5]; + S (&var3)[4] = s_arr; #pragma omp parallel #pragma omp for reduction(+:t_var) reduction(&:var) reduction(&& : var1) reduction(min: t_var1) for (int i = 0; i < 2; ++i) { @@ -205,6 +212,18 @@ int main() { for (int i = 0; i < 10; ++i) ; #pragma omp parallel +#pragma omp for reduction(& : var2[1][1 : 6]) + for (int i = 0; i < 10; ++i) + ; +#pragma omp parallel +#pragma omp for reduction(& : var2[1 : 1][1 : 6]) + for (int i = 0; i < 10; ++i) + ; +#pragma omp parallel +#pragma omp for reduction(& : var2[1 : 1][1]) + for (int i = 0; i < 10; ++i) + ; +#pragma omp parallel #pragma omp for reduction(& : vvar2[0 : 5]) for (int i = 0; i < 10; ++i) ; @@ -213,28 +232,42 @@ int main() { for (int i = 0; i < 10; ++i) ; #pragma omp parallel +#pragma omp for reduction(& : var3[ : 2]) + for (int i = 0; i < 10; ++i) + ; + // TODO: The compiler should also be able to generate a constant sized array in this case! +#pragma omp parallel +#pragma omp for reduction(& : var3[2 : ]) + for (int i = 0; i < 10; ++i) + ; +#pragma omp parallel #pragma omp for reduction(& : var3) for (int i = 0; i < 10; ++i) ; - return tmain(); + return tmain(); #endif } // CHECK: define {{.*}}i{{[0-9]+}} @main() // CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]], // CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]]) -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [2 x i32]*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK1:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK2:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK3:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK4:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK5:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK6:@.+]] to void -// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]() +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK4:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK5:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK6:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [5 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK7:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK8:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK9:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK10:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK11:@.+]] to void +// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT_42:@.+]]() // CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]* // CHECK: ret // -// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(4) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}}) // CHECK: [[T_VAR_PRIV:%.+]] = alloca float, // CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]], // CHECK: [[VAR1_PRIV:%.+]] = alloca [[S_FLOAT_TY]], @@ -910,44 +943,183 @@ int main() { // CHECK: store [[S_FLOAT_TY]]* [[PSEUDO_VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]] // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[S_FLOAT_TY]]*** dereferenceable(8) %{{.+}}) -// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR2_ORIG_ADDR:%.+]] = alloca [[S_FLOAT_TY]]***, +// CHECK: [[VAR2_PRIV:%.+]] = alloca [1 x [6 x [[S_FLOAT_TY]]]], // Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*], +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VVAR2_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]], +// CHECK: [[VAR2_ORIG:%.+]] = load [[S_FLOAT_TY]]***, [[S_FLOAT_TY]]**** [[VAR2_ORIG_ADDR]], -// CHECK: [[LOW:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0 -// CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64 -// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 -// CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]] -// CHECK: [[DIF:%.+]] = sdiv exact i64 [[BYTE_DIF]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) -// CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1 -// CHECK: call i8* @llvm.stacksave() -// CHECK: [[VVAR2_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]], -// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], +// CHECK: [[ARRIDX:%.+]] = getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], i64 1 +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[ARRIDX]], +// CHECK: [[LOW:%.+]] = getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[LD]], i64 1 +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], + +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], +// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], // CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 // CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 // CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] // CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) -// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VVAR2_PRIV]], i64 [[OFFSET]] -// CHECK: [[VVAR2_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VVAR2_PRIV]] to [2 x [[S_FLOAT_TY]]]* +// CHECK: [[PSEUDO_VAR2_PRIV:%.+]] = getelementptr [1 x [6 x [[S_FLOAT_TY]]]], [1 x [6 x [[S_FLOAT_TY]]]]* [[VAR2_PRIV]], i64 [[OFFSET]] +// CHECK: store [[S_FLOAT_TY]]** [[REF:.+]], [[S_FLOAT_TY]]*** % +// CHECK: [[VAR2_PRIV:%.+]] = bitcast [1 x [6 x [[S_FLOAT_TY]]]]* [[PSEUDO_VAR2_PRIV]] to [[S_FLOAT_TY]]* +// CHECK: store [[S_FLOAT_TY]]* [[VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]] // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[S_FLOAT_TY]]*** dereferenceable(8) %{{.+}}) -// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR2_ORIG_ADDR:%.+]] = alloca [[S_FLOAT_TY]]***, +// CHECK: [[VAR2_PRIV:%.+]] = alloca [1 x [6 x [[S_FLOAT_TY]]]], // Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*], +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], +// CHECK: [[VAR2_ORIG:%.+]] = load [[S_FLOAT_TY]]***, [[S_FLOAT_TY]]**** [[VAR2_ORIG_ADDR]], + +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], +// CHECK: [[ARRIDX:%.+]] = getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], i64 1 +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[ARRIDX]], +// CHECK: [[LOW:%.+]] = getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[LD]], i64 1 +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], + +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], +// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], +// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 +// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 +// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] +// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) +// CHECK: [[PSEUDO_VAR2_PRIV:%.+]] = getelementptr [1 x [6 x [[S_FLOAT_TY]]]], [1 x [6 x [[S_FLOAT_TY]]]]* [[VAR2_PRIV]], i64 [[OFFSET]] +// CHECK: store [[S_FLOAT_TY]]** [[REF:.+]], [[S_FLOAT_TY]]*** % +// CHECK: [[VAR2_PRIV:%.+]] = bitcast [1 x [6 x [[S_FLOAT_TY]]]]* [[PSEUDO_VAR2_PRIV]] to [[S_FLOAT_TY]]* +// CHECK: store [[S_FLOAT_TY]]* [[VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]] +// CHECK: ret void + +// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[S_FLOAT_TY]]*** dereferenceable(8) %{{.+}}) + +// CHECK: [[VAR2_ORIG_ADDR:%.+]] = alloca [[S_FLOAT_TY]]***, +// CHECK: [[VAR2_PRIV:%.+]] = alloca [[S_FLOAT_TY]], + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], + +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], +// CHECK: [[VAR2_ORIG:%.+]] = load [[S_FLOAT_TY]]***, [[S_FLOAT_TY]]**** [[VAR2_ORIG_ADDR]], + +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], +// CHECK: [[ARRIDX:%.+]] = getelementptr inbounds [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], i64 1 +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[ARRIDX]], +// CHECK: [[LOW:%.+]] = getelementptr inbounds [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[LD]], i64 1 +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], + +// CHECK: [[LD:%.+]] = load [[S_FLOAT_TY]]**, [[S_FLOAT_TY]]*** [[VAR2_ORIG]], +// CHECK: [[ORIG_START:%.+]] = load [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]** [[LD]], +// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 +// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 +// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] +// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) +// CHECK: [[PSEUDO_VAR2_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VAR2_PRIV]], i64 [[OFFSET]] +// CHECK: store [[S_FLOAT_TY]]** [[REF:.+]], [[S_FLOAT_TY]]*** % +// CHECK: store [[S_FLOAT_TY]]* [[PSEUDO_VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]] +// CHECK: ret void + +// CHECK: define internal void [[MAIN_MICROTASK7]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [5 x [[S_FLOAT_TY]]]* dereferenceable(20) %{{.+}}) + +// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [5 x [[S_FLOAT_TY]]]*, +// CHECK: [[VVAR2_PRIV:%.+]] = alloca [5 x [[S_FLOAT_TY]]], + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], + +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], +// CHECK: [[VVAR2_ORIG:%.+]] = load [5 x [[S_FLOAT_TY]]]*, [5 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]], + +// CHECK: [[LOW:%.+]] = getelementptr inbounds [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0 +// CHECK: [[ORIG_START:%.+]] = bitcast [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 +// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 +// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] +// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) +// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_PRIV]], i64 [[OFFSET]] +// CHECK: ret void + +// CHECK: define internal void [[MAIN_MICROTASK8]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}}) + +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], + +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], + +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], + +// CHECK: [[LOW:%.+]] = getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 1 +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], + +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 +// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 +// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] +// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) +// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i64 [[OFFSET]] +// CHECK: [[VAR3_PRIV:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]* + +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % + +// CHECK: ret void + +// CHECK: define internal void [[MAIN_MICROTASK9]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}}) + +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], + +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], + +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], + +// CHECK: [[LOW:%.+]] = getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 0 +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], + +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 +// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 +// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] +// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) +// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i64 [[OFFSET]] +// CHECK: [[VAR3_PRIV:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]* + +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % + +// CHECK: ret void + +// CHECK: define internal void [[MAIN_MICROTASK10]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}}) + +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*], + +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], // CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64 // CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW:%.+]] to i64 // CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]] @@ -955,44 +1127,47 @@ int main() { // CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1 // CHECK: call i8* @llvm.stacksave() // CHECK: [[VAR3_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* // CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 // CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 // CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] // CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (float* getelementptr (float, float* null, i32 1) to i64) // CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VAR3_PRIV]], i64 [[OFFSET]] -// CHECK: [[VAR3_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VAR3_PRIV]] to [2 x [[S_FLOAT_TY]]]* +// CHECK: [[VAR3_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]* -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** % +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(8) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK11]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(16) %{{.+}}) -// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, -// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR3_PRIV:%.+]] = alloca [4 x [[S_FLOAT_TY]]], // Reduction list for runtime. // CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0 -// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 2 +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0 +// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 4 -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** % -// CHECK: bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % +// CHECK: bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* // CHECK: ret void -// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]() +// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT_42]]() // CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]], // CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]]) // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i32*, [[S_INT_TY]]*, [[S_INT_TY]]*, i32*, [2 x i32]*, [2 x [[S_INT_TY]]]*)* [[TMAIN_MICROTASK:@.+]] to void +// Not interested in this one: +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [42 x [[S_INT_TY]]]*, [2 x i32]*, i32*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]*)* [[TMAIN_MICROTASK2:@.+]] to void // CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]* // CHECK: ret // @@ -1226,5 +1401,27 @@ int main() { // CHECK: store i{{[0-9]+}} [[UP]], i{{[0-9]+}}* [[T_VAR1_LHS]], // CHECK: ret void +// CHECK: define internal void [[TMAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [42 x [[S_INT_TY]]]* dereferenceable(168) %{{.*}}, [2 x i32]* dereferenceable(8) %{{.*}}, i32* dereferenceable(4) %{{.*}}, [2 x [[S_INT_TY]]]* dereferenceable(8) %{{.*}}, [[S_INT_TY]]* dereferenceable(4) %{{.*}}) + +// CHECK: [[ARR_ORIG_ADDR:%.+]] = alloca [42 x [[S_INT_TY]]]*, +// CHECK: [[ARR_PRIV:%.+]] = alloca [40 x [[S_INT_TY]]], + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], + +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], + +// CHECK: [[ARR_ORIG:%.+]] = load [42 x [[S_INT_TY]]]*, [42 x [[S_INT_TY]]]** [[ARR_ORIG_ADDR]], +// CHECK: [[LOW:%.+]] = getelementptr inbounds [42 x [[S_INT_TY]]], [42 x [[S_INT_TY]]]* [[ARR_ORIG]], i64 0, i64 1 +// CHECK: [[ORIG_START:%.+]] = bitcast [42 x [[S_INT_TY]]]* [[ARR_ORIG]] to [[S_INT_TY]]* +// CHECK: [[START:%.+]] = ptrtoint [[S_INT_TY]]* [[ORIG_START]] to i64 +// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_INT_TY]]* [[LOW]] to i64 +// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] +// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint (i32* getelementptr (i32, i32* null, i32 1) to i64) +// CHECK: [[PSEUDO_ARR_PRIV:%.+]] = getelementptr [40 x [[S_INT_TY]]], [40 x [[S_INT_TY]]]* [[ARR_PRIV]], i64 [[OFFSET]] +// CHECK: [[ARR_PRIV:%.+]] = bitcast [40 x [[S_INT_TY]]]* [[PSEUDO_ARR_PRIV]] to [42 x [[S_INT_TY]]]* + +// CHECK: ret void + #endif diff --git a/test/OpenMP/for_reduction_codegen_UDR.cpp b/test/OpenMP/for_reduction_codegen_UDR.cpp index 95b04f44d4..d78e515f30 100644 --- a/test/OpenMP/for_reduction_codegen_UDR.cpp +++ b/test/OpenMP/for_reduction_codegen_UDR.cpp @@ -40,7 +40,7 @@ void init_plus(BaseS1&, const BaseS1&); // CHECK-DAG: [[REDUCTION_LOCK:@.+]] = common global [8 x i32] zeroinitializer #pragma omp declare reduction(operator&& : int : omp_out = 111 & omp_in) -template +template T tmain() { T t; S test; @@ -49,6 +49,7 @@ T tmain() { S s_arr[] = {1, 2}; S &var = test; S var1; + S arr[length]; #pragma omp declare reduction(operator& : T : omp_out = 15 + omp_in) #pragma omp declare reduction(operator+ : T : omp_out = 1513 + omp_in) initializer(omp_priv = 321) #pragma omp declare reduction(min : T : omp_out = 47 - omp_in) initializer(omp_priv = 432 / omp_orig) @@ -66,6 +67,12 @@ T tmain() { vec[i] = t_var; s_arr[i] = var; } +#pragma omp parallel +#pragma omp for reduction(+ : arr[1:length-2]) + for (int i = 0; i < 2; ++i) { + vec[i] = t_var; + s_arr[i] = var; + } return T(); } @@ -78,12 +85,12 @@ int main() { S test; float t_var = 0, t_var1; int vec[] = {1, 2}; - S s_arr[] = {1, 2}; + S s_arr[] = {1, 2, 3, 4}; S &var = test; S var1, arrs[10][4]; S **var2 = foo(); - S vvar2[2]; - S(&var3)[2] = s_arr; + S vvar2[5]; + S(&var3)[4] = s_arr; #pragma omp declare reduction(operator+ : int : omp_out = 555 * omp_in) initializer(omp_priv = 888) #pragma omp parallel #pragma omp for reduction(+ : t_var) reduction(& : var) reduction(&& : var1) reduction(min : t_var1) @@ -115,24 +122,24 @@ int main() { #pragma omp for reduction(& : var3) for (int i = 0; i < 10; ++i) ; - return tmain(); + return tmain(); } // CHECK: define {{.*}}i{{[0-9]+}} @main() // CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]], // CHECK: call {{.*}} [[S_FLOAT_TY_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]]) -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, float*, [[S_FLOAT_TY]]*, [[S_FLOAT_TY]]*, float*, [2 x i32]*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [2 x i32]*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK1:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i64, i64, i32*, [10 x [4 x [[S_FLOAT_TY]]]]*)* [[MAIN_MICROTASK2:@.+]] to void // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[S_FLOAT_TY]]***)* [[MAIN_MICROTASK3:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK4:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK5:@.+]] to void -// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK6:@.+]] to void -// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT:@.+]]() +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [5 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK4:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK5:@.+]] to void +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [4 x [[S_FLOAT_TY]]]*)* [[MAIN_MICROTASK6:@.+]] to void +// CHECK: = call {{.*}}i{{.+}} [[TMAIN_INT_42:@.+]]() // CHECK: call {{.*}} [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]* // CHECK: ret // -// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, float* dereferenceable(4) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, [[S_FLOAT_TY]]* dereferenceable(12) %{{.+}}, float* dereferenceable(4) %{{.+}}, [2 x i32]* dereferenceable(8) %vec, [4 x [[S_FLOAT_TY]]]* dereferenceable(48) %{{.+}}) // CHECK: [[T_VAR_PRIV:%.+]] = alloca float, // CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]], // CHECK: [[VAR1_PRIV:%.+]] = alloca [[S_FLOAT_TY]], @@ -711,89 +718,85 @@ int main() { // CHECK: store [[S_FLOAT_TY]]* [[PSEUDO_VAR2_PRIV]], [[S_FLOAT_TY]]** [[REF]] // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK4]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [5 x [[S_FLOAT_TY]]]* dereferenceable(60) %{{.+}}) -// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, +// CHECK: [[VVAR2_ORIG_ADDR:%.+]] = alloca [5 x [[S_FLOAT_TY]]]*, +// CHECK: [[VVAR2_PRIV:%.+]] = alloca [5 x [[S_FLOAT_TY]]], // Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*], +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VVAR2_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]], +// CHECK: [[VVAR2_ORIG:%.+]] = load [5 x [[S_FLOAT_TY]]]*, [5 x [[S_FLOAT_TY]]]** [[VVAR2_ORIG_ADDR]], -// CHECK: [[LOW:%.+]] = getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0 -// CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64 -// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 -// CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]] -// CHECK: [[DIF:%.+]] = sdiv exact i64 [[BYTE_DIF]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64) -// CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1 -// CHECK: call i8* @llvm.stacksave() -// CHECK: [[VVAR2_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]], -// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[LOW:%.+]] = getelementptr inbounds [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]], i64 0, i64 0 +// CHECK: [[ORIG_START:%.+]] = bitcast [5 x [[S_FLOAT_TY]]]* [[VVAR2_ORIG]] to [[S_FLOAT_TY]]* // CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 // CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 // CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] // CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64) -// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VVAR2_PRIV]], i64 [[OFFSET]] -// CHECK: [[VVAR2_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VVAR2_PRIV]] to [2 x [[S_FLOAT_TY]]]* +// CHECK: [[PSEUDO_VVAR2_PRIV:%.+]] = getelementptr [5 x [[S_FLOAT_TY]]], [5 x [[S_FLOAT_TY]]]* [[VVAR2_PRIV]], i64 [[OFFSET]] // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK5]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(48) %{{.+}}) -// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], // Reduction list for runtime. -// CHECK: [[RED_LIST:%.+]] = alloca [2 x i8*], +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], -// CHECK: [[LAST:%.+]] = ptrtoint [[S_FLOAT_TY]]* %{{.+}} to i64 -// CHECK: [[FIRST:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW:%.+]] to i64 -// CHECK: [[BYTE_DIF:%.+]] = sub i64 [[LAST]], [[FIRST]] -// CHECK: [[DIF:%.+]] = sdiv exact i64 [[BYTE_DIF]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64) -// CHECK: [[SIZE:%.+]] = add nuw i64 [[DIF]], 1 -// CHECK: call i8* @llvm.stacksave() -// CHECK: [[VAR3_PRIV:%.+]] = alloca [[S_FLOAT_TY]], i64 [[SIZE]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: [[ORIG_START:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], + +// CHECK: [[LOW:%.+]] = getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], i64 0, i64 1 +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], + +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: [[ORIG_START:%.+]] = bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* // CHECK: [[START:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[ORIG_START]] to i64 // CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_FLOAT_TY]]* [[LOW]] to i64 // CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] // CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint ([[S_FLOAT_TY]]* getelementptr ([[S_FLOAT_TY]], [[S_FLOAT_TY]]* null, i32 1) to i64) -// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* [[VAR3_PRIV]], i64 [[OFFSET]] -// CHECK: [[VAR3_PRIV:%.+]] = bitcast [[S_FLOAT_TY]]* [[PSEUDO_VAR3_PRIV]] to [2 x [[S_FLOAT_TY]]]* +// CHECK: [[PSEUDO_VAR3_PRIV:%.+]] = getelementptr [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i64 [[OFFSET]] +// CHECK: [[VAR3_PRIV:%.+]] = bitcast [2 x [[S_FLOAT_TY]]]* [[PSEUDO_VAR3_PRIV]] to [4 x [[S_FLOAT_TY]]]* -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** % +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [2 x [[S_FLOAT_TY]]]* dereferenceable(24) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK6]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [4 x [[S_FLOAT_TY]]]* dereferenceable(48) %{{.+}}) -// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [2 x [[S_FLOAT_TY]]]*, -// CHECK: [[VAR3_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], +// CHECK: [[VAR3_ORIG_ADDR:%.+]] = alloca [4 x [[S_FLOAT_TY]]]*, +// CHECK: [[VAR3_PRIV:%.+]] = alloca [4 x [[S_FLOAT_TY]]], // Reduction list for runtime. // CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], // CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], -// CHECK: [[VAR3_ORIG:%.+]] = load [2 x [[S_FLOAT_TY]]]*, [2 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], -// CHECK: getelementptr inbounds [2 x [[S_FLOAT_TY]]], [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0 -// CHECK: bitcast [2 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* -// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 2 +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]], [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR:%.+]], +// CHECK: [[VAR3_ORIG:%.+]] = load [4 x [[S_FLOAT_TY]]]*, [4 x [[S_FLOAT_TY]]]** [[VAR3_ORIG_ADDR]], +// CHECK: getelementptr inbounds [4 x [[S_FLOAT_TY]]], [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], i32 0, i32 0 +// CHECK: bitcast [4 x [[S_FLOAT_TY]]]* [[VAR3_ORIG]] to [[S_FLOAT_TY]]* +// CHECK: getelementptr [[S_FLOAT_TY]], [[S_FLOAT_TY]]* %{{.+}}, i64 4 -// CHECK: store [2 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [2 x [[S_FLOAT_TY]]]** % +// CHECK: store [4 x [[S_FLOAT_TY]]]* [[VAR3_PRIV]], [4 x [[S_FLOAT_TY]]]** % // CHECK: ret void -// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]() +// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT_42]]() // CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]], // CHECK: call {{.*}} [[S_INT_TY_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]]) // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 6, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, i32*, [[S_INT_TY]]*, [[S_INT_TY]]*, i32*, [2 x i32]*, [2 x [[S_INT_TY]]]*)* [[TMAIN_MICROTASK:@.+]] to void +// Not interested in this one: +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 5, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [42 x [[S_INT_TY]]]*, [2 x i32]*, i32*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]*)* [[TMAIN_MICROTASK2:@.+]] to void +// CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]* // CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]* // CHECK: ret // @@ -964,5 +967,27 @@ int main() { // CHECK: sub nsw i32 47, % // CHECK: ret void +// CHECK: define internal void [[TMAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [42 x [[S_INT_TY]]]* dereferenceable(504) %{{.*}}, [2 x i32]* dereferenceable(8) %{{.*}}, i32* dereferenceable(4) %{{.*}}, [2 x [[S_INT_TY]]]* dereferenceable(24) %{{.*}}, [[S_INT_TY]]* dereferenceable(12) %{{.*}}) + +// CHECK: [[ARR_ORIG_ADDR:%.+]] = alloca [42 x [[S_INT_TY]]]*, +// CHECK: [[ARR_PRIV:%.+]] = alloca [40 x [[S_INT_TY]]], + +// Reduction list for runtime. +// CHECK: [[RED_LIST:%.+]] = alloca [1 x i8*], + +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_ADDR:%.+]], + +// CHECK: [[ARR_ORIG:%.+]] = load [42 x [[S_INT_TY]]]*, [42 x [[S_INT_TY]]]** [[ARR_ORIG_ADDR]], +// CHECK: [[LOW:%.+]] = getelementptr inbounds [42 x [[S_INT_TY]]], [42 x [[S_INT_TY]]]* [[ARR_ORIG]], i64 0, i64 1 +// CHECK: [[ORIG_START:%.+]] = bitcast [42 x [[S_INT_TY]]]* [[ARR_ORIG]] to [[S_INT_TY]]* +// CHECK: [[START:%.+]] = ptrtoint [[S_INT_TY]]* [[ORIG_START]] to i64 +// CHECK: [[LOW_BOUND:%.+]] = ptrtoint [[S_INT_TY]]* [[LOW]] to i64 +// CHECK: [[OFFSET_BYTES:%.+]] = sub i64 [[START]], [[LOW_BOUND]] +// CHECK: [[OFFSET:%.+]] = sdiv exact i64 [[OFFSET_BYTES]], ptrtoint ([[S_INT_TY]]* getelementptr ([[S_INT_TY]], [[S_INT_TY]]* null, i32 1) to i64) +// CHECK: [[PSEUDO_ARR_PRIV:%.+]] = getelementptr [40 x [[S_INT_TY]]], [40 x [[S_INT_TY]]]* [[ARR_PRIV]], i64 [[OFFSET]] +// CHECK: [[ARR_PRIV:%.+]] = bitcast [40 x [[S_INT_TY]]]* [[PSEUDO_ARR_PRIV]] to [42 x [[S_INT_TY]]]* + +// CHECK: ret void + #endif -- GitLab From 96af6760cdf721570c13b4aff35b11dcef5f043c Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Mon, 23 Oct 2017 21:31:05 +0000 Subject: [PATCH 0028/1682] [Driver] Use ld.lld directly for Fuchsia rather than passing flavor Passing a flavor to LLD requires command line argument, but if these are being passed through a response file, this will fail because LLD needs to know which driver to use before processing the response file. Use ld.lld directly instead to avoid this issue. Differential Revision: https://reviews.llvm.org/D39176 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316379 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Driver/ToolChains/Fuchsia.cpp | 6 ++---- lib/Driver/ToolChains/Fuchsia.h | 2 +- test/Driver/fuchsia.c | 7 +++---- test/Driver/fuchsia.cpp | 5 ++--- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/lib/Driver/ToolChains/Fuchsia.cpp b/lib/Driver/ToolChains/Fuchsia.cpp index 5cea62b750..10ee7b7829 100644 --- a/lib/Driver/ToolChains/Fuchsia.cpp +++ b/lib/Driver/ToolChains/Fuchsia.cpp @@ -44,10 +44,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.ClaimAllArgs(options::OPT_w); const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - if (llvm::sys::path::stem(Exec).equals_lower("lld")) { - CmdArgs.push_back("-flavor"); - CmdArgs.push_back("gnu"); - + if (llvm::sys::path::filename(Exec).equals_lower("ld.lld") || + llvm::sys::path::stem(Exec).equals_lower("ld.lld")) { CmdArgs.push_back("-z"); CmdArgs.push_back("rodynamic"); } diff --git a/lib/Driver/ToolChains/Fuchsia.h b/lib/Driver/ToolChains/Fuchsia.h index dab44a2b49..6d825fb817 100644 --- a/lib/Driver/ToolChains/Fuchsia.h +++ b/lib/Driver/ToolChains/Fuchsia.h @@ -82,7 +82,7 @@ public: llvm::opt::ArgStringList &CmdArgs) const override; const char *getDefaultLinker() const override { - return "lld"; + return "ld.lld"; } protected: diff --git a/test/Driver/fuchsia.c b/test/Driver/fuchsia.c index d3af79e506..3f5597c36e 100644 --- a/test/Driver/fuchsia.c +++ b/test/Driver/fuchsia.c @@ -1,16 +1,15 @@ // RUN: %clang %s -### -no-canonical-prefixes --target=x86_64-unknown-fuchsia \ -// RUN: --sysroot=%S/platform -fuse-ld=ld 2>&1 \ +// RUN: --sysroot=%S/platform 2>&1 \ // RUN: | FileCheck -check-prefixes=CHECK,CHECK-X86_64 %s // RUN: %clang %s -### -no-canonical-prefixes --target=aarch64-unknown-fuchsia \ -// RUN: --sysroot=%S/platform -fuse-ld=ld 2>&1 \ +// RUN: --sysroot=%S/platform 2>&1 \ // RUN: | FileCheck -check-prefixes=CHECK,CHECK-AARCH64 %s // CHECK: {{.*}}clang{{.*}}" "-cc1" // CHECK: "-munwind-tables" // CHECK: "-fuse-init-array" // CHECK: "-isysroot" "[[SYSROOT:[^"]+]]" // CHECK: "-internal-externc-isystem" "[[SYSROOT]]{{/|\\\\}}include" -// CHECK: {{.*}}lld{{.*}}" "-flavor" "gnu" -// CHECK: "-z" "rodynamic" +// CHECK: {{.*}}ld.lld{{.*}}" "-z" "rodynamic" // CHECK: "--sysroot=[[SYSROOT]]" // CHECK: "-pie" // CHECK: "--build-id" diff --git a/test/Driver/fuchsia.cpp b/test/Driver/fuchsia.cpp index ab0a901dac..cbd08adb44 100644 --- a/test/Driver/fuchsia.cpp +++ b/test/Driver/fuchsia.cpp @@ -1,13 +1,12 @@ // RUN: %clangxx %s -### -no-canonical-prefixes --target=x86_64-unknown-fuchsia \ -// RUN: --sysroot=%S/platform 2>&1 -fuse-ld=ld | FileCheck %s +// RUN: --sysroot=%S/platform 2>&1 | FileCheck %s // CHECK: {{.*}}clang{{.*}}" "-cc1" // CHECK: "-triple" "x86_64-fuchsia" // CHECK: "-fuse-init-array" // CHECK: "-isysroot" "[[SYSROOT:[^"]+]]" // CHECK: "-internal-isystem" "{{.*[/\\]}}x86_64-fuchsia{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}v1" // CHECK: "-internal-externc-isystem" "[[SYSROOT]]{{/|\\\\}}include" -// CHECK: {{.*}}lld{{.*}}" "-flavor" "gnu" -// CHECK: "-z" "rodynamic" +// CHECK: {{.*}}ld.lld{{.*}}" "-z" "rodynamic" // CHECK: "--sysroot=[[SYSROOT]]" // CHECK: "-pie" // CHECK: "--build-id" -- GitLab From b1ead8ba0f35dc3bf852be933dc2fe123fefa2ea Mon Sep 17 00:00:00 2001 From: Volodymyr Sapsai Date: Mon, 23 Oct 2017 22:01:41 +0000 Subject: [PATCH 0029/1682] [Sema] Add support for flexible array members in Obj-C. Allow Obj-C ivars with incomplete array type but only as the last ivar. Also add a requirement for ivars that contain a flexible array member to be at the end of class too. It is possible to add in a subclass another ivar at the end but we'll emit a warning in this case. Also we'll emit a warning if a variable sized ivar is declared in class extension or in implementation because subclasses won't know they should avoid adding new ivars. In ARC incomplete array objects are treated as __unsafe_unretained so require them to be marked as such. Prohibit synthesizing ivars with flexible array members because order of synthesized ivars is not obvious and tricky to control. Spelling out ivar explicitly gives control to developers and helps to avoid surprises with unexpected ivar ordering. For C and C++ changed diagnostic to tell explicitly a field is not the last one and point to the next field. It is not as useful as in Obj-C but it is an improvement and it is consistent with Obj-C. For C for unions emit more specific err_flexible_array_union instead of generic err_field_incomplete. rdar://problem/21054495 Reviewers: rjmccall, theraven Reviewed By: rjmccall Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D38773 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316381 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticGroups.td | 2 + include/clang/Basic/DiagnosticSemaKinds.td | 22 ++ lib/Sema/SemaDecl.cpp | 115 ++++---- lib/Sema/SemaDeclObjC.cpp | 112 ++++++++ lib/Sema/SemaObjCProperty.cpp | 8 + test/Sema/transparent-union.c | 2 +- test/SemaCXX/flexible-array-test.cpp | 5 + test/SemaObjC/flexible-array-arc.m | 36 +++ test/SemaObjC/flexible-array.m | 288 +++++++++++++++++++++ test/SemaObjC/ivar-sem-check-1.m | 5 +- test/SemaObjCXX/flexible-array.mm | 37 +++ 11 files changed, 577 insertions(+), 55 deletions(-) create mode 100644 test/SemaObjC/flexible-array-arc.m create mode 100644 test/SemaObjC/flexible-array.m create mode 100644 test/SemaObjCXX/flexible-array.mm diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 1896280761..4cceaf6ccc 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -374,6 +374,7 @@ def ObjCRootClass : DiagGroup<"objc-root-class">; def ObjCPointerIntrospectPerformSelector : DiagGroup<"deprecated-objc-pointer-introspection-performSelector">; def ObjCPointerIntrospect : DiagGroup<"deprecated-objc-pointer-introspection", [ObjCPointerIntrospectPerformSelector]>; def ObjCMultipleMethodNames : DiagGroup<"objc-multiple-method-names">; +def ObjCFlexibleArray : DiagGroup<"objc-flexible-array">; def OpenCLUnsupportedRGBA: DiagGroup<"opencl-unsupported-rgba">; def DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">; def ExplicitInitializeCall : DiagGroup<"explicit-initialize-call">; @@ -750,6 +751,7 @@ def Most : DiagGroup<"most", [ VolatileRegisterVar, ObjCMissingSuperCalls, ObjCDesignatedInit, + ObjCFlexibleArray, OverloadedVirtual, PrivateExtern, SelTypeCast, diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index ce79ac2e90..b1cba0655c 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -5222,6 +5222,28 @@ def ext_flexible_array_empty_aggregate_gnu : Extension< def ext_flexible_array_union_gnu : Extension< "flexible array member %0 in a union is a GNU extension">, InGroup; +def err_flexible_array_not_at_end : Error< + "flexible array member %0 with type %1 is not at the end of" + " %select{struct|interface|union|class|enum}2">; +def err_objc_variable_sized_type_not_at_end : Error< + "field %0 with variable sized type %1 is not at the end of class">; +def note_next_field_declaration : Note< + "next field declaration is here">; +def note_next_ivar_declaration : Note< + "next %select{instance variable declaration|synthesized instance variable}0" + " is here">; +def err_synthesize_variable_sized_ivar : Error< + "synthesized property with variable size type %0" + " requires an existing instance variable">; +def err_flexible_array_arc_retainable : Error< + "ARC forbids flexible array members with retainable object type">; +def warn_variable_sized_ivar_visibility : Warning< + "field %0 with variable sized type %1 is not visible to subclasses and" + " can conflict with their instance variables">, InGroup; +def warn_superclass_variable_sized_type_not_at_end : Warning< + "field %0 can overwrite instance variable %1 with variable sized type %2" + " in superclass %3">, InGroup; + let CategoryName = "ARC Semantic Issue" in { // ARC-mode diagnostics. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d75a469970..573c1af8d2 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -14997,6 +14997,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, // possibly recursively, a member that is such a structure) // shall not be a member of a structure or an element of an // array. + bool IsLastField = (i + 1 == Fields.end()); if (FDTy->isFunctionType()) { // Field declared as a function. Diag(FD->getLocation(), diag::err_field_declared_as_function) @@ -15004,60 +15005,70 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; - } else if (FDTy->isIncompleteArrayType() && Record && - ((i + 1 == Fields.end() && !Record->isUnion()) || - ((getLangOpts().MicrosoftExt || - getLangOpts().CPlusPlus) && - (i + 1 == Fields.end() || Record->isUnion())))) { - // Flexible array member. - // Microsoft and g++ is more permissive regarding flexible array. - // It will accept flexible array in union and also - // as the sole element of a struct/class. - unsigned DiagID = 0; - if (Record->isUnion()) - DiagID = getLangOpts().MicrosoftExt - ? diag::ext_flexible_array_union_ms - : getLangOpts().CPlusPlus - ? diag::ext_flexible_array_union_gnu - : diag::err_flexible_array_union; - else if (NumNamedMembers < 1) - DiagID = getLangOpts().MicrosoftExt - ? diag::ext_flexible_array_empty_aggregate_ms - : getLangOpts().CPlusPlus - ? diag::ext_flexible_array_empty_aggregate_gnu - : diag::err_flexible_array_empty_aggregate; - - if (DiagID) - Diag(FD->getLocation(), DiagID) << FD->getDeclName() - << Record->getTagKind(); - // While the layout of types that contain virtual bases is not specified - // by the C++ standard, both the Itanium and Microsoft C++ ABIs place - // virtual bases after the derived members. This would make a flexible - // array member declared at the end of an object not adjacent to the end - // of the type. - if (CXXRecordDecl *RD = dyn_cast(Record)) - if (RD->getNumVBases() != 0) - Diag(FD->getLocation(), diag::err_flexible_array_virtual_base) + } else if (FDTy->isIncompleteArrayType() && + (Record || isa(EnclosingDecl))) { + if (Record) { + // Flexible array member. + // Microsoft and g++ is more permissive regarding flexible array. + // It will accept flexible array in union and also + // as the sole element of a struct/class. + unsigned DiagID = 0; + if (!Record->isUnion() && !IsLastField) { + Diag(FD->getLocation(), diag::err_flexible_array_not_at_end) + << FD->getDeclName() << FD->getType() << Record->getTagKind(); + Diag((*(i + 1))->getLocation(), diag::note_next_field_declaration); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } else if (Record->isUnion()) + DiagID = getLangOpts().MicrosoftExt + ? diag::ext_flexible_array_union_ms + : getLangOpts().CPlusPlus + ? diag::ext_flexible_array_union_gnu + : diag::err_flexible_array_union; + else if (NumNamedMembers < 1) + DiagID = getLangOpts().MicrosoftExt + ? diag::ext_flexible_array_empty_aggregate_ms + : getLangOpts().CPlusPlus + ? diag::ext_flexible_array_empty_aggregate_gnu + : diag::err_flexible_array_empty_aggregate; + + if (DiagID) + Diag(FD->getLocation(), DiagID) << FD->getDeclName() + << Record->getTagKind(); + // While the layout of types that contain virtual bases is not specified + // by the C++ standard, both the Itanium and Microsoft C++ ABIs place + // virtual bases after the derived members. This would make a flexible + // array member declared at the end of an object not adjacent to the end + // of the type. + if (CXXRecordDecl *RD = dyn_cast(Record)) + if (RD->getNumVBases() != 0) + Diag(FD->getLocation(), diag::err_flexible_array_virtual_base) + << FD->getDeclName() << Record->getTagKind(); + if (!getLangOpts().C99) + Diag(FD->getLocation(), diag::ext_c99_flexible_array_member) << FD->getDeclName() << Record->getTagKind(); - if (!getLangOpts().C99) - Diag(FD->getLocation(), diag::ext_c99_flexible_array_member) - << FD->getDeclName() << Record->getTagKind(); - // If the element type has a non-trivial destructor, we would not - // implicitly destroy the elements, so disallow it for now. - // - // FIXME: GCC allows this. We should probably either implicitly delete - // the destructor of the containing class, or just allow this. - QualType BaseElem = Context.getBaseElementType(FD->getType()); - if (!BaseElem->isDependentType() && BaseElem.isDestructedType()) { - Diag(FD->getLocation(), diag::err_flexible_array_has_nontrivial_dtor) - << FD->getDeclName() << FD->getType(); - FD->setInvalidDecl(); - EnclosingDecl->setInvalidDecl(); - continue; + // If the element type has a non-trivial destructor, we would not + // implicitly destroy the elements, so disallow it for now. + // + // FIXME: GCC allows this. We should probably either implicitly delete + // the destructor of the containing class, or just allow this. + QualType BaseElem = Context.getBaseElementType(FD->getType()); + if (!BaseElem->isDependentType() && BaseElem.isDestructedType()) { + Diag(FD->getLocation(), diag::err_flexible_array_has_nontrivial_dtor) + << FD->getDeclName() << FD->getType(); + FD->setInvalidDecl(); + EnclosingDecl->setInvalidDecl(); + continue; + } + // Okay, we have a legal flexible array member at the end of the struct. + Record->setHasFlexibleArrayMember(true); + } else { + // In ObjCContainerDecl ivars with incomplete array type are accepted, + // unless they are followed by another ivar. That check is done + // elsewhere, after synthesized ivars are known. } - // Okay, we have a legal flexible array member at the end of the struct. - Record->setHasFlexibleArrayMember(true); } else if (!FDTy->isDependentType() && RequireCompleteType(FD->getLocation(), FD->getType(), diag::err_field_incomplete)) { @@ -15074,7 +15085,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, // If this is a struct/class and this is not the last element, reject // it. Note that GCC supports variable sized arrays in the middle of // structures. - if (i + 1 != Fields.end()) + if (!IsLastField) Diag(FD->getLocation(), diag::ext_variable_sized_type_in_struct) << FD->getDeclName() << FD->getType(); else { diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 607ffe984e..abdcc4da62 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -3721,6 +3721,26 @@ static void DiagnoseWeakIvars(Sema &S, ObjCImplementationDecl *ID) { } } +/// Diagnose attempts to use flexible array member with retainable object type. +static void DiagnoseRetainableFlexibleArrayMember(Sema &S, + ObjCInterfaceDecl *ID) { + if (!S.getLangOpts().ObjCAutoRefCount) + return; + + for (auto ivar = ID->all_declared_ivar_begin(); ivar; + ivar = ivar->getNextIvar()) { + if (ivar->isInvalidDecl()) + continue; + QualType IvarTy = ivar->getType(); + if (IvarTy->isIncompleteArrayType() && + (IvarTy.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) && + IvarTy->isObjCLifetimeType()) { + S.Diag(ivar->getLocation(), diag::err_flexible_array_arc_retainable); + ivar->setInvalidDecl(); + } + } +} + Sema::ObjCContainerKind Sema::getObjCContainerKind() const { switch (CurContext->getDeclKind()) { case Decl::ObjCInterface: @@ -3741,6 +3761,96 @@ Sema::ObjCContainerKind Sema::getObjCContainerKind() const { } } +static bool IsVariableSizedType(QualType T) { + if (T->isIncompleteArrayType()) + return true; + const auto *RecordTy = T->getAs(); + return (RecordTy && RecordTy->getDecl()->hasFlexibleArrayMember()); +} + +static void DiagnoseVariableSizedIvars(Sema &S, ObjCContainerDecl *OCD) { + ObjCInterfaceDecl *IntfDecl = nullptr; + ObjCInterfaceDecl::ivar_range Ivars = llvm::make_range( + ObjCInterfaceDecl::ivar_iterator(), ObjCInterfaceDecl::ivar_iterator()); + if ((IntfDecl = dyn_cast(OCD))) { + Ivars = IntfDecl->ivars(); + } else if (auto *ImplDecl = dyn_cast(OCD)) { + IntfDecl = ImplDecl->getClassInterface(); + Ivars = ImplDecl->ivars(); + } else if (auto *CategoryDecl = dyn_cast(OCD)) { + if (CategoryDecl->IsClassExtension()) { + IntfDecl = CategoryDecl->getClassInterface(); + Ivars = CategoryDecl->ivars(); + } + } + + // Check if variable sized ivar is in interface and visible to subclasses. + if (!isa(OCD)) { + for (auto ivar : Ivars) { + if (!ivar->isInvalidDecl() && IsVariableSizedType(ivar->getType())) { + S.Diag(ivar->getLocation(), diag::warn_variable_sized_ivar_visibility) + << ivar->getDeclName() << ivar->getType(); + } + } + } + + // Subsequent checks require interface decl. + if (!IntfDecl) + return; + + // Check if variable sized ivar is followed by another ivar. + for (ObjCIvarDecl *ivar = IntfDecl->all_declared_ivar_begin(); ivar; + ivar = ivar->getNextIvar()) { + if (ivar->isInvalidDecl() || !ivar->getNextIvar()) + continue; + QualType IvarTy = ivar->getType(); + bool IsInvalidIvar = false; + if (IvarTy->isIncompleteArrayType()) { + S.Diag(ivar->getLocation(), diag::err_flexible_array_not_at_end) + << ivar->getDeclName() << IvarTy + << TTK_Class; // Use "class" for Obj-C. + IsInvalidIvar = true; + } else if (const RecordType *RecordTy = IvarTy->getAs()) { + if (RecordTy->getDecl()->hasFlexibleArrayMember()) { + S.Diag(ivar->getLocation(), + diag::err_objc_variable_sized_type_not_at_end) + << ivar->getDeclName() << IvarTy; + IsInvalidIvar = true; + } + } + if (IsInvalidIvar) { + S.Diag(ivar->getNextIvar()->getLocation(), + diag::note_next_ivar_declaration) + << ivar->getNextIvar()->getSynthesize(); + ivar->setInvalidDecl(); + } + } + + // Check if ObjC container adds ivars after variable sized ivar in superclass. + // Perform the check only if OCD is the first container to declare ivars to + // avoid multiple warnings for the same ivar. + ObjCIvarDecl *FirstIvar = + (Ivars.begin() == Ivars.end()) ? nullptr : *Ivars.begin(); + if (FirstIvar && (FirstIvar == IntfDecl->all_declared_ivar_begin())) { + const ObjCInterfaceDecl *SuperClass = IntfDecl->getSuperClass(); + while (SuperClass && SuperClass->ivar_empty()) + SuperClass = SuperClass->getSuperClass(); + if (SuperClass) { + auto IvarIter = SuperClass->ivar_begin(); + std::advance(IvarIter, SuperClass->ivar_size() - 1); + const ObjCIvarDecl *LastIvar = *IvarIter; + if (IsVariableSizedType(LastIvar->getType())) { + S.Diag(FirstIvar->getLocation(), + diag::warn_superclass_variable_sized_type_not_at_end) + << FirstIvar->getDeclName() << LastIvar->getDeclName() + << LastIvar->getType() << SuperClass->getDeclName(); + S.Diag(LastIvar->getLocation(), diag::note_entity_declared_at) + << LastIvar->getDeclName(); + } + } + } +} + // Note: For class/category implementations, allMethods is always null. Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef allMethods, ArrayRef allTUVars) { @@ -3872,6 +3982,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef allMethods, if (IDecl->hasDesignatedInitializers()) DiagnoseMissingDesignatedInitOverrides(IC, IDecl); DiagnoseWeakIvars(*this, IC); + DiagnoseRetainableFlexibleArrayMember(*this, IDecl); bool HasRootClassAttr = IDecl->hasAttr(); if (IDecl->getSuperClass() == nullptr) { @@ -3941,6 +4052,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef allMethods, } } } + DiagnoseVariableSizedIvars(*this, OCD); if (isInterfaceDeclKind) { // Reject invalid vardecls. for (unsigned i = 0, e = allTUVars.size(); i != e; i++) { diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 9c61d45158..ea5b1da46f 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -1290,6 +1290,14 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // An abstract type is as bad as an incomplete type. CompleteTypeErr = true; } + if (!CompleteTypeErr) { + const RecordType *RecordTy = PropertyIvarType->getAs(); + if (RecordTy && RecordTy->getDecl()->hasFlexibleArrayMember()) { + Diag(PropertyIvarLoc, diag::err_synthesize_variable_sized_ivar) + << PropertyIvarType; + CompleteTypeErr = true; // suppress later diagnostics about the ivar + } + } if (CompleteTypeErr) Ivar->setInvalidDecl(); ClassImpDecl->addDecl(Ivar); diff --git a/test/Sema/transparent-union.c b/test/Sema/transparent-union.c index dfbadcfe62..0481127674 100644 --- a/test/Sema/transparent-union.c +++ b/test/Sema/transparent-union.c @@ -102,7 +102,7 @@ union pr15134v2 { union pr30520v { void b; } __attribute__((transparent_union)); // expected-error {{field has incomplete type 'void'}} -union pr30520a { int b[]; } __attribute__((transparent_union)); // expected-error {{field has incomplete type 'int []'}} +union pr30520a { int b[]; } __attribute__((transparent_union)); // expected-error {{flexible array member 'b' in a union is not allowed}} // expected-note@+1 2 {{forward declaration of 'struct stb'}} union pr30520s { struct stb b; } __attribute__((transparent_union)); // expected-error {{field has incomplete type 'struct stb'}} diff --git a/test/SemaCXX/flexible-array-test.cpp b/test/SemaCXX/flexible-array-test.cpp index 2d74fa5245..f2105ca361 100644 --- a/test/SemaCXX/flexible-array-test.cpp +++ b/test/SemaCXX/flexible-array-test.cpp @@ -66,6 +66,11 @@ union B { char c[]; }; +class C { + char c[]; // expected-error {{flexible array member 'c' with type 'char []' is not at the end of class}} + int s; // expected-note {{next field declaration is here}} +}; + namespace rdar9065507 { struct StorageBase { diff --git a/test/SemaObjC/flexible-array-arc.m b/test/SemaObjC/flexible-array-arc.m new file mode 100644 index 0000000000..1490329b18 --- /dev/null +++ b/test/SemaObjC/flexible-array-arc.m @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class -DNOARC %s +#ifdef NOARC +// expected-no-diagnostics +#endif + +@interface RetainableArray { + id flexible[]; +#ifndef NOARC + // expected-error@-2 {{ARC forbids flexible array members with retainable object type}} +#endif +} +@end +@implementation RetainableArray +@end + +// Emit diagnostic only if have @implementation. +@interface RetainableArrayWithoutImpl { + id flexible[]; +} +@end + +// With ARC flexible array member objects can be only __unsafe_unretained +@interface UnsafeUnretainedArray { + __unsafe_unretained id flexible[]; +} +@end +@implementation UnsafeUnretainedArray +@end + +@interface NotObjCLifetimeTypeArray { + char flexible[]; +} +@end +@implementation NotObjCLifetimeTypeArray +@end diff --git a/test/SemaObjC/flexible-array.m b/test/SemaObjC/flexible-array.m new file mode 100644 index 0000000000..68e32d851f --- /dev/null +++ b/test/SemaObjC/flexible-array.m @@ -0,0 +1,288 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s + +// # Flexible array member. +// ## Instance variables only in interface. +@interface LastIvar { + char flexible[]; +} +@end + +@interface NotLastIvar { + char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}} + int last; // expected-note {{next instance variable declaration is here}} +} +@end + +// ## Instance variables in implementation. +@interface LastIvarInImpl +@end +@implementation LastIvarInImpl { + char flexible[]; // expected-warning {{field 'flexible' with variable sized type 'char []' is not visible to subclasses and can conflict with their instance variables}} +} +@end + +@interface NotLastIvarInImpl +@end +@implementation NotLastIvarInImpl { + char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}} + // expected-warning@-1 {{field 'flexible' with variable sized type 'char []' is not visible to subclasses and can conflict with their instance variables}} + int last; // expected-note {{next instance variable declaration is here}} +} +@end + +@implementation NotLastIvarInImplWithoutInterface { // expected-warning {{cannot find interface declaration for 'NotLastIvarInImplWithoutInterface'}} + char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}} + // expected-warning@-1 {{field 'flexible' with variable sized type 'char []' is not visible to subclasses and can conflict with their instance variables}} + int last; // expected-note {{next instance variable declaration is here}} +} +@end + +@interface LastIvarInClass_OtherIvarInImpl { + char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}} +} +@end +@implementation LastIvarInClass_OtherIvarInImpl { + int last; // expected-note {{next instance variable declaration is here}} +} +@end + +// ## Non-instance variables in implementation. +@interface LastIvarInClass_UnrelatedVarInImpl { + char flexible[]; +} +@end +@implementation LastIvarInClass_UnrelatedVarInImpl +int nonIvar; +@end + +// ## Instance variables in class extension. +@interface LastIvarInExtension +@end +@interface LastIvarInExtension() { + char flexible[]; // expected-warning {{field 'flexible' with variable sized type 'char []' is not visible to subclasses and can conflict with their instance variables}} +} +@end + +@interface NotLastIvarInExtension +@end +@interface NotLastIvarInExtension() { + char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}} + // expected-warning@-1 {{field 'flexible' with variable sized type 'char []' is not visible to subclasses and can conflict with their instance variables}} + int last; // expected-note {{next instance variable declaration is here}} +} +@end + +@interface LastIvarInClass_OtherIvarInExtension { + char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}} +} +@end +@interface LastIvarInClass_OtherIvarInExtension() { + int last; // expected-note {{next instance variable declaration is here}} +} +@end + +@interface LastIvarInExtension_OtherIvarInExtension +@end +@interface LastIvarInExtension_OtherIvarInExtension() { + int last; // expected-note {{next instance variable declaration is here}} +} +@end +@interface LastIvarInExtension_OtherIvarInExtension() +// Extension without ivars to test we see through such extensions. +@end +@interface LastIvarInExtension_OtherIvarInExtension() { + char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}} + // expected-warning@-1 {{field 'flexible' with variable sized type 'char []' is not visible to subclasses and can conflict with their instance variables}} +} +@end + +@interface LastIvarInExtension_OtherIvarInImpl +@end +@interface LastIvarInExtension_OtherIvarInImpl() { + char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}} + // expected-warning@-1 {{field 'flexible' with variable sized type 'char []' is not visible to subclasses and can conflict with their instance variables}} +} +@end +@implementation LastIvarInExtension_OtherIvarInImpl { + int last; // expected-note {{next instance variable declaration is here}} +} +@end + +// ## Instance variables in named categories. +@interface IvarInNamedCategory +@end +@interface IvarInNamedCategory(Category) { + char flexible[]; // expected-error {{instance variables may not be placed in categories}} +} +@end + +// ## Synthesized instance variable. +@interface LastIvarAndProperty { + char _flexible[]; +} +@property char flexible[]; // expected-error {{property cannot have array or function type 'char []'}} +@end + +// ## Synthesize other instance variables. +@interface LastIvar_ExplicitlyNamedPropertyBackingIvarPreceding { + int _elementsCount; + char flexible[]; +} +@property int count; +@end +@implementation LastIvar_ExplicitlyNamedPropertyBackingIvarPreceding +@synthesize count = _elementsCount; +@end + +@interface LastIvar_ImplicitlyNamedPropertyBackingIvarPreceding { + int count; + char flexible[]; +} +@property int count; +@end +@implementation LastIvar_ImplicitlyNamedPropertyBackingIvarPreceding +@synthesize count; +@end + +@interface NotLastIvar_ExplicitlyNamedPropertyBackingIvarLast { + char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}} +} +@property int count; +@end +@implementation NotLastIvar_ExplicitlyNamedPropertyBackingIvarLast +@synthesize count = _elementsCount; // expected-note {{next synthesized instance variable is here}} +@end + +@interface NotLastIvar_ImplicitlyNamedPropertyBackingIvarLast { + char flexible[]; // expected-error {{flexible array member 'flexible' with type 'char []' is not at the end of class}} +} +@property int count; // expected-note {{next synthesized instance variable is here}} +@end +@implementation NotLastIvar_ImplicitlyNamedPropertyBackingIvarLast +// Test auto-synthesize. +//@synthesize count; +@end + + +// # Variable sized types. +struct Packet { + unsigned int size; + char data[]; +}; + +// ## Instance variables only in interface. +@interface LastStructIvar { + struct Packet flexible; +} +@end + +@interface NotLastStructIvar { + struct Packet flexible; // expected-error {{field 'flexible' with variable sized type 'struct Packet' is not at the end of class}} + int last; // expected-note {{next instance variable declaration is here}} +} +@end + +// ## Instance variables in implementation. +@interface LastStructIvarInImpl +@end +@implementation LastStructIvarInImpl { + struct Packet flexible; // expected-warning {{field 'flexible' with variable sized type 'struct Packet' is not visible to subclasses and can conflict with their instance variables}} +} +@end + +@interface NotLastStructIvarInImpl +@end +@implementation NotLastStructIvarInImpl { + struct Packet flexible; // expected-error {{field 'flexible' with variable sized type 'struct Packet' is not at the end of class}} + // expected-warning@-1 {{field 'flexible' with variable sized type 'struct Packet' is not visible to subclasses and can conflict with their instance variables}} + int last; // expected-note {{next instance variable declaration is here}} +} +@end + +@interface LastStructIvarInClass_OtherIvarInImpl { + struct Packet flexible; // expected-error {{field 'flexible' with variable sized type 'struct Packet' is not at the end of class}} +} +@end +@implementation LastStructIvarInClass_OtherIvarInImpl { + int last; // expected-note {{next instance variable declaration is here}} +} +@end + +// ## Synthesized instance variable. +@interface LastSynthesizeStructIvar +@property int first; +@property struct Packet flexible; // expected-error {{synthesized property with variable size type 'struct Packet' requires an existing instance variable}} +@end +@implementation LastSynthesizeStructIvar +@end + +@interface NotLastSynthesizeStructIvar +@property struct Packet flexible; // expected-error {{synthesized property with variable size type 'struct Packet' requires an existing instance variable}} +@property int last; +@end +@implementation NotLastSynthesizeStructIvar +@end + +@interface LastStructIvarWithExistingIvarAndSynthesizedProperty { + struct Packet _flexible; +} +@property struct Packet flexible; +@end +@implementation LastStructIvarWithExistingIvarAndSynthesizedProperty +@end + + +// # Subclasses. +@interface FlexibleArrayMemberBase { + char flexible[]; // expected-note6 {{'flexible' declared here}} +} +@end + +@interface NoIvarAdditions : FlexibleArrayMemberBase +@end +@implementation NoIvarAdditions +@end + +@interface AddedIvarInInterface : FlexibleArrayMemberBase { + int last; // expected-warning {{field 'last' can overwrite instance variable 'flexible' with variable sized type 'char []' in superclass 'FlexibleArrayMemberBase'}} +} +@end + +@interface AddedIvarInImplementation : FlexibleArrayMemberBase +@end +@implementation AddedIvarInImplementation { + int last; // expected-warning {{field 'last' can overwrite instance variable 'flexible' with variable sized type 'char []' in superclass 'FlexibleArrayMemberBase'}} +} +@end + +@interface AddedIvarInExtension : FlexibleArrayMemberBase +@end +@interface AddedIvarInExtension() { + int last; // expected-warning {{field 'last' can overwrite instance variable 'flexible' with variable sized type 'char []' in superclass 'FlexibleArrayMemberBase'}} +} +@end + +@interface SynthesizedIvar : FlexibleArrayMemberBase +@property int count; +@end +@implementation SynthesizedIvar +@synthesize count; // expected-warning {{field 'count' can overwrite instance variable 'flexible' with variable sized type 'char []' in superclass 'FlexibleArrayMemberBase'}} +@end + +@interface WarnInSubclassOnlyOnce : FlexibleArrayMemberBase { + int last; // expected-warning {{field 'last' can overwrite instance variable 'flexible' with variable sized type 'char []' in superclass 'FlexibleArrayMemberBase'}} +} +@end +@interface WarnInSubclassOnlyOnce() { + int laster; +} +@end +@implementation WarnInSubclassOnlyOnce { + int lastest; +} +@end + +@interface AddedIvarInSubSubClass : NoIvarAdditions { + int last; // expected-warning {{field 'last' can overwrite instance variable 'flexible' with variable sized type 'char []' in superclass 'FlexibleArrayMemberBase'}} +} +@end diff --git a/test/SemaObjC/ivar-sem-check-1.m b/test/SemaObjC/ivar-sem-check-1.m index de038f5487..48e0a54b62 100644 --- a/test/SemaObjC/ivar-sem-check-1.m +++ b/test/SemaObjC/ivar-sem-check-1.m @@ -6,14 +6,15 @@ typedef int FOO(); @interface INTF { struct F {} JJ; - int arr[]; // expected-error {{field has incomplete type}} + int arr[]; // expected-error {{flexible array member 'arr' with type 'int []' is not at the end of class}} struct S IC; // expected-error {{field has incomplete type}} + // expected-note@-1 {{next instance variable declaration is here}} struct T { // expected-note {{previous definition is here}} struct T {} X; // expected-error {{nested redefinition of 'T'}} }YYY; FOO BADFUNC; // expected-error {{field 'BADFUNC' declared as a function}} int kaka; // expected-note {{previous declaration is here}} int kaka; // expected-error {{duplicate member 'kaka'}} - char ch[]; // expected-error {{field has incomplete type}} + char ch[]; } @end diff --git a/test/SemaObjCXX/flexible-array.mm b/test/SemaObjCXX/flexible-array.mm new file mode 100644 index 0000000000..5537876c30 --- /dev/null +++ b/test/SemaObjCXX/flexible-array.mm @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s + +// Test only flexible array member functionality specific to C++. + +union VariableSizeUnion { + int s; + char c[]; +}; + +@interface LastUnionIvar { + VariableSizeUnion flexible; +} +@end + +@interface NotLastUnionIvar { + VariableSizeUnion flexible; // expected-error {{field 'flexible' with variable sized type 'VariableSizeUnion' is not at the end of class}} + int last; // expected-note {{next instance variable declaration is here}} +} +@end + + +class VariableSizeClass { +public: + int s; + char c[]; +}; + +@interface LastClassIvar { + VariableSizeClass flexible; +} +@end + +@interface NotLastClassIvar { + VariableSizeClass flexible; // expected-error {{field 'flexible' with variable sized type 'VariableSizeClass' is not at the end of class}} + int last; // expected-note {{next instance variable declaration is here}} +} +@end -- GitLab From 117339c38e266bf28c69d0bf29d35cb5ca79e2d8 Mon Sep 17 00:00:00 2001 From: Alexander Shaposhnikov Date: Mon, 23 Oct 2017 23:46:06 +0000 Subject: [PATCH 0030/1682] [analyzer] Fix handling of labels in getLValueElement In getLValueElement Base may represent the address of a label (as in the newly-added test case), in this case it's not a loc::MemRegionVal and Base.castAs() triggers an assert, this diff makes getLValueElement return UnknownVal instead. Differential revision: https://reviews.llvm.org/D39174 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316399 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/StaticAnalyzer/Core/Store.cpp | 5 ++++- test/Analysis/ptr-arith.c | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp index 1af49f68cc..173fdd8d00 100644 --- a/lib/StaticAnalyzer/Core/Store.cpp +++ b/lib/StaticAnalyzer/Core/Store.cpp @@ -440,7 +440,10 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset, // value. See also the similar FIXME in getLValueFieldOrIvar(). if (Base.isUnknownOrUndef() || Base.getAs()) return Base; - + + if (Base.getAs()) + return UnknownVal(); + const SubRegion *BaseRegion = Base.castAs().getRegionAs(); diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c index b78ec503a1..93cb4ee9a6 100644 --- a/test/Analysis/ptr-arith.c +++ b/test/Analysis/ptr-arith.c @@ -342,3 +342,8 @@ void negativeIndex(char *str) { clang_analyzer_eval(*ptr3 == 'a'); // expected-warning{{UNKNOWN}} } +void test_no_crash_on_pointer_to_label() { + char *a = &&label; + a[0] = 0; +label:; +} -- GitLab From 2b1d1f02e9ceb837f16cf85447f8211f331954b1 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Mon, 23 Oct 2017 23:59:52 +0000 Subject: [PATCH 0031/1682] [Analyzer] Do not use static storage to for implementations created in BodyFarm.cpp Differential Revision: https://reviews.llvm.org/D39208 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316400 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Analysis/AnalysisDeclContext.h | 18 +++++--- {lib => include/clang}/Analysis/BodyFarm.h | 8 ++-- lib/Analysis/AnalysisDeclContext.cpp | 42 ++++++++---------- lib/Analysis/BodyFarm.cpp | 2 +- lib/StaticAnalyzer/Core/AnalysisManager.cpp | 46 ++++++++------------ 5 files changed, 56 insertions(+), 60 deletions(-) rename {lib => include/clang}/Analysis/BodyFarm.h (93%) diff --git a/include/clang/Analysis/AnalysisDeclContext.h b/include/clang/Analysis/AnalysisDeclContext.h index ebec0d26ba..1486071891 100644 --- a/include/clang/Analysis/AnalysisDeclContext.h +++ b/include/clang/Analysis/AnalysisDeclContext.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_ANALYSIS_ANALYSISDECLCONTEXT_H #include "clang/AST/Decl.h" +#include "clang/Analysis/BodyFarm.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/CodeInjector.h" #include "llvm/ADT/DenseMap.h" @@ -409,6 +410,7 @@ class AnalysisDeclContextManager { typedef llvm::DenseMap> ContextMap; + ASTContext &ASTCtx; ContextMap Contexts; LocationContextManager LocContexts; CFG::BuildOptions cfgBuildOptions; @@ -416,22 +418,25 @@ class AnalysisDeclContextManager { /// Pointer to an interface that can provide function bodies for /// declarations from external source. std::unique_ptr Injector; - + + /// Pointer to a factory for creating and caching implementations for common + /// methods during the analysis. + BodyFarm *BdyFrm = nullptr; + /// Flag to indicate whether or not bodies should be synthesized /// for well-known functions. bool SynthesizeBodies; public: - AnalysisDeclContextManager(bool useUnoptimizedCFG = false, + AnalysisDeclContextManager(ASTContext &ASTCtx, bool useUnoptimizedCFG = false, bool addImplicitDtors = false, bool addInitializers = false, bool addTemporaryDtors = false, - bool addLifetime = false, - bool addLoopExit = false, + bool addLifetime = false, bool addLoopExit = false, bool synthesizeBodies = false, bool addStaticInitBranches = false, bool addCXXNewAllocator = true, - CodeInjector* injector = nullptr); + CodeInjector *injector = nullptr); ~AnalysisDeclContextManager(); @@ -472,6 +477,9 @@ public: return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx); } + /// Get and lazily create a {@code BodyFarm} instance. + BodyFarm *getBodyFarm(); + /// Discard all previously created AnalysisDeclContexts. void clear(); diff --git a/lib/Analysis/BodyFarm.h b/include/clang/Analysis/BodyFarm.h similarity index 93% rename from lib/Analysis/BodyFarm.h rename to include/clang/Analysis/BodyFarm.h index edbe996246..14cf2624b8 100644 --- a/lib/Analysis/BodyFarm.h +++ b/include/clang/Analysis/BodyFarm.h @@ -28,11 +28,11 @@ class ObjCMethodDecl; class ObjCPropertyDecl; class Stmt; class CodeInjector; - + class BodyFarm { public: BodyFarm(ASTContext &C, CodeInjector *injector) : C(C), Injector(injector) {} - + /// Factory method for creating bodies for ordinary functions. Stmt *getBody(const FunctionDecl *D); @@ -40,12 +40,12 @@ public: Stmt *getBody(const ObjCMethodDecl *D); private: - typedef llvm::DenseMap > BodyMap; + typedef llvm::DenseMap> BodyMap; ASTContext &C; BodyMap Bodies; CodeInjector *Injector; }; -} +} // namespace clang #endif diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp index 73eb142f97..2171194edc 100644 --- a/lib/Analysis/AnalysisDeclContext.cpp +++ b/lib/Analysis/AnalysisDeclContext.cpp @@ -13,7 +13,6 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/AnalysisDeclContext.h" -#include "BodyFarm.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" @@ -23,6 +22,7 @@ #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/Analyses/PseudoConstantAnalysis.h" +#include "clang/Analysis/BodyFarm.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/CFGStmtMap.h" #include "clang/Analysis/Support/BumpVector.h" @@ -63,18 +63,12 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs; } -AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG, - bool addImplicitDtors, - bool addInitializers, - bool addTemporaryDtors, - bool addLifetime, - bool addLoopExit, - bool synthesizeBodies, - bool addStaticInitBranch, - bool addCXXNewAllocator, - CodeInjector *injector) - : Injector(injector), SynthesizeBodies(synthesizeBodies) -{ +AnalysisDeclContextManager::AnalysisDeclContextManager( + ASTContext &ASTCtx, bool useUnoptimizedCFG, bool addImplicitDtors, + bool addInitializers, bool addTemporaryDtors, bool addLifetime, + bool addLoopExit, bool synthesizeBodies, bool addStaticInitBranch, + bool addCXXNewAllocator, CodeInjector *injector) + : ASTCtx(ASTCtx), Injector(injector), SynthesizeBodies(synthesizeBodies) { cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG; cfgBuildOptions.AddImplicitDtors = addImplicitDtors; cfgBuildOptions.AddInitializers = addInitializers; @@ -87,11 +81,6 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG, void AnalysisDeclContextManager::clear() { Contexts.clear(); } -static BodyFarm &getBodyFarm(ASTContext &C, CodeInjector *injector = nullptr) { - static BodyFarm *BF = new BodyFarm(C, injector); - return *BF; -} - Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const { IsAutosynthesized = false; if (const FunctionDecl *FD = dyn_cast(D)) { @@ -99,8 +88,7 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const { if (auto *CoroBody = dyn_cast_or_null(Body)) Body = CoroBody->getBody(); if (Manager && Manager->synthesizeBodies()) { - Stmt *SynthesizedBody = - getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(FD); + Stmt *SynthesizedBody = Manager->getBodyFarm()->getBody(FD); if (SynthesizedBody) { Body = SynthesizedBody; IsAutosynthesized = true; @@ -111,8 +99,7 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const { else if (const ObjCMethodDecl *MD = dyn_cast(D)) { Stmt *Body = MD->getBody(); if (Manager && Manager->synthesizeBodies()) { - Stmt *SynthesizedBody = - getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(MD); + Stmt *SynthesizedBody = Manager->getBodyFarm()->getBody(MD); if (SynthesizedBody) { Body = SynthesizedBody; IsAutosynthesized = true; @@ -317,6 +304,12 @@ AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) { return AC.get(); } +BodyFarm *AnalysisDeclContextManager::getBodyFarm() { + if (!BdyFrm) + BdyFrm = new BodyFarm(ASTCtx, Injector.get()); + return BdyFrm; +} + const StackFrameContext * AnalysisDeclContext::getStackFrame(LocationContext const *Parent, const Stmt *S, const CFGBlock *Blk, unsigned Idx) { @@ -610,7 +603,10 @@ AnalysisDeclContext::~AnalysisDeclContext() { } } -AnalysisDeclContextManager::~AnalysisDeclContextManager() {} +AnalysisDeclContextManager::~AnalysisDeclContextManager() { + if (!BdyFrm) + delete BdyFrm; +} LocationContext::~LocationContext() {} diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp index 6a8b529bba..dd348847b3 100644 --- a/lib/Analysis/BodyFarm.cpp +++ b/lib/Analysis/BodyFarm.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "BodyFarm.h" +#include "clang/Analysis/BodyFarm.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp index b7e2c277ef..1cc08f0d9f 100644 --- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -14,33 +14,25 @@ using namespace ento; void AnalysisManager::anchor() { } -AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, - const LangOptions &lang, - const PathDiagnosticConsumers &PDC, - StoreManagerCreator storemgr, - ConstraintManagerCreator constraintmgr, - CheckerManager *checkerMgr, - AnalyzerOptions &Options, - CodeInjector *injector) - : AnaCtxMgr(Options.UnoptimizedCFG, - Options.includeImplicitDtorsInCFG(), - /*AddInitializers=*/true, - Options.includeTemporaryDtorsInCFG(), - Options.includeLifetimeInCFG(), - // Adding LoopExit elements to the CFG is a requirement for loop - // unrolling. - Options.includeLoopExitInCFG() || Options.shouldUnrollLoops(), - Options.shouldSynthesizeBodies(), - Options.shouldConditionalizeStaticInitializers(), - /*addCXXNewAllocator=*/true, - injector), - Ctx(ctx), - Diags(diags), - LangOpts(lang), - PathConsumers(PDC), - CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), - CheckerMgr(checkerMgr), - options(Options) { +AnalysisManager::AnalysisManager( + ASTContext &ASTCtx, DiagnosticsEngine &diags, const LangOptions &lang, + const PathDiagnosticConsumers &PDC, StoreManagerCreator storemgr, + ConstraintManagerCreator constraintmgr, CheckerManager *checkerMgr, + AnalyzerOptions &Options, CodeInjector *injector) + : AnaCtxMgr(ASTCtx, Options.UnoptimizedCFG, + Options.includeImplicitDtorsInCFG(), + /*AddInitializers=*/true, Options.includeTemporaryDtorsInCFG(), + Options.includeLifetimeInCFG(), + // Adding LoopExit elements to the CFG is a requirement for loop + // unrolling. + Options.includeLoopExitInCFG() || Options.shouldUnrollLoops(), + Options.shouldSynthesizeBodies(), + Options.shouldConditionalizeStaticInitializers(), + /*addCXXNewAllocator=*/true, + injector), + Ctx(ASTCtx), Diags(diags), LangOpts(lang), PathConsumers(PDC), + CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), + CheckerMgr(checkerMgr), options(Options) { AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); } -- GitLab From 68518a40c274d4ee6ecad035363ac6a1040b617f Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Tue, 24 Oct 2017 00:13:18 +0000 Subject: [PATCH 0032/1682] [Analyzer] Handle implicit function reference in bodyfarming std::call_once Differential Revision: https://reviews.llvm.org/D39201 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316402 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/BodyFarm.cpp | 28 ++++++++++++++++++++-------- test/Analysis/call_once.cpp | 13 +++++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp index dd348847b3..8a56b761ec 100644 --- a/lib/Analysis/BodyFarm.cpp +++ b/lib/Analysis/BodyFarm.cpp @@ -253,13 +253,23 @@ static CallExpr *create_call_once_funcptr_call(ASTContext &C, ASTMaker M, const ParmVarDecl *Callback, ArrayRef CallArgs) { - return new (C) CallExpr( - /*ASTContext=*/C, - /*StmtClass=*/M.makeLvalueToRvalue(/*Expr=*/Callback), - /*args=*/CallArgs, - /*QualType=*/C.VoidTy, - /*ExprValueType=*/VK_RValue, - /*SourceLocation=*/SourceLocation()); + QualType Ty = Callback->getType(); + DeclRefExpr *Call = M.makeDeclRefExpr(Callback); + CastKind CK; + if (Ty->isRValueReferenceType()) { + CK = CK_LValueToRValue; + } else { + assert(Ty->isLValueReferenceType()); + CK = CK_FunctionToPointerDecay; + Ty = C.getPointerType(Ty.getNonReferenceType()); + } + + return new (C) + CallExpr(C, M.makeImplicitCast(Call, Ty.getNonReferenceType(), CK), + /*args=*/CallArgs, + /*QualType=*/C.VoidTy, + /*ExprValueType=*/VK_RValue, + /*SourceLocation=*/SourceLocation()); } static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M, @@ -366,9 +376,11 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { CallbackFunctionType = CallbackRecordDecl->getLambdaCallOperator() ->getType() ->getAs(); - } else { + } else if (!CallbackType->getPointeeType().isNull()) { CallbackFunctionType = CallbackType->getPointeeType()->getAs(); + } else { + CallbackFunctionType = CallbackType->getAs(); } if (!CallbackFunctionType) diff --git a/test/Analysis/call_once.cpp b/test/Analysis/call_once.cpp index db701457f6..2154be6f48 100644 --- a/test/Analysis/call_once.cpp +++ b/test/Analysis/call_once.cpp @@ -290,3 +290,16 @@ void test_mutator_noref() { std::call_once(flag, &fail_mutator, a); clang_analyzer_eval(a == 42); // expected-warning{{FALSE}} } + +// Function is implicitly treated as a function pointer +// even when an ampersand is not explicitly set. +void callbackn(int ¶m) { + param = 42; +}; +void test_implicit_funcptr() { + int x = 0; + static std::once_flag flagn; + + std::call_once(flagn, callbackn, x); + clang_analyzer_eval(x == 42); // expected-warning{{TRUE}} +} -- GitLab From 9f1735d6ac75bdf3258a345f00653b637a786b3d Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Tue, 24 Oct 2017 01:09:43 +0000 Subject: [PATCH 0033/1682] [Analyzer] Fix for the memory leak: fix typo in if-statement. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316403 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/AnalysisDeclContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp index 2171194edc..4408a0e0e4 100644 --- a/lib/Analysis/AnalysisDeclContext.cpp +++ b/lib/Analysis/AnalysisDeclContext.cpp @@ -604,7 +604,7 @@ AnalysisDeclContext::~AnalysisDeclContext() { } AnalysisDeclContextManager::~AnalysisDeclContextManager() { - if (!BdyFrm) + if (BdyFrm) delete BdyFrm; } -- GitLab From fbbb8c17f50e6bb450a12965d30ac47a12c9aa58 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Tue, 24 Oct 2017 01:39:56 +0000 Subject: [PATCH 0034/1682] Fix template parameter default args missed if redecled This bug was found via self-build on lld, and worked around here: https://reviews.llvm.org/rL316180 The issue is that the 'using' causes the lookup to pick up the first decl. However, when setting inherited default parameters, we only update 'forward', not 'backward'. SO, only the newest param list has all the information about the default arguments. This patch ensures that the list of parameters we look through checks the newest decl's template parameter list so it doesn't miss a default. Differential Revision: https://reviews.llvm.org/D39127 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316405 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaTemplate.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 0930fdd653..26b80f11fb 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -4805,7 +4805,12 @@ bool Sema::CheckTemplateArgumentList( // template. TemplateArgumentListInfo NewArgs = TemplateArgs; - TemplateParameterList *Params = Template->getTemplateParameters(); + // Make sure we get the template parameter list from the most + // recentdeclaration, since that is the only one that has is guaranteed to + // have all the default template argument information. + TemplateParameterList *Params = + cast(Template->getMostRecentDecl()) + ->getTemplateParameters(); SourceLocation RAngleLoc = NewArgs.getRAngleLoc(); -- GitLab From bca81dc70a81c58378cc853256544386194ced1d Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Tue, 24 Oct 2017 02:17:07 +0000 Subject: [PATCH 0035/1682] Unnamed bitfields don't block constant evaluation of constexpr ctors C++14 [dcl.constexpr]p4 states that in the body of a constexpr constructor, > every non-variant non-static data member and base class sub-object shall be initialized However, [class.bit]p2 notes that > Unnamed bit-fields are not members and cannot be initialized. Therefore, we should make sure to filter them out of the check that all fields are initialized. Fixing this makes the constant evaluator a bit smarter, and specifically allows constexpr constructors to avoid tripping -Wglobal-constructors when the type contains unnamed bitfields. Reviewed at https://reviews.llvm.org/D39035. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316408 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/ExprConstant.cpp | 3 +++ test/SemaCXX/constant-expression-cxx11.cpp | 16 ++++++++++++++++ test/SemaCXX/warn-global-constructors.cpp | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index c25b3b6322..c09c99386c 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1818,6 +1818,9 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, } } for (const auto *I : RD->fields()) { + if (I->isUnnamedBitfield()) + continue; + if (!CheckConstantExpression(Info, DiagLoc, I->getType(), Value.getStructField(I->getFieldIndex()))) return false; diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 68b82c7d96..51dd6199e6 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -1931,6 +1931,22 @@ namespace Bitfields { }; static_assert(X::f(3) == -1, "3 should truncate to -1"); } + + struct HasUnnamedBitfield { + unsigned a; + unsigned : 20; + unsigned b; + + constexpr HasUnnamedBitfield() : a(), b() {} + constexpr HasUnnamedBitfield(unsigned a, unsigned b) : a(a), b(b) {} + }; + + void testUnnamedBitfield() { + const HasUnnamedBitfield zero{}; + int a = 1 / zero.b; // expected-warning {{division by zero is undefined}} + const HasUnnamedBitfield oneZero{1, 0}; + int b = 1 / oneZero.b; // expected-warning {{division by zero is undefined}} + } } namespace ZeroSizeTypes { diff --git a/test/SemaCXX/warn-global-constructors.cpp b/test/SemaCXX/warn-global-constructors.cpp index 856826414a..430f239a3e 100644 --- a/test/SemaCXX/warn-global-constructors.cpp +++ b/test/SemaCXX/warn-global-constructors.cpp @@ -126,3 +126,22 @@ namespace pr20420 { void *array_storage[1]; const int &global_reference = *(int *)array_storage; } + +namespace bitfields { + struct HasUnnamedBitfield { + unsigned a; + unsigned : 20; + unsigned b; + + constexpr HasUnnamedBitfield() : a(), b() {} + constexpr HasUnnamedBitfield(unsigned a, unsigned b) : a(a), b(b) {} + explicit HasUnnamedBitfield(unsigned a) {} + }; + + const HasUnnamedBitfield zeroConst{}; + HasUnnamedBitfield zeroMutable{}; + const HasUnnamedBitfield explicitConst{1, 2}; + HasUnnamedBitfield explicitMutable{1, 2}; + const HasUnnamedBitfield nonConstexprConst{1}; // expected-warning {{global constructor}} + HasUnnamedBitfield nonConstexprMutable{1}; // expected-warning {{global constructor}} +} -- GitLab From a45d5bb59f1d95d850d6bf1ec2448ac6cf653415 Mon Sep 17 00:00:00 2001 From: Tim Shen Date: Tue, 24 Oct 2017 03:11:02 +0000 Subject: [PATCH 0036/1682] [test] Fix clang-test for FreeBSD and NetBSD Lit tries to inject the shared library paths, but no action is taken when platform.system() is not recognized, results in an environment variable with an empty name, which is illegal. The patch fixes this mechanism for FreeBSD and NetBSD, and gives an warning on other platforms, so that the latecomers don't have to spend time on debugging lit. Thanks Zhihao Yuan for the patch! Differential Revision: https://reviews.llvm.org/D39162 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316411 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/Unit/lit.cfg.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/test/Unit/lit.cfg.py b/test/Unit/lit.cfg.py index c4794ccbe5..f4bcdd76d1 100644 --- a/test/Unit/lit.cfg.py +++ b/test/Unit/lit.cfg.py @@ -35,17 +35,23 @@ for symbolizer in ['ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH']: if symbolizer in os.environ: config.environment[symbolizer] = os.environ[symbolizer] -shlibpath_var = '' -if platform.system() == 'Linux': - shlibpath_var = 'LD_LIBRARY_PATH' -elif platform.system() == 'Darwin': - shlibpath_var = 'DYLD_LIBRARY_PATH' -elif platform.system() == 'Windows': - shlibpath_var = 'PATH' - -# in stand-alone builds, shlibdir is clang's build tree -# while llvm_libs_dir is installed LLVM (and possibly older clang) -shlibpath = os.path.pathsep.join((config.shlibdir, config.llvm_libs_dir, - config.environment.get(shlibpath_var,''))) - -config.environment[shlibpath_var] = shlibpath +def find_shlibpath_var(): + if platform.system() in ['Linux', 'FreeBSD', 'NetBSD']: + yield 'LD_LIBRARY_PATH' + elif platform.system() == 'Darwin': + yield 'DYLD_LIBRARY_PATH' + elif platform.system() == 'Windows': + yield 'PATH' + +for shlibpath_var in find_shlibpath_var(): + # in stand-alone builds, shlibdir is clang's build tree + # while llvm_libs_dir is installed LLVM (and possibly older clang) + shlibpath = os.path.pathsep.join( + (config.shlibdir, + config.llvm_libs_dir, + config.environment.get(shlibpath_var, ''))) + config.environment[shlibpath_var] = shlibpath + break +else: + lit_config.warning("unable to inject shared library path on '{}'" + .format(platform.system())) -- GitLab From 55c536c5901afcbe111e76ed16fbe8ce4434c563 Mon Sep 17 00:00:00 2001 From: Peter Smith Date: Tue, 24 Oct 2017 09:51:55 +0000 Subject: [PATCH 0037/1682] [AArch64] Fix PR34625 -mtune without -mcpu should not set -target-cpu When -mtune is used on AArch64 the -target-cpu is passed the value of the cpu given to -mtune. As well as setting micro-architectural features of the -mtune cpu, this will also add the architectural features such as support for instructions. This can result in the backend using instructions that are supported in the -mtune cpu but not supported in the target architecture. For example use of the v8.1-a LSE extensions with -march=v8. This change removes the setting of -target-cpu for -mtune, the -mcpu must be used to set -target-cpu. This has the effect of removing all non-hard coded benefits of mtune but it does produce correct output when -mtune cpu with a later architecture than v8 is used. Fixes PR34625 Differential Revision: https://reviews.llvm.org/D39179 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316424 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Driver/ToolChains/Arch/AArch64.cpp | 16 +- test/Driver/aarch64-cpus.c | 244 ++++++++++++++----------- 2 files changed, 152 insertions(+), 108 deletions(-) diff --git a/lib/Driver/ToolChains/Arch/AArch64.cpp b/lib/Driver/ToolChains/Arch/AArch64.cpp index 36186f0ac3..ad04aedd09 100644 --- a/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -20,14 +20,12 @@ using namespace clang; using namespace llvm::opt; /// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are -/// targeting. Set \p A to the Arg corresponding to the -mcpu or -mtune -/// arguments if they are provided, or to nullptr otherwise. +/// targeting. Set \p A to the Arg corresponding to the -mcpu argument if it is +/// provided, or to nullptr otherwise. std::string aarch64::getAArch64TargetCPU(const ArgList &Args, Arg *&A) { std::string CPU; - // If we have -mtune or -mcpu, use that. - if ((A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ))) { - CPU = StringRef(A->getValue()).lower(); - } else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) { + // If we have -mcpu, use that. + if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) { StringRef Mcpu = A->getValue(); CPU = Mcpu.split("+").first.lower(); } @@ -122,6 +120,12 @@ getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, const ArgList &Args, std::vector &Features) { std::string MtuneLowerCase = Mtune.lower(); + // Check CPU name is valid + std::vector MtuneFeatures; + StringRef Tune; + if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, MtuneFeatures)) + return false; + // Handle CPU name is 'native'. if (MtuneLowerCase == "native") MtuneLowerCase = llvm::sys::getHostCPUName(); diff --git a/test/Driver/aarch64-cpus.c b/test/Driver/aarch64-cpus.c index f644d2b88a..229484b257 100644 --- a/test/Driver/aarch64-cpus.c +++ b/test/Driver/aarch64-cpus.c @@ -21,165 +21,188 @@ // RUN: %clang -target aarch64 -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s // RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s // RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s -// RUN: %clang -target aarch64 -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s -// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s -// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35 %s +// RUN: %clang -target aarch64 -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-TUNE %s +// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-TUNE %s +// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-TUNE %s // CA35: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a35" +// CA35-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target arm64 -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35 %s // RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35 %s -// RUN: %clang -target arm64 -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35 %s -// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35 %s +// RUN: %clang -target arm64 -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35-TUNE %s +// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA35-TUNE %s // ARM64-CA35: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a35" - +// ARM64-CA35-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64 -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s // RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s // RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s -// RUN: %clang -target aarch64 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s -// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53 %s +// RUN: %clang -target aarch64 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-TUNE %s +// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-TUNE %s // CA53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a53" +// CA53-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target arm64 -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s // RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s -// RUN: %clang -target arm64 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s -// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53 %s +// RUN: %clang -target arm64 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53-TUNE %s +// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA53-TUNE %s // ARM64-CA53: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a53" +// ARM64-CA53-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64 -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55 %s // RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55 %s // RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55 %s -// RUN: %clang -target aarch64 -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55 %s -// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55 %s +// RUN: %clang -target aarch64 -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-TUNE %s +// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-TUNE %s // CA55: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a55" +// CA55-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target arm64 -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA55 %s // RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA55 %s -// RUN: %clang -target arm64 -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA55 %s -// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA55 %s +// RUN: %clang -target arm64 -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA55-TUNE %s +// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA55-TUNE %s // ARM64-CA55: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a55" +// ARM64-CA55-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s // RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s // RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s -// RUN: %clang -target aarch64 -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s -// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s -// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57 %s +// RUN: %clang -target aarch64 -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-TUNE %s +// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-TUNE %s +// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-TUNE %s // CA57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a57" +// CA57-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target arm64 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s // RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s -// RUN: %clang -target arm64 -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s -// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57 %s +// RUN: %clang -target arm64 -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57-TUNE %s +// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA57-TUNE %s // ARM64-CA57: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a57" +// ARM64-CA57-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64 -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72 %s // RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72 %s // RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72 %s -// RUN: %clang -target aarch64 -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72 %s -// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72 %s -// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72 %s +// RUN: %clang -target aarch64 -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-TUNE %s +// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-TUNE %s +// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-TUNE %s // CA72: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a72" +// CA72-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target arm64 -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA72 %s // RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA72 %s -// RUN: %clang -target arm64 -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA72 %s -// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA72 %s +// RUN: %clang -target arm64 -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA72-TUNE %s +// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CA72-TUNE %s // ARM64-CA72: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a72" +// ARM64-CA72-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64 -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73 %s // RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73 %s // RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73 %s -// RUN: %clang -target aarch64 -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73 %s -// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73 %s -// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73 %s +// RUN: %clang -target aarch64 -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-TUNE %s +// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-TUNE %s +// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-TUNE %s // CORTEX-A73: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a73" +// CORTEX-A73-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target arm64 -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A73 %s // RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A73 %s -// RUN: %clang -target arm64 -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A73 %s -// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A73 %s +// RUN: %clang -target arm64 -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A73-TUNE %s +// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A73-TUNE %s // ARM64-CORTEX-A73: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a73" +// ARM64-CORTEX-A73-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64 -mcpu=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A75 %s // RUN: %clang -target aarch64 -mlittle-endian -mcpu=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A75 %s // RUN: %clang -target aarch64_be -mlittle-endian -mcpu=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A75 %s -// RUN: %clang -target aarch64 -mtune=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A75 %s -// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A75 %s -// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A75 %s +// RUN: %clang -target aarch64 -mtune=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A75-TUNE %s +// RUN: %clang -target aarch64 -mlittle-endian -mtune=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A75-TUNE %s +// RUN: %clang -target aarch64_be -mlittle-endian -mtune=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A75-TUNE %s // CORTEX-A75: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a75" +// CORTEX-A75-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target arm64 -mcpu=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A75 %s // RUN: %clang -target arm64 -mlittle-endian -mcpu=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A75 %s -// RUN: %clang -target arm64 -mtune=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A75 %s -// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A75 %s +// RUN: %clang -target arm64 -mtune=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A75-TUNE %s +// RUN: %clang -target arm64 -mlittle-endian -mtune=cortex-a75 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-CORTEX-A75-TUNE %s // ARM64-CORTEX-A75: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a75" +// ARM64-CORTEX-A75-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64 -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s // RUN: %clang -target aarch64 -mlittle-endian -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s // RUN: %clang -target aarch64_be -mlittle-endian -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s -// RUN: %clang -target aarch64 -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s -// RUN: %clang -target aarch64 -mlittle-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s -// RUN: %clang -target aarch64_be -mlittle-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1 %s +// RUN: %clang -target aarch64 -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-TUNE %s +// RUN: %clang -target aarch64 -mlittle-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-TUNE %s +// RUN: %clang -target aarch64_be -mlittle-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-TUNE %s // M1: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "exynos-m1" +// M1-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64 -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2 %s // RUN: %clang -target aarch64 -mlittle-endian -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2 %s // RUN: %clang -target aarch64_be -mlittle-endian -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2 %s -// RUN: %clang -target aarch64 -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2 %s -// RUN: %clang -target aarch64 -mlittle-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2 %s -// RUN: %clang -target aarch64_be -mlittle-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2 %s +// RUN: %clang -target aarch64 -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-TUNE %s +// RUN: %clang -target aarch64 -mlittle-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-TUNE %s +// RUN: %clang -target aarch64_be -mlittle-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-TUNE %s // M2: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "exynos-m2" +// M2-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64_be -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3 %s // RUN: %clang -target aarch64 -mbig-endian -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3 %s // RUN: %clang -target aarch64_be -mbig-endian -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3 %s -// RUN: %clang -target aarch64_be -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3 %s -// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3 %s -// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3 %s +// RUN: %clang -target aarch64_be -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-TUNE %s +// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-TUNE %s +// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-TUNE %s // M3: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "exynos-m3" +// M3-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" // RUN: %clang -target arm64 -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1 %s // RUN: %clang -target arm64 -mlittle-endian -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1 %s -// RUN: %clang -target arm64 -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1 %s -// RUN: %clang -target arm64 -mlittle-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1 %s +// RUN: %clang -target arm64 -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1-TUNE %s +// RUN: %clang -target arm64 -mlittle-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M1-TUNE %s // ARM64-M1: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "exynos-m1" +// ARM64-M1-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target arm64 -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M2 %s // RUN: %clang -target arm64 -mlittle-endian -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M2 %s -// RUN: %clang -target arm64 -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M2 %s -// RUN: %clang -target arm64 -mlittle-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M2 %s +// RUN: %clang -target arm64 -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M2-TUNE %s +// RUN: %clang -target arm64 -mlittle-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M2-TUNE %s // ARM64-M2: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "exynos-m2" +// ARM64-M2-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target arm64 -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M3 %s // RUN: %clang -target arm64 -mlittle-endian -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M3 %s -// RUN: %clang -target arm64 -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M3 %s -// RUN: %clang -target arm64 -mlittle-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M3 %s +// RUN: %clang -target arm64 -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M3-TUNE %s +// RUN: %clang -target arm64 -mlittle-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-M3-TUNE %s // ARM64-M3: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "exynos-m3" +// ARM64-M3-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64 -mcpu=falkor -### -c %s 2>&1 | FileCheck -check-prefix=FALKOR %s // RUN: %clang -target aarch64 -mlittle-endian -mcpu=falkor -### -c %s 2>&1 | FileCheck -check-prefix=FALKOR %s -// RUN: %clang -target aarch64 -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=FALKOR %s -// RUN: %clang -target aarch64 -mlittle-endian -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=FALKOR %s +// RUN: %clang -target aarch64 -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=FALKOR-TUNE %s +// RUN: %clang -target aarch64 -mlittle-endian -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=FALKOR-TUNE %s // FALKOR: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "falkor" +// FALKOR-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target arm64 -mcpu=falkor -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-FALKOR %s // RUN: %clang -target arm64 -mlittle-endian -mcpu=falkor -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-FALKOR %s -// RUN: %clang -target arm64 -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-FALKOR %s -// RUN: %clang -target arm64 -mlittle-endian -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-FALKOR %s +// RUN: %clang -target arm64 -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-FALKOR-TUNE %s +// RUN: %clang -target arm64 -mlittle-endian -mtune=falkor -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-FALKOR-TUNE %s // ARM64-FALKOR: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "falkor" +// ARM64-FALKOR-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64 -mcpu=kryo -### -c %s 2>&1 | FileCheck -check-prefix=KRYO %s // RUN: %clang -target aarch64 -mlittle-endian -mcpu=kryo -### -c %s 2>&1 | FileCheck -check-prefix=KRYO %s -// RUN: %clang -target aarch64 -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=KRYO %s -// RUN: %clang -target aarch64 -mlittle-endian -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=KRYO %s +// RUN: %clang -target aarch64 -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=KRYO-TUNE %s +// RUN: %clang -target aarch64 -mlittle-endian -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=KRYO-TUNE %s // KRYO: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "kryo" +// KRYO-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target arm64 -mcpu=kryo -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-KRYO %s // RUN: %clang -target arm64 -mlittle-endian -mcpu=kryo -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-KRYO %s -// RUN: %clang -target arm64 -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-KRYO %s -// RUN: %clang -target arm64 -mlittle-endian -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-KRYO %s +// RUN: %clang -target arm64 -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-KRYO-TUNE %s +// RUN: %clang -target arm64 -mlittle-endian -mtune=kryo -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-KRYO-TUNE %s // ARM64-KRYO: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "kryo" +// ARM64-KRYO-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64 -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99 %s // RUN: %clang -target aarch64 -mlittle-endian -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99 %s @@ -188,7 +211,7 @@ // RUN: %clang -target aarch64 -mlittle-endian -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-TUNE %s // RUN: %clang -target aarch64_be -mlittle-endian -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-TUNE %s // THUNDERX2T99: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "thunderx2t99" "-target-feature" "+v8.1a" -// THUNDERX2T99-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "thunderx2t99" +// THUNDERX2T99-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" // THUNDERX2T99-TUNE-NOT: +v8.1a // RUN: %clang -target arm64 -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-THUNDERX2T99 %s @@ -196,7 +219,7 @@ // RUN: %clang -target arm64 -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-THUNDERX2T99-TUNE %s // RUN: %clang -target arm64 -mlittle-endian -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=ARM64-THUNDERX2T99-TUNE %s // ARM64-THUNDERX2T99: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "thunderx2t99" "-target-feature" "+v8.1a" -// ARM64-THUNDERX2T99-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "thunderx2t99" +// ARM64-THUNDERX2T99-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" // ARM64-THUNDERX2T99-TUNE-NOT: +v8.1a // RUN: %clang -target aarch64_be -### -c %s 2>&1 | FileCheck -check-prefix=GENERIC-BE %s @@ -207,91 +230,104 @@ // RUN: %clang -target aarch64_be -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s // RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s // RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s -// RUN: %clang -target aarch64_be -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s -// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s -// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE %s +// RUN: %clang -target aarch64_be -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE-TUNE %s +// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE-TUNE %s +// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a35 -### -c %s 2>&1 | FileCheck -check-prefix=CA35-BE-TUNE %s // CA35-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a35" +// CA35-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64_be -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s // RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s // RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s -// RUN: %clang -target aarch64_be -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s -// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s -// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE %s +// RUN: %clang -target aarch64_be -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE-TUNE %s +// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE-TUNE %s +// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CA53-BE-TUNE %s // CA53-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a53" +// CA53-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64_be -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-BE %s // RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-BE %s // RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-BE %s -// RUN: %clang -target aarch64_be -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-BE %s -// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-BE %s -// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-BE %s +// RUN: %clang -target aarch64_be -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-BE-TUNE %s +// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-BE-TUNE %s +// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a55 -### -c %s 2>&1 | FileCheck -check-prefix=CA55-BE-TUNE %s // CA55-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a55" +// CA55-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64_be -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s // RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s // RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s -// RUN: %clang -target aarch64_be -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s -// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s -// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE %s +// RUN: %clang -target aarch64_be -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE-TUNE %s +// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE-TUNE %s +// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=CA57-BE-TUNE %s // CA57-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a57" +// CA57-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64_be -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE %s // RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE %s // RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE %s -// RUN: %clang -target aarch64_be -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE %s -// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE %s -// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE %s +// RUN: %clang -target aarch64_be -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE-TUNE %s +// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE-TUNE %s +// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=CA72-BE-TUNE %s // CA72-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a72" +// CA72-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64_be -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE %s // RUN: %clang -target aarch64 -mbig-endian -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE %s // RUN: %clang -target aarch64_be -mbig-endian -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE %s -// RUN: %clang -target aarch64_be -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE %s -// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE %s -// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE %s +// RUN: %clang -target aarch64_be -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE-TUNE %s +// RUN: %clang -target aarch64 -mbig-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE-TUNE %s +// RUN: %clang -target aarch64_be -mbig-endian -mtune=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=CORTEX-A73-BE-TUNE %s // CORTEX-A73-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "cortex-a73" +// CORTEX-A73-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64_be -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s // RUN: %clang -target aarch64 -mbig-endian -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s // RUN: %clang -target aarch64_be -mbig-endian -mcpu=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s -// RUN: %clang -target aarch64_be -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s -// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s -// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE %s +// RUN: %clang -target aarch64_be -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE-TUNE %s +// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE-TUNE %s +// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m1 -### -c %s 2>&1 | FileCheck -check-prefix=M1-BE-TUNE %s // M1-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "exynos-m1" +// M1-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64_be -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE %s // RUN: %clang -target aarch64 -mbig-endian -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE %s // RUN: %clang -target aarch64_be -mbig-endian -mcpu=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE %s -// RUN: %clang -target aarch64_be -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE %s -// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE %s -// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE %s +// RUN: %clang -target aarch64_be -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE-TUNE %s +// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE-TUNE %s +// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m2 -### -c %s 2>&1 | FileCheck -check-prefix=M2-BE-TUNE %s // M2-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "exynos-m2" +// M2-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64_be -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE %s // RUN: %clang -target aarch64 -mbig-endian -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE %s // RUN: %clang -target aarch64_be -mbig-endian -mcpu=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE %s -// RUN: %clang -target aarch64_be -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE %s -// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE %s -// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE %s +// RUN: %clang -target aarch64_be -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE-TUNE %s +// RUN: %clang -target aarch64 -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE-TUNE %s +// RUN: %clang -target aarch64_be -mbig-endian -mtune=exynos-m3 -### -c %s 2>&1 | FileCheck -check-prefix=M3-BE-TUNE %s // M3-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "exynos-m3" +// M3-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64_be -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE %s // RUN: %clang -target aarch64 -mbig-endian -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE %s // RUN: %clang -target aarch64_be -mbig-endian -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE %s -// RUN: %clang -target aarch64_be -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE %s -// RUN: %clang -target aarch64 -mbig-endian -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE %s -// RUN: %clang -target aarch64_be -mbig-endian -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE %s +// RUN: %clang -target aarch64_be -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE-TUNE %s +// RUN: %clang -target aarch64 -mbig-endian -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE-TUNE %s +// RUN: %clang -target aarch64_be -mbig-endian -mtune=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=THUNDERX2T99-BE-TUNE %s // THUNDERX2T99-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "thunderx2t99" - -// RUN: %clang -target aarch64 -mcpu=cortex-a57 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s -// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s -// RUN: %clang -target aarch64 -mcpu=cortex-a72 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s -// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s -// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s -// RUN: %clang -target aarch64 -mcpu=thunderx2t99 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s -// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE %s -// MCPU-MTUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a53" +// THUNDERX2T99-BE-TUNE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" + +// RUN: %clang -target aarch64 -mcpu=cortex-a57 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE-A57 %s +// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=cortex-a57 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE-A57 %s +// RUN: %clang -target aarch64 -mcpu=cortex-a72 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE-A72 %s +// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=cortex-a72 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE-A72 %s +// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=cortex-a73 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE-A73 %s +// RUN: %clang -target aarch64 -mcpu=thunderx2t99 -mtune=cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE-THUNDERX2T99 %s +// RUN: %clang -target aarch64 -mtune=cortex-a53 -mcpu=thunderx2t99 -### -c %s 2>&1 | FileCheck -check-prefix=MCPU-MTUNE-THUNDERX2T99 %s +// MCPU-MTUNE-A57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a57" +// MCPU-MTUNE-A72: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a72" +// MCPU-MTUNE-A73: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a73" +// MCPU-MTUNE-THUNDERX2T99: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "thunderx2t99" // RUN: %clang -target aarch64 -march=armv8.1a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A %s // RUN: %clang -target aarch64 -march=armv8.1-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV81A %s @@ -342,17 +378,21 @@ // ================== Check whether -mcpu and -mtune accept mixed-case values. // RUN: %clang -target aarch64 -mcpu=Cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-CA53 %s -// RUN: %clang -target aarch64 -mtune=Cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-CA53 %s +// RUN: %clang -target aarch64 -mtune=Cortex-a53 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-CA53-TUNE %s // CASE-INSENSITIVE-CA53: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a53" +// CASE-INSENSITIVE-CA53-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target arm64 -mcpu=cortex-A53 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-ARM64-CA53 %s -// RUN: %clang -target arm64 -mtune=cortex-A53 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-ARM64-CA53 %s +// RUN: %clang -target arm64 -mtune=cortex-A53 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-ARM64-CA53-TUNE %s // CASE-INSENSITIVE-ARM64-CA53: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a53" +// CASE-INSENSITIVE-ARM64-CA53-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target aarch64 -mcpu=CORTEX-A57 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-CA57 %s -// RUN: %clang -target aarch64 -mtune=CORTEX-A57 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-CA57 %s +// RUN: %clang -target aarch64 -mtune=CORTEX-A57 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-CA57-TUNE %s // CASE-INSENSITIVE-CA57: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "cortex-a57" +// CASE-INSENSITIVE-CA57-TUNE: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" // RUN: %clang -target arm64 -mcpu=Cortex-A57 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-ARM64-CA57 %s -// RUN: %clang -target arm64 -mtune=Cortex-A57 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-ARM64-CA57 %s +// RUN: %clang -target arm64 -mtune=Cortex-A57 -### -c %s 2>&1 | FileCheck -check-prefix=CASE-INSENSITIVE-ARM64-CA57-TUNE %s // CASE-INSENSITIVE-ARM64-CA57: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "cortex-a57" +// CASE-INSENSITIVE-ARM64-CA57-TUNE: "-cc1"{{.*}} "-triple" "arm64{{.*}}" "-target-cpu" "generic" -- GitLab From 230376a3f6366a23eb9187be0d6b9a37ead024fe Mon Sep 17 00:00:00 2001 From: Eric Liu Date: Tue, 24 Oct 2017 13:10:58 +0000 Subject: [PATCH 0038/1682] [Tooling] Add a factory method for CommonOptionsParser Summary: This returns error instead of exiting the program in case of error. Reviewers: klimek, hokein Reviewed By: hokein Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D39042 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316433 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Tooling/CommonOptionsParser.h | 17 +++++++- lib/Tooling/CommonOptionsParser.cpp | 45 ++++++++++++++++++--- 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/include/clang/Tooling/CommonOptionsParser.h b/include/clang/Tooling/CommonOptionsParser.h index 70f5e80e1e..e89b59c4c5 100644 --- a/include/clang/Tooling/CommonOptionsParser.h +++ b/include/clang/Tooling/CommonOptionsParser.h @@ -30,6 +30,7 @@ #include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Tooling/CompilationDatabase.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" namespace clang { namespace tooling { @@ -86,13 +87,18 @@ public: /// All options not belonging to \p Category become hidden. /// /// It also allows calls to set the required number of positional parameters. - /// - /// This constructor exits program in case of error. CommonOptionsParser(int &argc, const char **argv, llvm::cl::OptionCategory &Category, llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview = nullptr); + /// \brief A factory method that is similar to the above constructor, except + /// this returns an error instead exiting the program on error. + static llvm::Expected + create(int &argc, const char **argv, llvm::cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, + const char *Overview = nullptr); + /// Returns a reference to the loaded compilations database. CompilationDatabase &getCompilations() { return *Compilations; @@ -106,6 +112,13 @@ public: static const char *const HelpMessage; private: + CommonOptionsParser() = default; + + llvm::Error init(int &argc, const char **argv, + llvm::cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, + const char *Overview); + std::unique_ptr Compilations; std::vector SourcePathList; }; diff --git a/lib/Tooling/CommonOptionsParser.cpp b/lib/Tooling/CommonOptionsParser.cpp index edcb7df533..9ad15cc8b2 100644 --- a/lib/Tooling/CommonOptionsParser.cpp +++ b/lib/Tooling/CommonOptionsParser.cpp @@ -24,9 +24,9 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/CommandLine.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" +#include "llvm/Support/CommandLine.h" using namespace clang::tooling; using namespace llvm; @@ -81,7 +81,7 @@ std::vector ArgumentsAdjustingCompilations::adjustCommands( return Commands; } -CommonOptionsParser::CommonOptionsParser( +llvm::Error CommonOptionsParser::init( int &argc, const char **argv, cl::OptionCategory &Category, llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) { static cl::opt Help("h", cl::desc("Alias for -help"), cl::Hidden, @@ -105,20 +105,30 @@ CommonOptionsParser::CommonOptionsParser( cl::desc("Additional argument to prepend to the compiler command line"), cl::cat(Category), cl::sub(*cl::AllSubCommands)); + cl::ResetAllOptionOccurrences(); + cl::HideUnrelatedOptions(Category); std::string ErrorMessage; Compilations = FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage); - if (!Compilations && !ErrorMessage.empty()) - llvm::errs() << ErrorMessage; - cl::ParseCommandLineOptions(argc, argv, Overview); + if (!ErrorMessage.empty()) + ErrorMessage.append("\n"); + llvm::raw_string_ostream OS(ErrorMessage); + // Stop initializing if command-line option parsing failed. + if (!cl::ParseCommandLineOptions(argc, argv, Overview, &OS)) { + OS.flush(); + return llvm::make_error("[CommonOptionsParser]: " + + ErrorMessage, + llvm::inconvertibleErrorCode()); + } + cl::PrintOptionValues(); SourcePathList = SourcePaths; if ((OccurrencesFlag == cl::ZeroOrMore || OccurrencesFlag == cl::Optional) && SourcePathList.empty()) - return; + return llvm::Error::success(); if (!Compilations) { if (!BuildPath.empty()) { Compilations = @@ -142,4 +152,27 @@ CommonOptionsParser::CommonOptionsParser( AdjustingCompilations->appendArgumentsAdjuster( getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END)); Compilations = std::move(AdjustingCompilations); + return llvm::Error::success(); +} + +llvm::Expected CommonOptionsParser::create( + int &argc, const char **argv, llvm::cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) { + CommonOptionsParser Parser; + llvm::Error Err = + Parser.init(argc, argv, Category, OccurrencesFlag, Overview); + if (Err) + return std::move(Err); + return std::move(Parser); +} + +CommonOptionsParser::CommonOptionsParser( + int &argc, const char **argv, cl::OptionCategory &Category, + llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) { + llvm::Error Err = init(argc, argv, Category, OccurrencesFlag, Overview); + if (Err) { + llvm::report_fatal_error( + "CommonOptionsParser: failed to parse command-line arguments. " + + llvm::toString(std::move(Err))); + } } -- GitLab From 47dbb7c0df89914d76d70960557124df96725c5d Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 24 Oct 2017 13:46:58 +0000 Subject: [PATCH 0039/1682] Do not add a colon chunk to the code completion of class inheritance access modifiers With enabled CINDEXTEST_CODE_COMPLETE_PATTERNS env option (which enables IncludeCodePatterns in completion options) code completion after colon currently suggests access modifiers with 2 completion chunks which is incorrect. Example: class A : B { } Currently we get 'NotImplemented:{TypedText public}{Colon :} (40)' but the correct line is just 'NotImplemented:{TypedText public} (40)' The fix introduces more specific scope that occurs between ':' and '{' It allows us to determine when we don't need to add ':' as a second chunk to the public/protected/private access modifiers. Patch by Ivan Donchevskii! Differential Revision: https://reviews.llvm.org/D38618 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316436 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Scope.h | 3 +++ lib/Parse/ParseDeclCXX.cpp | 3 +++ lib/Sema/SemaCodeComplete.cpp | 8 +++++--- test/Index/complete-super.cpp | 5 +++++ 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h index e892d8205b..cd58a9910f 100644 --- a/include/clang/Sema/Scope.h +++ b/include/clang/Sema/Scope.h @@ -127,6 +127,9 @@ public: /// This is a compound statement scope. CompoundStmtScope = 0x400000, + + /// We are between inheritance colon and the real class/struct definition scope. + ClassInheritanceScope = 0x800000, }; private: /// The parent scope for this scope. This is null for the translation-unit diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index ada67e84d2..ca195901cf 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -3195,6 +3195,9 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, } if (Tok.is(tok::colon)) { + ParseScope InheritanceScope(this, getCurScope()->getFlags() | + Scope::ClassInheritanceScope); + ParseBaseClause(TagDecl); if (!Tok.is(tok::l_brace)) { bool SuggestFixIt = false; diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 90a15e17a2..fdfc39993d 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -1658,21 +1658,23 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, if (CCC == Sema::PCC_Class) { AddTypedefResult(Results); + bool IsNotInheritanceScope = + !(S->getFlags() & Scope::ClassInheritanceScope); // public: Builder.AddTypedTextChunk("public"); - if (Results.includeCodePatterns()) + if (IsNotInheritanceScope && Results.includeCodePatterns()) Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); // protected: Builder.AddTypedTextChunk("protected"); - if (Results.includeCodePatterns()) + if (IsNotInheritanceScope && Results.includeCodePatterns()) Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); // private: Builder.AddTypedTextChunk("private"); - if (Results.includeCodePatterns()) + if (IsNotInheritanceScope && Results.includeCodePatterns()) Builder.AddChunk(CodeCompletionString::CK_Colon); Results.AddResult(Result(Builder.TakeString())); } diff --git a/test/Index/complete-super.cpp b/test/Index/complete-super.cpp index 9ffa7c8a40..92d3f7f585 100644 --- a/test/Index/complete-super.cpp +++ b/test/Index/complete-super.cpp @@ -40,3 +40,8 @@ void B::bar(float real) { // CHECK-ACCESS-PATTERN: NotImplemented:{TypedText private}{Colon :} (40) // CHECK-ACCESS-PATTERN: NotImplemented:{TypedText protected}{Colon :} (40) // CHECK-ACCESS-PATTERN: NotImplemented:{TypedText public}{Colon :} (40) + +// RUN: env CINDEXTEST_CODE_COMPLETE_PATTERNS=1 c-index-test -code-completion-at=%s:10:12 %s | FileCheck -check-prefix=CHECK-INHERITANCE-PATTERN %s +// CHECK-INHERITANCE-PATTERN: NotImplemented:{TypedText private} (40) +// CHECK-INHERITANCE-PATTERN: NotImplemented:{TypedText protected} (40) +// CHECK-INHERITANCE-PATTERN: NotImplemented:{TypedText public} (40) -- GitLab From b4bdd6abd64045960b1d648cb5b7a8de6f292586 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Tue, 24 Oct 2017 13:51:07 +0000 Subject: [PATCH 0040/1682] Add Forgotten test for: Fix template parameter default args missed if redecled Addendum to differential revision: https://reviews.llvm.org/D39127 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316437 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../template-default-param-through-using.cpp | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 test/SemaCXX/template-default-param-through-using.cpp diff --git a/test/SemaCXX/template-default-param-through-using.cpp b/test/SemaCXX/template-default-param-through-using.cpp new file mode 100644 index 0000000000..4bf26d5811 --- /dev/null +++ b/test/SemaCXX/template-default-param-through-using.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics +namespace llvm { + template struct StringSet; + template struct Int; + template class Outer> + struct TemplTempl; +} + +namespace lld { + using llvm::StringSet; + using llvm::Int; + using llvm::TemplTempl; +}; + +namespace llvm { + template struct StringSet; +} + +template struct Temp{}; + +namespace llvm { + template struct StringSet{}; + template struct Int{}; + template class Outer = Temp> + struct TemplTempl{}; +}; + +namespace lld { + StringSet<> s; + Int<> i; + TemplTempl tt; +} -- GitLab From 91c475757be55ddd2948197478cff7c4335efdf0 Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Tue, 24 Oct 2017 14:52:35 +0000 Subject: [PATCH 0041/1682] [modules] Add a regression test for merging anon decls in extern C contexts. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316444 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/Modules/merge-anon-in-extern_c.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 test/Modules/merge-anon-in-extern_c.cpp diff --git a/test/Modules/merge-anon-in-extern_c.cpp b/test/Modules/merge-anon-in-extern_c.cpp new file mode 100644 index 0000000000..1443251f7e --- /dev/null +++ b/test/Modules/merge-anon-in-extern_c.cpp @@ -0,0 +1,19 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -verify %s +// expected-no-diagnostics + +#pragma clang module build sys_types +module sys_types {} +#pragma clang module contents +#pragma clang module begin sys_types +extern "C" { + typedef union { bool b; } pthread_mutex_t; +} +#pragma clang module end +#pragma clang module endbuild + +typedef union { bool b; } pthread_mutex_t; +#pragma clang module import sys_types + +const pthread_mutex_t *m; + -- GitLab From 1e065697f1f4ff348a37d0644c8b007c1e4d7e78 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Tue, 24 Oct 2017 15:34:59 +0000 Subject: [PATCH 0042/1682] Fix spelling in comment, field is isMsStruct, not Strust git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316447 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Decl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 875a21a538..e85c6c568a 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -3540,7 +3540,7 @@ public: return K >= firstRecord && K <= lastRecord; } - /// isMsStrust - Get whether or not this is an ms_struct which can + /// isMsStruct - Get whether or not this is an ms_struct which can /// be turned on with an attribute, pragma, or -mms-bitfields /// commandline option. bool isMsStruct(const ASTContext &C) const; -- GitLab From 103c2c8a5c5d847e52d2617f9208355634755847 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Tue, 24 Oct 2017 16:16:34 +0000 Subject: [PATCH 0043/1682] Remove repeated function name in doxygen comment. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316453 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Decl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index e85c6c568a..ef0f502a35 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -3540,7 +3540,7 @@ public: return K >= firstRecord && K <= lastRecord; } - /// isMsStruct - Get whether or not this is an ms_struct which can + /// \brief Get whether or not this is an ms_struct which can /// be turned on with an attribute, pragma, or -mms-bitfields /// commandline option. bool isMsStruct(const ASTContext &C) const; -- GitLab From 53710bdec511dfcfb69ee4d234b7f579b4955101 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 24 Oct 2017 16:39:37 +0000 Subject: [PATCH 0044/1682] [code completion] Complete ObjC methods in @implementation without leading '-'/'+' prefix rdar://12040840 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316458 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 3 +-- lib/Parse/Parser.cpp | 12 +++++++++--- lib/Sema/SemaCodeComplete.cpp | 27 +++++++++++++++++---------- test/Index/complete-method-decls.m | 22 ++++++++++++++++++++++ 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 368ae18bab..ba9b604ebc 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -10210,8 +10210,7 @@ public: void CodeCompleteObjCPropertyDefinition(Scope *S); void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, IdentifierInfo *PropertyName); - void CodeCompleteObjCMethodDecl(Scope *S, - bool IsInstanceMethod, + void CodeCompleteObjCMethodDecl(Scope *S, Optional IsInstanceMethod, ParsedType ReturnType); void CodeCompleteObjCMethodDeclSelector(Scope *S, bool IsInstanceMethod, diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index e24735dfc6..0b07ba1888 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -753,9 +753,15 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, SingleDecl = ParseObjCMethodDefinition(); break; case tok::code_completion: - Actions.CodeCompleteOrdinaryName(getCurScope(), - CurParsedObjCImpl? Sema::PCC_ObjCImplementation - : Sema::PCC_Namespace); + if (CurParsedObjCImpl) { + // Code-complete Objective-C methods even without leading '-'/'+' prefix. + Actions.CodeCompleteObjCMethodDecl(getCurScope(), + /*IsInstanceMethod=*/None, + /*ReturnType=*/nullptr); + } + Actions.CodeCompleteOrdinaryName( + getCurScope(), + CurParsedObjCImpl ? Sema::PCC_ObjCImplementation : Sema::PCC_Namespace); cutOffParsing(); return nullptr; case tok::kw_export: diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index fdfc39993d..06246d469f 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -6647,7 +6647,7 @@ typedef llvm::DenseMap< /// indexed by selector so they can be easily found. static void FindImplementableMethods(ASTContext &Context, ObjCContainerDecl *Container, - bool WantInstanceMethods, + Optional WantInstanceMethods, QualType ReturnType, KnownMethodsMap &KnownMethods, bool InOriginalClass = true) { @@ -6718,7 +6718,7 @@ static void FindImplementableMethods(ASTContext &Context, // we want the methods from this container to override any methods // we've previously seen with the same selector. for (auto *M : Container->methods()) { - if (M->isInstanceMethod() == WantInstanceMethods) { + if (!WantInstanceMethods || M->isInstanceMethod() == *WantInstanceMethods) { if (!ReturnType.isNull() && !Context.hasSameUnqualifiedType(ReturnType, M->getReturnType())) continue; @@ -7390,8 +7390,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, } } -void Sema::CodeCompleteObjCMethodDecl(Scope *S, - bool IsInstanceMethod, +void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional IsInstanceMethod, ParsedType ReturnTy) { // Determine the return type of the method we're declaring, if // provided. @@ -7446,7 +7445,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, ObjCMethodDecl *Method = M->second.getPointer(); CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); - + + // Add the '-'/'+' prefix if it wasn't provided yet. + if (!IsInstanceMethod) { + Builder.AddTextChunk(Method->isInstanceMethod() ? "-" : "+"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + } + // If the result type was not already provided, add it to the // pattern as (type). if (ReturnType.isNull()) { @@ -7548,11 +7553,13 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, if (IFace) for (auto *Cat : IFace->visible_categories()) Containers.push_back(Cat); - - for (unsigned I = 0, N = Containers.size(); I != N; ++I) - for (auto *P : Containers[I]->instance_properties()) - AddObjCKeyValueCompletions(P, IsInstanceMethod, ReturnType, Context, - KnownSelectors, Results); + + if (IsInstanceMethod) { + for (unsigned I = 0, N = Containers.size(); I != N; ++I) + for (auto *P : Containers[I]->instance_properties()) + AddObjCKeyValueCompletions(P, *IsInstanceMethod, ReturnType, Context, + KnownSelectors, Results); + } } Results.ExitScope(); diff --git a/test/Index/complete-method-decls.m b/test/Index/complete-method-decls.m index 8a17142266..f561f81496 100644 --- a/test/Index/complete-method-decls.m +++ b/test/Index/complete-method-decls.m @@ -236,3 +236,25 @@ typedef A *MyObjectRef; // RUN: c-index-test -code-completion-at=%s:107:2 %s -target x86_64-apple-macosx10.7 | FileCheck -check-prefix=CHECK-NULLABILITY2 %s // CHECK-NULLABILITY2: ObjCInstanceMethodDecl:{LeftParen (}{Text instancetype}{RightParen )}{TypedText getI3} (40) // CHECK-NULLABILITY2: ObjCInstanceMethodDecl:{LeftParen (}{Text I3 *}{RightParen )}{TypedText produceI3}{TypedText :}{LeftParen (}{Text I3 *}{RightParen )}{Text i3} (40) + +@interface CompleteWithoutLeadingPrefix + +- (void)aMethod; ++ (int)aClassMethod:(int)x; +@property int p; + +@end + +@implementation CompleteWithoutLeadingPrefix + + + +@end + +// RUN: c-index-test -code-completion-at=%s:250:1 %s | FileCheck -check-prefix=CHECK-COMP-NO-PREFIX %s +// CHECK-COMP-NO-PREFIX: NotImplemented:{TypedText @end} (40) +// CHECK-COMP-NO-PREFIX: ObjCClassMethodDecl:{Text +}{HorizontalSpace }{LeftParen (}{Text int}{RightParen )}{TypedText aClassMethod}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text x} (40) +// CHECK-COMP-NO-PREFIX: ObjCInstanceMethodDecl:{Text -}{HorizontalSpace }{LeftParen (}{Text void}{RightParen )}{TypedText aMethod} (40) +// CHECK-COMP-NO-PREFIX: ObjCInterfaceDecl:{TypedText I1} +// CHECK-COMP-NO-PREFIX: ObjCInstanceMethodDecl:{Text -}{HorizontalSpace }{LeftParen (}{Text int}{RightParen )}{TypedText p} (40) +// CHECK-COMP-NO-PREFIX: ObjCInstanceMethodDecl:{Text -}{HorizontalSpace }{LeftParen (}{Text void}{RightParen )}{TypedText setP}{TypedText :}{LeftParen (}{Text int}{RightParen )}{Text p} (40) -- GitLab From 58538f115416ae2ce6cc4cfa794d243bade5458d Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 24 Oct 2017 17:18:45 +0000 Subject: [PATCH 0045/1682] [refactor] Initial outline of implementation of "extract function" refactoring This commit adds an initial, skeleton outline of the "extract function" refactoring. The extracted function doesn't capture variables / rewrite code yet, it just basically does a simple copy-paste. The following initiation rules are specified: - extraction can only be done for executable code in a function/method/block. This means that you can't extract a global variable initialize into a function right now. - simple literals and references are not extractable. This commit also adds support for full source ranges to clang-refactor's test mode. Differential Revision: https://reviews.llvm.org/D38982 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316465 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../clang/Basic/DiagnosticRefactoringKinds.td | 7 + .../clang/Tooling/Refactoring/ASTSelection.h | 15 ++ .../Refactoring/RefactoringActionRegistry.def | 1 + .../RefactoringActionRuleRequirements.h | 26 ++ .../RefactoringActionRulesInternal.h | 2 +- .../Refactoring/RefactoringRuleContext.h | 8 + lib/Tooling/Refactoring/ASTSelection.cpp | 37 +++ .../Refactoring/ASTSelectionRequirements.cpp | 48 ++++ lib/Tooling/Refactoring/CMakeLists.txt | 2 + lib/Tooling/Refactoring/Extract.cpp | 232 ++++++++++++++++++ .../Extract/ExtractExprIntoFunction.cpp | 56 +++++ test/Refactor/LocalRename/Field.cpp | 8 +- .../LocalRename/NoSymbolSelectedError.cpp | 4 +- test/Refactor/tool-test-support.c | 5 + tools/clang-refactor/TestSupport.cpp | 65 ++++- 15 files changed, 499 insertions(+), 17 deletions(-) create mode 100644 lib/Tooling/Refactoring/ASTSelectionRequirements.cpp create mode 100644 lib/Tooling/Refactoring/Extract.cpp create mode 100644 test/Refactor/Extract/ExtractExprIntoFunction.cpp diff --git a/include/clang/Basic/DiagnosticRefactoringKinds.td b/include/clang/Basic/DiagnosticRefactoringKinds.td index ba9c830d60..b54b9301a7 100644 --- a/include/clang/Basic/DiagnosticRefactoringKinds.td +++ b/include/clang/Basic/DiagnosticRefactoringKinds.td @@ -19,6 +19,13 @@ def err_refactor_no_selection : Error<"refactoring action can't be initiated " "without a selection">; def err_refactor_selection_no_symbol : Error<"there is no symbol at the given " "location">; +def err_refactor_selection_invalid_ast : Error<"the provided selection does " + "not overlap with the AST nodes of interest">; + +def err_refactor_code_outside_of_function : Error<"the selected code is not a " + "part of a function's / method's body">; +def err_refactor_extract_simple_expression : Error<"the selected expression " + "is too simple to extract">; } diff --git a/include/clang/Tooling/Refactoring/ASTSelection.h b/include/clang/Tooling/Refactoring/ASTSelection.h index 17a97d2aaf..aa02a6899e 100644 --- a/include/clang/Tooling/Refactoring/ASTSelection.h +++ b/include/clang/Tooling/Refactoring/ASTSelection.h @@ -115,6 +115,21 @@ public: return SelectedNode.get().Children[I].Node.get(); } + /// Returns true when a selected code range is in a function-like body + /// of code, like a function, method or a block. + /// + /// This function can be used to test against selected expressions that are + /// located outside of a function, e.g. global variable initializers, default + /// argument values, or even template arguments. + /// + /// Use the \c getFunctionLikeNearestParent to get the function-like parent + /// declaration. + bool isInFunctionLikeBodyOfCode() const; + + /// Returns the nearest function-like parent declaration or null if such + /// declaration doesn't exist. + const Decl *getFunctionLikeNearestParent() const; + static Optional create(SourceRange SelectionRange, const SelectedASTNode &ASTSelection); diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRegistry.def b/include/clang/Tooling/Refactoring/RefactoringActionRegistry.def index a1191f1e50..9aeead4148 100644 --- a/include/clang/Tooling/Refactoring/RefactoringActionRegistry.def +++ b/include/clang/Tooling/Refactoring/RefactoringActionRegistry.def @@ -3,5 +3,6 @@ #endif REFACTORING_ACTION(LocalRename) +REFACTORING_ACTION(Extract) #undef REFACTORING_ACTION diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h b/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h index 36c982b063..355a6a55f2 100644 --- a/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h +++ b/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_REQUIREMENTS_H #include "clang/Basic/LLVM.h" +#include "clang/Tooling/Refactoring/ASTSelection.h" #include "clang/Tooling/Refactoring/RefactoringDiagnostic.h" #include "clang/Tooling/Refactoring/RefactoringOption.h" #include "clang/Tooling/Refactoring/RefactoringRuleContext.h" @@ -52,6 +53,31 @@ public: } }; +/// An AST selection requirement is satisfied when any portion of the AST +/// overlaps with the selection range. +/// +/// The requirement will be evaluated only once during the initiation and +/// search of matching refactoring action rules. +class ASTSelectionRequirement : public SourceRangeSelectionRequirement { +public: + Expected evaluate(RefactoringRuleContext &Context) const; +}; + +/// A selection requirement that is satisfied when the selection range overlaps +/// with a number of neighbouring statements in the AST. The statemenst must be +/// contained in declaration like a function. The selection range must be a +/// non-empty source selection (i.e. cursors won't be accepted). +/// +/// The requirement will be evaluated only once during the initiation and search +/// of matching refactoring action rules. +/// +/// \see CodeRangeASTSelection +class CodeRangeASTSelectionRequirement : public ASTSelectionRequirement { +public: + Expected + evaluate(RefactoringRuleContext &Context) const; +}; + /// A base class for any requirement that requires some refactoring options. class RefactoringOptionsRequirement : public RefactoringActionRuleRequirement { public: diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h b/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h index cf6147c0ba..443c7f86df 100644 --- a/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h +++ b/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h @@ -57,7 +57,7 @@ void invokeRuleAfterValidatingRequirements( return Consumer.handleError(std::move(Err)); // Construct the target action rule by extracting the evaluated // requirements from Expected<> wrappers and then run it. - RuleType((*std::get(Values))...).invoke(Consumer, Context); + RuleType(std::move((*std::get(Values)))...).invoke(Consumer, Context); } inline void visitRefactoringOptionsImpl(RefactoringOptionVisitor &) {} diff --git a/include/clang/Tooling/Refactoring/RefactoringRuleContext.h b/include/clang/Tooling/Refactoring/RefactoringRuleContext.h index 54ea06d861..882ab824b6 100644 --- a/include/clang/Tooling/Refactoring/RefactoringRuleContext.h +++ b/include/clang/Tooling/Refactoring/RefactoringRuleContext.h @@ -12,6 +12,7 @@ #include "clang/Basic/DiagnosticError.h" #include "clang/Basic/SourceManager.h" +#include "clang/Tooling/Refactoring/ASTSelection.h" namespace clang { @@ -62,6 +63,10 @@ public: return createDiagnosticError(SourceLocation(), DiagID); } + void setASTSelection(std::unique_ptr Node) { + ASTNodeSelection = std::move(Node); + } + private: /// The source manager for the translation unit / file on which a refactoring /// action might operate on. @@ -74,6 +79,9 @@ private: ASTContext *AST = nullptr; /// The allocator for diagnostics. PartialDiagnostic::StorageAllocator DiagStorage; + + // FIXME: Remove when memoized. + std::unique_ptr ASTNodeSelection; }; } // end namespace tooling diff --git a/lib/Tooling/Refactoring/ASTSelection.cpp b/lib/Tooling/Refactoring/ASTSelection.cpp index 2c9c42bfcb..9d0683a285 100644 --- a/lib/Tooling/Refactoring/ASTSelection.cpp +++ b/lib/Tooling/Refactoring/ASTSelection.cpp @@ -322,6 +322,10 @@ CodeRangeASTSelection::create(SourceRange SelectionRange, return CodeRangeASTSelection(Selected.Node, Selected.Parents, /*AreChildrenSelected=*/false); } + // FIXME (Alex L): First selected SwitchCase means that first case statement. + // is selected actually + // (See https://github.com/apple/swift-clang & CompoundStmtRange). + // FIXME (Alex L): Tweak selection rules for compound statements, see: // https://github.com/apple/swift-clang/blob/swift-4.1-branch/lib/Tooling/ // Refactor/ASTSlice.cpp#L513 @@ -330,3 +334,36 @@ CodeRangeASTSelection::create(SourceRange SelectionRange, return CodeRangeASTSelection(Selected.Node, Selected.Parents, /*AreChildrenSelected=*/true); } + +bool CodeRangeASTSelection::isInFunctionLikeBodyOfCode() const { + bool IsPrevCompound = false; + // Scan through the parents (bottom-to-top) and check if the selection is + // contained in a compound statement that's a body of a function/method + // declaration. + for (const auto &Parent : llvm::reverse(Parents)) { + const DynTypedNode &Node = Parent.get().Node; + if (const auto *D = Node.get()) { + // FIXME (Alex L): Test for BlockDecl && ObjCMethodDecl. + if (isa(D)) + return IsPrevCompound; + // FIXME (Alex L): We should return false on top-level decls in functions + // e.g. we don't want to extract: + // function foo() { struct X { + // int m = /*selection:*/ 1 + 2 /*selection end*/; }; }; + } + IsPrevCompound = Node.get() != nullptr; + } + return false; +} + +const Decl *CodeRangeASTSelection::getFunctionLikeNearestParent() const { + for (const auto &Parent : llvm::reverse(Parents)) { + const DynTypedNode &Node = Parent.get().Node; + if (const auto *D = Node.get()) { + // FIXME (Alex L): Test for BlockDecl && ObjCMethodDecl. + if (isa(D)) + return D; + } + } + return nullptr; +} diff --git a/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp b/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp new file mode 100644 index 0000000000..c0232c5da4 --- /dev/null +++ b/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp @@ -0,0 +1,48 @@ +//===--- ASTSelectionRequirements.cpp - Clang refactoring library ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h" + +using namespace clang; +using namespace tooling; + +Expected +ASTSelectionRequirement::evaluate(RefactoringRuleContext &Context) const { + // FIXME: Memoize so that selection is evaluated only once. + Expected Range = + SourceRangeSelectionRequirement::evaluate(Context); + if (!Range) + return Range.takeError(); + + Optional Selection = + findSelectedASTNodes(Context.getASTContext(), *Range); + if (!Selection) + return Context.createDiagnosticError( + Range->getBegin(), diag::err_refactor_selection_invalid_ast); + return std::move(*Selection); +} + +Expected CodeRangeASTSelectionRequirement::evaluate( + RefactoringRuleContext &Context) const { + // FIXME: Memoize so that selection is evaluated only once. + Expected ASTSelection = + ASTSelectionRequirement::evaluate(Context); + if (!ASTSelection) + return ASTSelection.takeError(); + std::unique_ptr StoredSelection = + llvm::make_unique(std::move(*ASTSelection)); + Optional CodeRange = CodeRangeASTSelection::create( + Context.getSelectionRange(), *StoredSelection); + if (!CodeRange) + return Context.createDiagnosticError( + Context.getSelectionRange().getBegin(), + diag::err_refactor_selection_invalid_ast); + Context.setASTSelection(std::move(StoredSelection)); + return std::move(*CodeRange); +} diff --git a/lib/Tooling/Refactoring/CMakeLists.txt b/lib/Tooling/Refactoring/CMakeLists.txt index 43ea1d9c54..f30c679a92 100644 --- a/lib/Tooling/Refactoring/CMakeLists.txt +++ b/lib/Tooling/Refactoring/CMakeLists.txt @@ -2,7 +2,9 @@ set(LLVM_LINK_COMPONENTS Support) add_clang_library(clangToolingRefactor ASTSelection.cpp + ASTSelectionRequirements.cpp AtomicChange.cpp + Extract.cpp RefactoringActions.cpp Rename/RenamingAction.cpp Rename/SymbolOccurrences.cpp diff --git a/lib/Tooling/Refactoring/Extract.cpp b/lib/Tooling/Refactoring/Extract.cpp new file mode 100644 index 0000000000..616900c181 --- /dev/null +++ b/lib/Tooling/Refactoring/Extract.cpp @@ -0,0 +1,232 @@ +//===--- Extract.cpp - Clang refactoring library --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Implements the "extract" refactoring that can pull code into +/// new functions, methods or declare new variables. +/// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Tooling/Refactoring/RefactoringAction.h" +#include "clang/Tooling/Refactoring/RefactoringActionRules.h" +#include "clang/Tooling/Refactoring/RefactoringOptions.h" + +namespace clang { +namespace tooling { + +namespace { + +/// Returns true if \c E is a simple literal or a reference expression that +/// should not be extracted. +bool isSimpleExpression(const Expr *E) { + if (!E) + return false; + switch (E->IgnoreParenCasts()->getStmtClass()) { + case Stmt::DeclRefExprClass: + case Stmt::PredefinedExprClass: + case Stmt::IntegerLiteralClass: + case Stmt::FloatingLiteralClass: + case Stmt::ImaginaryLiteralClass: + case Stmt::CharacterLiteralClass: + case Stmt::StringLiteralClass: + return true; + default: + return false; + } +} + +class ExtractableCodeSelectionRequirement final + : public CodeRangeASTSelectionRequirement { +public: + Expected + evaluate(RefactoringRuleContext &Context) const { + Expected Selection = + CodeRangeASTSelectionRequirement::evaluate(Context); + if (!Selection) + return Selection.takeError(); + CodeRangeASTSelection &Code = *Selection; + + // We would like to extract code out of functions/methods/blocks. + // Prohibit extraction from things like global variable / field + // initializers and other top-level expressions. + if (!Code.isInFunctionLikeBodyOfCode()) + return Context.createDiagnosticError( + diag::err_refactor_code_outside_of_function); + + // Avoid extraction of simple literals and references. + if (Code.size() == 1 && isSimpleExpression(dyn_cast(Code[0]))) + return Context.createDiagnosticError( + diag::err_refactor_extract_simple_expression); + + // FIXME (Alex L): Prohibit extraction of Objective-C property setters. + return Selection; + } +}; + +class ExtractFunction final : public SourceChangeRefactoringRule { +public: + ExtractFunction(CodeRangeASTSelection Code, Optional DeclName) + : Code(std::move(Code)), + DeclName(DeclName ? std::move(*DeclName) : "extracted") {} + + Expected + createSourceReplacements(RefactoringRuleContext &Context) override; + +private: + CodeRangeASTSelection Code; + + // FIXME: Account for naming collisions: + // - error when name is specified by user. + // - rename to "extractedN" when name is implicit. + std::string DeclName; +}; + +SourceLocation computeFunctionExtractionLocation(const Decl *D) { + // FIXME (Alex L): Method -> function extraction should place function before + // C++ record if the method is defined inside the record. + return D->getLocStart(); +} + +// FIXME: Support C++ method extraction. +// FIXME: Support Objective-C method extraction. +Expected +ExtractFunction::createSourceReplacements(RefactoringRuleContext &Context) { + const Decl *ParentDecl = Code.getFunctionLikeNearestParent(); + assert(ParentDecl && "missing parent"); + + // Compute the source range of the code that should be extracted. + SourceRange ExtractedRange(Code[0]->getLocStart(), + Code[Code.size() - 1]->getLocEnd()); + // FIXME (Alex L): Add code that accounts for macro locations. + + ASTContext &AST = Context.getASTContext(); + SourceManager &SM = AST.getSourceManager(); + const LangOptions &LangOpts = AST.getLangOpts(); + Rewriter ExtractedCodeRewriter(SM, LangOpts); + + // FIXME: Capture used variables. + + // Compute the return type. + QualType ReturnType = AST.VoidTy; + // FIXME (Alex L): Account for the return statement in extracted code. + // FIXME (Alex L): Check for lexical expression instead. + bool IsExpr = Code.size() == 1 && isa(Code[0]); + if (IsExpr) { + // FIXME (Alex L): Get a more user-friendly type if needed. + ReturnType = cast(Code[0])->getType(); + } + + // FIXME: Rewrite the extracted code performing any required adjustments. + + // FIXME: Capture any field if necessary (method -> function extraction). + + // FIXME: Sort captured variables by name. + + // FIXME: Capture 'this' / 'self' if necessary. + + // FIXME: Compute the actual parameter types. + + // Compute the location of the extracted declaration. + SourceLocation ExtractedDeclLocation = + computeFunctionExtractionLocation(ParentDecl); + // FIXME: Adjust the location to account for any preceding comments. + + // FIXME: Adjust with PP awareness like in Sema to get correct 'bool' + // treatment. + PrintingPolicy PP = AST.getPrintingPolicy(); + // FIXME: PP.UseStdFunctionForLambda = true; + PP.SuppressStrongLifetime = true; + PP.SuppressLifetimeQualifiers = true; + PP.SuppressUnwrittenScope = true; + + AtomicChange Change(SM, ExtractedDeclLocation); + // Create the replacement for the extracted declaration. + { + std::string ExtractedCode; + llvm::raw_string_ostream OS(ExtractedCode); + // FIXME: Use 'inline' in header. + OS << "static "; + ReturnType.print(OS, PP, DeclName); + OS << '('; + // FIXME: Arguments. + OS << ')'; + + // Function body. + OS << " {\n"; + if (IsExpr && !ReturnType->isVoidType()) + OS << "return "; + OS << ExtractedCodeRewriter.getRewrittenText(ExtractedRange); + // FIXME: Compute the correct semicolon policy. + OS << ';'; + OS << "\n}\n\n"; + auto Err = Change.insert(SM, ExtractedDeclLocation, OS.str()); + if (Err) + return std::move(Err); + } + + // Create the replacement for the call to the extracted declaration. + { + std::string ReplacedCode; + llvm::raw_string_ostream OS(ReplacedCode); + + OS << DeclName << '('; + // FIXME: Forward arguments. + OS << ')'; + // FIXME: Add semicolon if needed. + + auto Err = Change.replace( + SM, CharSourceRange::getTokenRange(ExtractedRange), OS.str()); + if (Err) + return std::move(Err); + } + + // FIXME: Add support for assocciated symbol location to AtomicChange to mark + // the ranges of the name of the extracted declaration. + return AtomicChanges{std::move(Change)}; +} + +class DeclNameOption final : public OptionalRefactoringOption { +public: + StringRef getName() const { return "name"; } + StringRef getDescription() const { + return "Name of the extracted declaration"; + } +}; + +class ExtractRefactoring final : public RefactoringAction { +public: + StringRef getCommand() const override { return "extract"; } + + StringRef getDescription() const override { + return "(WIP action; use with caution!) Extracts code into a new function " + "/ method / variable"; + } + + /// Returns a set of refactoring actions rules that are defined by this + /// action. + RefactoringActionRules createActionRules() const override { + RefactoringActionRules Rules; + Rules.push_back(createRefactoringActionRule( + ExtractableCodeSelectionRequirement(), + OptionRequirement())); + return Rules; + } +}; + +} // end anonymous namespace + +std::unique_ptr createExtractAction() { + return llvm::make_unique(); +} + +} // end namespace tooling +} // end namespace clang diff --git a/test/Refactor/Extract/ExtractExprIntoFunction.cpp b/test/Refactor/Extract/ExtractExprIntoFunction.cpp new file mode 100644 index 0000000000..be610fc303 --- /dev/null +++ b/test/Refactor/Extract/ExtractExprIntoFunction.cpp @@ -0,0 +1,56 @@ +// RUN: clang-refactor extract -selection=test:%s %s -- -std=c++11 2>&1 | grep -v CHECK | FileCheck %s + + +void simpleExtractNoCaptures() { + int i = /*range=->+0:33*/1 + 2; +} + +// CHECK: 1 '' results: +// CHECK: static int extracted() { +// CHECK-NEXT: return 1 + 2;{{$}} +// CHECK-NEXT: }{{[[:space:]].*}} +// CHECK-NEXT: void simpleExtractNoCaptures() { +// CHECK-NEXT: int i = /*range=->+0:33*/extracted();{{$}} +// CHECK-NEXT: } + +void simpleExtractStmtNoCaptures() { + /*range astatement=->+1:13*/int a = 1; + int b = 2; +} +// CHECK: 1 'astatement' results: +// CHECK: static void extracted() { +// CHECK-NEXT: int a = 1; +// CHECK-NEXT: int b = 2;;{{$}} +// CHECK-NEXT: }{{[[:space:]].*}} +// CHECK-NEXT: void simpleExtractStmtNoCaptures() { +// CHECK-NEXT: /*range astatement=->+1:13*/extracted(){{$}} +// CHECK-NEXT: } + + +void blankRangeNoExtraction() { + int i = /*range blank=*/1 + 2; +} + +// CHECK: 1 'blank' results: +// CHECK-NEXT: the provided selection does not overlap with the AST nodes of interest + +int outOfBodyCodeNoExtraction = /*range out_of_body_expr=->+0:72*/1 + 2; + +struct OutOfBodyStuff { + int FieldInit = /*range out_of_body_expr=->+0:58*/1 + 2; + + void foo(int x =/*range out_of_body_expr=->+0:58*/1 + 2); +}; + +// CHECK: 3 'out_of_body_expr' results: +// CHECK: the selected code is not a part of a function's / method's body + +void simpleExpressionNoExtraction() { + int i = /*range simple_expr=->+0:41*/1 + /*range simple_expr=->+0:76*/(2); + (void) /*range simple_expr=->+0:40*/i; + (void)/*range simple_expr=->+0:47*/"literal"; + (void)/*range simple_expr=->+0:41*/'c'; +} + +// CHECK: 5 'simple_expr' results: +// CHECK-NEXT: the selected expression is too simple to extract diff --git a/test/Refactor/LocalRename/Field.cpp b/test/Refactor/LocalRename/Field.cpp index 83ca2e5748..e674401b96 100644 --- a/test/Refactor/LocalRename/Field.cpp +++ b/test/Refactor/LocalRename/Field.cpp @@ -1,9 +1,11 @@ -// RUN: clang-refactor local-rename -selection=test:%s -new-name=Bar %s -- | FileCheck %s +// RUN: clang-refactor local-rename -selection=test:%s -new-name=Bar %s -- | grep -v CHECK | FileCheck %s class Baz { - int /*range=*/Foo; // CHECK: int /*range=*/Bar; + int /*range=*/Foo; + // CHECK: int /*range=*/Bar; public: Baz(); }; -Baz::Baz() : /*range=*/Foo(0) {} // CHECK: Baz::Baz() : /*range=*/Bar(0) {}; +Baz::Baz() : /*range=*/Foo(0) {} +// CHECK: Baz::Baz() : /*range=*/Bar(0) {} diff --git a/test/Refactor/LocalRename/NoSymbolSelectedError.cpp b/test/Refactor/LocalRename/NoSymbolSelectedError.cpp index b6e96e11b7..98de61a45f 100644 --- a/test/Refactor/LocalRename/NoSymbolSelectedError.cpp +++ b/test/Refactor/LocalRename/NoSymbolSelectedError.cpp @@ -1,5 +1,5 @@ -// RUN: not clang-refactor local-rename -selection=%s:4:1 -new-name=Bar %s -- 2>&1 | FileCheck %s -// RUN: clang-refactor local-rename -selection=test:%s -new-name=Bar %s -- 2>&1 | FileCheck --check-prefix=TESTCHECK %s +// RUN: not clang-refactor local-rename -selection=%s:4:1 -new-name=Bar %s -- 2>&1 | grep -v CHECK | FileCheck %s +// RUN: clang-refactor local-rename -selection=test:%s -new-name=Bar %s -- 2>&1 | grep -v CHECK | FileCheck --check-prefix=TESTCHECK %s class Baz { // CHECK: [[@LINE]]:1: error: there is no symbol at the given location }; diff --git a/test/Refactor/tool-test-support.c b/test/Refactor/tool-test-support.c index a20825518c..0e073f6e1c 100644 --- a/test/Refactor/tool-test-support.c +++ b/test/Refactor/tool-test-support.c @@ -10,10 +10,13 @@ /*range named =+0*/int test5; +/*range =->+0:22*/int test6; + // CHECK: Test selection group '': // CHECK-NEXT: 105-105 // CHECK-NEXT: 158-158 // CHECK-NEXT: 197-197 +// CHECK-NEXT: 248-251 // CHECK-NEXT: Test selection group 'named': // CHECK-NEXT: 132-132 // CHECK-NEXT: 218-218 @@ -29,6 +32,8 @@ // CHECK: invoking action 'local-rename': // CHECK-NEXT: -selection={{.*}}tool-test-support.c:9:29 +// CHECK: invoking action 'local-rename': +// CHECK-NEXT: -selection={{.*}}tool-test-support.c:13:19 -> {{.*}}tool-test-support.c:13:22 // The following invocations are in the 'named' group, and they follow // the default invocation even if some of their ranges occur prior to the diff --git a/tools/clang-refactor/TestSupport.cpp b/tools/clang-refactor/TestSupport.cpp index 2f127bd7f6..9331dfd92e 100644 --- a/tools/clang-refactor/TestSupport.cpp +++ b/tools/clang-refactor/TestSupport.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" +#include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Regex.h" #include "llvm/Support/raw_ostream.h" @@ -241,9 +242,9 @@ bool TestRefactoringResultConsumer::handleAllResults() { // Dump the results: const auto &TestGroup = TestRanges.GroupedRanges[Group.index()]; if (!CanonicalResult) { - llvm::errs() << TestGroup.Ranges.size() << " '" << TestGroup.Name + llvm::outs() << TestGroup.Ranges.size() << " '" << TestGroup.Name << "' results:\n"; - llvm::errs() << *CanonicalErrorMessage << "\n"; + llvm::outs() << *CanonicalErrorMessage << "\n"; } else { llvm::outs() << TestGroup.Ranges.size() << " '" << TestGroup.Name << "' results:\n"; @@ -271,6 +272,25 @@ static unsigned addColumnOffset(StringRef Source, unsigned Offset, (NewlinePos == StringRef::npos ? ColumnOffset : (unsigned)NewlinePos); } +static unsigned addEndLineOffsetAndEndColumn(StringRef Source, unsigned Offset, + unsigned LineNumberOffset, + unsigned Column) { + StringRef Line = Source.drop_front(Offset); + unsigned LineOffset = 0; + for (; LineNumberOffset != 0; --LineNumberOffset) { + size_t NewlinePos = Line.find_first_of("\r\n"); + // Line offset goes out of bounds. + if (NewlinePos == StringRef::npos) + break; + LineOffset += NewlinePos + 1; + Line = Line.drop_front(NewlinePos + 1); + } + // Source now points to the line at +lineOffset; + size_t LineStart = Source.find_last_of("\r\n", /*From=*/Offset + LineOffset); + return addColumnOffset( + Source, LineStart == StringRef::npos ? 0 : LineStart + 1, Column - 1); +} + Optional findTestSelectionRanges(StringRef Filename) { ErrorOr> ErrOrFile = @@ -282,11 +302,11 @@ findTestSelectionRanges(StringRef Filename) { } StringRef Source = ErrOrFile.get()->getBuffer(); - // FIXME (Alex L): 3rd capture groups for +line:column. // See the doc comment for this function for the explanation of this // syntax. static Regex RangeRegex("range[[:blank:]]*([[:alpha:]_]*)?[[:blank:]]*=[[:" - "blank:]]*(\\+[[:digit:]]+)?"); + "blank:]]*(\\+[[:digit:]]+)?[[:blank:]]*(->[[:blank:]" + "]*[\\+\\:[:digit:]]+)?"); std::map> GroupedRanges; @@ -304,18 +324,22 @@ findTestSelectionRanges(StringRef Filename) { StringRef Comment = Source.substr(Tok.getLocation().getRawEncoding(), Tok.getLength()); SmallVector Matches; - // Allow CHECK: comments to contain range= commands. - if (!RangeRegex.match(Comment, &Matches) || Comment.contains("CHECK")) { - // Try to detect mistyped 'range:' comments to ensure tests don't miss - // anything. + // Try to detect mistyped 'range:' comments to ensure tests don't miss + // anything. + auto DetectMistypedCommand = [&]() -> bool { if (Comment.contains_lower("range") && Comment.contains("=") && !Comment.contains_lower("run") && !Comment.contains("CHECK")) { llvm::errs() << "error: suspicious comment '" << Comment << "' that " "resembles the range command found\n"; llvm::errs() << "note: please reword if this isn't a range command\n"; - return None; } + return false; + }; + // Allow CHECK: comments to contain range= commands. + if (!RangeRegex.match(Comment, &Matches) || Comment.contains("CHECK")) { + if (DetectMistypedCommand()) + return None; continue; } unsigned Offset = Tok.getEndLoc().getRawEncoding(); @@ -325,9 +349,28 @@ findTestSelectionRanges(StringRef Filename) { if (Matches[2].drop_front().getAsInteger(10, ColumnOffset)) assert(false && "regex should have produced a number"); } - // FIXME (Alex L): Support true ranges. Offset = addColumnOffset(Source, Offset, ColumnOffset); - TestSelectionRange Range = {Offset, Offset}; + unsigned EndOffset; + + if (!Matches[3].empty()) { + static Regex EndLocRegex( + "->[[:blank:]]*(\\+[[:digit:]]+):([[:digit:]]+)"); + SmallVector EndLocMatches; + if (!EndLocRegex.match(Matches[3], &EndLocMatches)) { + if (DetectMistypedCommand()) + return None; + continue; + } + unsigned EndLineOffset = 0, EndColumn = 0; + if (EndLocMatches[1].drop_front().getAsInteger(10, EndLineOffset) || + EndLocMatches[2].getAsInteger(10, EndColumn)) + assert(false && "regex should have produced a number"); + EndOffset = addEndLineOffsetAndEndColumn(Source, Offset, EndLineOffset, + EndColumn); + } else { + EndOffset = Offset; + } + TestSelectionRange Range = {Offset, EndOffset}; auto It = GroupedRanges.insert(std::make_pair( Matches[1].str(), SmallVector{Range})); if (!It.second) -- GitLab From cbd4fdfd80f5a3f88c6c00711b130b2695477eec Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Tue, 24 Oct 2017 17:23:53 +0000 Subject: [PATCH 0046/1682] Add missing clangRewrite lib dependency for clangToolingRefactor git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316467 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Tooling/Refactoring/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Tooling/Refactoring/CMakeLists.txt b/lib/Tooling/Refactoring/CMakeLists.txt index f30c679a92..5d3ddd45b6 100644 --- a/lib/Tooling/Refactoring/CMakeLists.txt +++ b/lib/Tooling/Refactoring/CMakeLists.txt @@ -19,5 +19,6 @@ add_clang_library(clangToolingRefactor clangFormat clangIndex clangLex + clangRewrite clangToolingCore ) -- GitLab From c7d0ffff6897138067f69d777fd99130c379794b Mon Sep 17 00:00:00 2001 From: Yaxun Liu Date: Tue, 24 Oct 2017 19:14:43 +0000 Subject: [PATCH 0047/1682] CodeGen: Fix missing debug loc due to alloca Builder save/restores insertion pointer when emitting addr space cast for alloca, but does not save/restore debug loc, which causes verifier failure for certain call instructions. This patch fixes that. Differential Revision: https://reviews.llvm.org/D39069 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316484 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGExpr.cpp | 3 +-- test/CodeGenOpenCL/func-call-dbg-loc.cl | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 test/CodeGenOpenCL/func-call-dbg-loc.cl diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 2eb6d0a0c0..6837377de8 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -74,12 +74,11 @@ Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align, // cast alloca to the default address space when necessary. if (CastToDefaultAddrSpace && getASTAllocaAddressSpace() != LangAS::Default) { auto DestAddrSpace = getContext().getTargetAddressSpace(LangAS::Default); - auto CurIP = Builder.saveIP(); + llvm::IRBuilderBase::InsertPointGuard IPG(Builder); Builder.SetInsertPoint(AllocaInsertPt); V = getTargetHooks().performAddrSpaceCast( *this, V, getASTAllocaAddressSpace(), LangAS::Default, Ty->getPointerTo(DestAddrSpace), /*non-null*/ true); - Builder.restoreIP(CurIP); } return Address(V, Align); diff --git a/test/CodeGenOpenCL/func-call-dbg-loc.cl b/test/CodeGenOpenCL/func-call-dbg-loc.cl new file mode 100644 index 0000000000..4ed082fa9f --- /dev/null +++ b/test/CodeGenOpenCL/func-call-dbg-loc.cl @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple amdgcn---amdgizcl -debug-info-kind=limited -O0 -emit-llvm -o - %s | FileCheck %s + +typedef struct +{ + int a; +} Struct; + +Struct func1(); + +void func2(Struct S); + +void func3() +{ + // CHECK: call i32 @func1() #{{[0-9]+}}, !dbg ![[LOC:[0-9]+]] + // CHECK: call void @func2(i32 %{{[0-9]+}}) #{{[0-9]+}}, !dbg ![[LOC]] + func2(func1()); +} + -- GitLab From 3692af84cecf2239927281bdb9679f618811f9f5 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Tue, 24 Oct 2017 19:52:31 +0000 Subject: [PATCH 0048/1682] [OPENMP] Fix PR35013: Fix passing VLAs captures to outlined functions. Fixed passing of VLAs and variably-modified types to outlined functions. Synchronized passing with the types codegen. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316488 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGStmtOpenMP.cpp | 8 +++++++- test/OpenMP/for_reduction_codegen.cpp | 4 ++-- test/OpenMP/for_reduction_codegen_UDR.cpp | 4 ++-- test/OpenMP/parallel_codegen.cpp | 6 +++--- test/OpenMP/target_firstprivate_codegen.cpp | 2 +- test/OpenMP/target_parallel_codegen.cpp | 4 ++-- test/OpenMP/target_teams_codegen.cpp | 4 ++-- test/OpenMP/vla_crash.c | 22 ++++++++++++++++++++- 8 files changed, 40 insertions(+), 14 deletions(-) diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index 0e5ea798eb..f46ca23c55 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -254,6 +254,12 @@ static QualType getCanonicalParamType(ASTContext &C, QualType T) { } if (T->isPointerType()) return C.getPointerType(getCanonicalParamType(C, T->getPointeeType())); + if (auto *A = T->getAsArrayTypeUnsafe()) { + if (auto *VLA = dyn_cast(A)) + return getCanonicalParamType(C, VLA->getElementType()); + else if (!A->isVariablyModifiedType()) + return C.getCanonicalType(T); + } return C.getCanonicalParamType(T); } @@ -327,7 +333,7 @@ static llvm::Function *emitOutlinedFunctionPrologue( II = &Ctx.Idents.get("vla"); } if (ArgType->isVariablyModifiedType()) - ArgType = getCanonicalParamType(Ctx, ArgType.getNonReferenceType()); + ArgType = getCanonicalParamType(Ctx, ArgType); auto *Arg = ImplicitParamDecl::Create(Ctx, /*DC=*/nullptr, FD->getLocation(), II, ArgType, ImplicitParamDecl::Other); diff --git a/test/OpenMP/for_reduction_codegen.cpp b/test/OpenMP/for_reduction_codegen.cpp index 2c49022ff0..ac4c6ffcac 100644 --- a/test/OpenMP/for_reduction_codegen.cpp +++ b/test/OpenMP/for_reduction_codegen.cpp @@ -524,7 +524,7 @@ int main() { // CHECK: store float [[UP]], float* [[T_VAR1_LHS]], // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK1]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* %{{.+}}, [2 x i32]* dereferenceable(8) %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(160) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK1]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* {{.+}} %{{.+}}, [2 x i32]* dereferenceable(8) %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(160) %{{.+}}) // Reduction list for runtime. // CHECK: [[RED_LIST:%.+]] = alloca [4 x i8*], @@ -725,7 +725,7 @@ int main() { // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(160) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* {{.+}} %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(160) %{{.+}}) // CHECK: [[ARRS_PRIV:%.+]] = alloca [10 x [4 x [[S_FLOAT_TY]]]], diff --git a/test/OpenMP/for_reduction_codegen_UDR.cpp b/test/OpenMP/for_reduction_codegen_UDR.cpp index d78e515f30..f5ec656048 100644 --- a/test/OpenMP/for_reduction_codegen_UDR.cpp +++ b/test/OpenMP/for_reduction_codegen_UDR.cpp @@ -307,7 +307,7 @@ int main() { // CHECK: fadd float 5.550000e+02, % // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK1]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* %{{.+}}, [2 x i32]* dereferenceable(8) %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(480) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK1]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* {{.+}} %{{.+}}, [2 x i32]* dereferenceable(8) %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(480) %{{.+}}) // Reduction list for runtime. // CHECK: [[RED_LIST:%.+]] = alloca [4 x i8*], @@ -503,7 +503,7 @@ int main() { // CHECK: ret void -// CHECK: define internal void [[MAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(480) %{{.+}}) +// CHECK: define internal void [[MAIN_MICROTASK2]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, i64 %{{.+}}, i64 %{{.+}}, i32* {{.+}} %{{.+}}, [10 x [4 x [[S_FLOAT_TY]]]]* dereferenceable(480) %{{.+}}) // CHECK: [[ARRS_PRIV:%.+]] = alloca [10 x [4 x [[S_FLOAT_TY]]]], diff --git a/test/OpenMP/parallel_codegen.cpp b/test/OpenMP/parallel_codegen.cpp index 68a178e2c3..77e8efded6 100644 --- a/test/OpenMP/parallel_codegen.cpp +++ b/test/OpenMP/parallel_codegen.cpp @@ -53,7 +53,7 @@ int main (int argc, char **argv) { // CHECK-DEBUG: ret i32 // CHECK-DEBUG-NEXT: } -// CHECK: define internal {{.*}}void [[OMP_OUTLINED]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i{{[0-9]+}}{{.*}} [[VLA_SIZE:%.+]], i32* [[VLA_ADDR:%[^)]+]]) +// CHECK: define internal {{.*}}void [[OMP_OUTLINED]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i{{[0-9]+}}{{.*}} [[VLA_SIZE:%.+]], i32* {{.+}} [[VLA_ADDR:%[^)]+]]) // CHECK-SAME: #[[FN_ATTRS:[0-9]+]] // CHECK: store i32* [[VLA_ADDR]], i32** [[VLA_PTR_ADDR:%.+]], // CHECK: [[VLA_REF:%.+]] = load i32*, i32** [[VLA_PTR_ADDR]] @@ -64,7 +64,7 @@ int main (int argc, char **argv) { // CHECK: call {{.*}}void @{{.+terminate.*|abort}}( // CHECK-NEXT: unreachable // CHECK-NEXT: } -// CHECK-DEBUG: define internal void [[OMP_OUTLINED_DEBUG:@.+]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i64 [[VLA_SIZE:%.+]], i32* [[VLA_ADDR:%[^)]+]]) +// CHECK-DEBUG: define internal void [[OMP_OUTLINED_DEBUG:@.+]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i64 [[VLA_SIZE:%.+]], i32* {{.+}} [[VLA_ADDR:%[^)]+]]) // CHECK-DEBUG-SAME: #[[FN_ATTRS:[0-9]+]] // CHECK-DEBUG: store i32* [[VLA_ADDR]], i32** [[VLA_PTR_ADDR:%.+]], // CHECK-DEBUG: [[VLA_REF:%.+]] = load i32*, i32** [[VLA_PTR_ADDR]] @@ -80,7 +80,7 @@ int main (int argc, char **argv) { // CHECK-DAG: declare {{.*}}void @__kmpc_fork_call(%ident_t*, i32, void (i32*, i32*, ...)*, ...) // CHECK-DEBUG-DAG: define linkonce_odr void [[FOO]](i32 %argc) // CHECK-DEBUG-DAG: declare void @__kmpc_fork_call(%ident_t*, i32, void (i32*, i32*, ...)*, ...) -// CHECK-DEBUG-DAG: define internal void [[OMP_OUTLINED]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i64 [[VLA_SIZE:%.+]], i32* [[VLA_ADDR:%[^)]+]]) +// CHECK-DEBUG-DAG: define internal void [[OMP_OUTLINED]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i64 [[VLA_SIZE:%.+]], i32* {{.+}} [[VLA_ADDR:%[^)]+]]) // CHECK-DEBUG-DAG: call void [[OMP_OUTLINED_DEBUG]] // CHECK: define linkonce_odr {{[a-z\_\b]*[ ]?i32}} [[TMAIN]](i8** %argc) diff --git a/test/OpenMP/target_firstprivate_codegen.cpp b/test/OpenMP/target_firstprivate_codegen.cpp index 647b7b6dbc..8eef475814 100644 --- a/test/OpenMP/target_firstprivate_codegen.cpp +++ b/test/OpenMP/target_firstprivate_codegen.cpp @@ -223,7 +223,7 @@ int foo(int n, double *ptr) { // make sure that firstprivate variables are generated in all cases and that we use those instances for operations inside the // target region - // TCHECK: define {{.*}}void @__omp_offloading_{{.+}}(i{{[0-9]+}} [[A2_IN:%.+]], [10 x float]* {{.+}} [[B_IN:%.+]], i{{[0-9]+}} [[BN_SZ:%.+]], float* [[BN_IN:%.+]], [5 x [10 x double]]* {{.+}} [[C_IN:%.+]], i{{[0-9]+}} [[CN_SZ1:%.+]], i{{[0-9]+}} [[CN_SZ2:%.+]], double* [[CN_IN:%.+]], [[TT]]* {{.+}} [[D_IN:%.+]]) + // TCHECK: define {{.*}}void @__omp_offloading_{{.+}}(i{{[0-9]+}} [[A2_IN:%.+]], [10 x float]* {{.+}} [[B_IN:%.+]], i{{[0-9]+}} [[BN_SZ:%.+]], float* {{.+}} [[BN_IN:%.+]], [5 x [10 x double]]* {{.+}} [[C_IN:%.+]], i{{[0-9]+}} [[CN_SZ1:%.+]], i{{[0-9]+}} [[CN_SZ2:%.+]], double* {{.+}} [[CN_IN:%.+]], [[TT]]* {{.+}} [[D_IN:%.+]]) // TCHECK: [[A2_ADDR:%.+]] = alloca i{{[0-9]+}}, // TCHECK: [[B_ADDR:%.+]] = alloca [10 x float]*, // TCHECK: [[VLA_ADDR:%.+]] = alloca i{{[0-9]+}}, diff --git a/test/OpenMP/target_parallel_codegen.cpp b/test/OpenMP/target_parallel_codegen.cpp index 17318d5288..968e2fb9a7 100644 --- a/test/OpenMP/target_parallel_codegen.cpp +++ b/test/OpenMP/target_parallel_codegen.cpp @@ -428,7 +428,7 @@ int foo(int n) { // CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 9, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i[[SZ]], [10 x float]*, i[[SZ]], float*, [5 x [10 x double]]*, i[[SZ]], i[[SZ]], double*, [[TT]]*)* [[OMP_OUTLINED4:@.+]] to void (i32*, i32*, ...)*), i[[SZ]] [[REF_A]], [10 x float]* [[REF_B]], i[[SZ]] [[VAL_VLA1]], float* [[REF_BN]], [5 x [10 x double]]* [[REF_C]], i[[SZ]] [[VAL_VLA2]], i[[SZ]] [[VAL_VLA3]], double* [[REF_CN]], [[TT]]* [[REF_D]]) // // -// CHECK: define internal {{.*}}void [[OMP_OUTLINED4]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}}, [10 x float]* {{.+}}, i[[SZ]] %{{.+}}, float* %{{.+}}, [5 x [10 x double]]* {{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, double* %{{.+}}, [[TT]]* {{.+}}) +// CHECK: define internal {{.*}}void [[OMP_OUTLINED4]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}}, [10 x float]* {{.+}}, i[[SZ]] %{{.+}}, float* {{.+}}, [5 x [10 x double]]* {{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, double* {{.+}}, [[TT]]* {{.+}}) // To reduce complexity, we're only going as far as validating the signature of the outlined parallel function. template @@ -703,7 +703,7 @@ int bar(int n){ // CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%ident_t* [[DEF_LOC]], i32 5, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, [[S1]]*, i[[SZ]], i[[SZ]], i[[SZ]], i16*)* [[OMP_OUTLINED5:@.+]] to void (i32*, i32*, ...)*), [[S1]]* [[REF_THIS]], i[[SZ]] [[REF_B]], i[[SZ]] [[VAL_VLA1]], i[[SZ]] [[VAL_VLA2]], i16* [[REF_C]]) // // -// CHECK: define internal {{.*}}void [[OMP_OUTLINED5]](i32* noalias %.global_tid., i32* noalias %.bound_tid., [[S1]]* %{{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, i16* %{{.+}}) +// CHECK: define internal {{.*}}void [[OMP_OUTLINED5]](i32* noalias %.global_tid., i32* noalias %.bound_tid., [[S1]]* %{{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, i16* {{.+}}) // To reduce complexity, we're only going as far as validating the signature of the outlined parallel function. diff --git a/test/OpenMP/target_teams_codegen.cpp b/test/OpenMP/target_teams_codegen.cpp index 978879d763..50ac5a1ced 100644 --- a/test/OpenMP/target_teams_codegen.cpp +++ b/test/OpenMP/target_teams_codegen.cpp @@ -441,7 +441,7 @@ int foo(int n) { // CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 9, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i[[SZ]], [10 x float]*, i[[SZ]], float*, [5 x [10 x double]]*, i[[SZ]], i[[SZ]], double*, [[TT]]*)* [[OMP_OUTLINED4:@.+]] to void (i32*, i32*, ...)*), i[[SZ]] [[REF_A]], [10 x float]* [[REF_B]], i[[SZ]] [[VAL_VLA1]], float* [[REF_BN]], [5 x [10 x double]]* [[REF_C]], i[[SZ]] [[VAL_VLA2]], i[[SZ]] [[VAL_VLA3]], double* [[REF_CN]], [[TT]]* [[REF_D]]) // // -// CHECK: define internal {{.*}}void [[OMP_OUTLINED4]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}}, [10 x float]* {{.+}}, i[[SZ]] %{{.+}}, float* %{{.+}}, [5 x [10 x double]]* {{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, double* %{{.+}}, [[TT]]* {{.+}}) +// CHECK: define internal {{.*}}void [[OMP_OUTLINED4]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i[[SZ]] %{{.+}}, [10 x float]* {{.+}}, i[[SZ]] %{{.+}}, float* {{.+}}, [5 x [10 x double]]* {{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, double* {{.+}}, [[TT]]* {{.+}}) // To reduce complexity, we're only going as far as validating the signature of the outlined parallel function. template @@ -718,7 +718,7 @@ int bar(int n){ // CHECK: call {{.*}}void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_teams(%ident_t* [[DEF_LOC]], i32 5, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, [[S1]]*, i[[SZ]], i[[SZ]], i[[SZ]], i16*)* [[OMP_OUTLINED5:@.+]] to void (i32*, i32*, ...)*), [[S1]]* [[REF_THIS]], i[[SZ]] [[REF_B]], i[[SZ]] [[VAL_VLA1]], i[[SZ]] [[VAL_VLA2]], i16* [[REF_C]]) // // -// CHECK: define internal {{.*}}void [[OMP_OUTLINED5]](i32* noalias %.global_tid., i32* noalias %.bound_tid., [[S1]]* %{{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, i16* %{{.+}}) +// CHECK: define internal {{.*}}void [[OMP_OUTLINED5]](i32* noalias %.global_tid., i32* noalias %.bound_tid., [[S1]]* %{{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, i[[SZ]] %{{.+}}, i16* {{.+}}) // To reduce complexity, we're only going as far as validating the signature of the outlined parallel function. diff --git a/test/OpenMP/vla_crash.c b/test/OpenMP/vla_crash.c index 50dcf06870..0dcba5503e 100644 --- a/test/OpenMP/vla_crash.c +++ b/test/OpenMP/vla_crash.c @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -verify -triple powerpc64le-unknown-linux-gnu -fopenmp -x c -emit-llvm %s -o - | FileCheck %s -// expected-no-diagnostics int a; @@ -20,3 +19,24 @@ void foo() { // CHECK: define internal void [[OUTLINED]](i32* {{[^,]+}}, i32* {{[^,]+}}, i64 {{[^,]+}}, i32** {{[^,]+}}, i64 {{[^,]+}}, i32**** {{[^,]+}}) +// CHECK-LABEL: bar +void bar(int n, int *a) { + // CHECK: [[N:%.+]] = alloca i32, + // CHECK: [[A:%.+]] = alloca i32*, + // CHECK: [[P:%.+]] = alloca i32*, + // CHECK: @__kmpc_global_thread_num + // CHECK: [[BC:%.+]] = bitcast i32** [[A]] to i32* + // CHECK: store i32* [[BC]], i32** [[P]], + // CHECK: call void @__kmpc_serialized_parallel + // CHECK: call void [[OUTLINED:@[^(]+]](i32* %{{[^,]+}}, i32* %{{[^,]+}}, i64 %{{[^,]+}}, i32** [[P]], i32** [[A]]) + // CHECK: call void @__kmpc_end_serialized_parallel + // CHECK: ret void + // expected-warning@+1 {{incompatible pointer types initializing 'int (*)[n]' with an expression of type 'int **'}} + int(*p)[n] = &a; +#pragma omp parallel if(0) + // expected-warning@+1 {{comparison of distinct pointer types ('int (*)[n]' and 'int **')}} + if (p == &a) { + } +} + +// CHECK: define internal void [[OUTLINED]](i32* {{[^,]+}}, i32* {{[^,]+}}, i64 {{[^,]+}}, i32** {{[^,]+}}, i32** {{[^,]+}}) -- GitLab From 05b3b1db31719cae8568468f036fb55c99017fe0 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Tue, 24 Oct 2017 21:05:43 +0000 Subject: [PATCH 0049/1682] [Sema] Document+test the -Wsign-compare change for enums in C code [NFC] rL316268 / D39122 has fixed PR35009, and now when in C, these three(?) diagnostics properly use the enum's underlying datatype. While it was fixed, the test coverage was clearly insufficient, because the -Wsign-compare change didn't show up in any of the tests, until it was reported in the post-commit mail for rL316268. So add the test for the -Wsign-compare diagnostic for enum for C code, and while there, document this in the release notes. The fix itself was obviously correct, so unless we want to silence this new diagnosed case, i deem this commit to be NFC. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316500 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/ReleaseNotes.rst | 4 ++++ test/Sema/sign-compare-enum.c | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 test/Sema/sign-compare-enum.c diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst index 698672e479..997c6d3fcd 100644 --- a/docs/ReleaseNotes.rst +++ b/docs/ReleaseNotes.rst @@ -82,6 +82,10 @@ Improvements to Clang's diagnostics tautological comparisons between integer variable of the type ``T`` and the largest/smallest possible integer constant of that same type. +- For C code, ``-Wsign-compare``, ``-Wtautological-constant-compare`` and + ``-Wtautological-constant-out-of-range-compare`` were adjusted to use the + underlying datatype of ``enum``. + - ``-Wnull-pointer-arithmetic`` now warns about performing pointer arithmetic on a null pointer. Such pointer arithmetic has an undefined behavior if the offset is nonzero. It also now warns about arithmetic on a null pointer diff --git a/test/Sema/sign-compare-enum.c b/test/Sema/sign-compare-enum.c new file mode 100644 index 0000000000..8661bd502f --- /dev/null +++ b/test/Sema/sign-compare-enum.c @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify -Wsign-compare %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify -Wsign-compare %s +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -DSILENCE -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -DSILENCE -verify %s + +int main() { + enum A { A_a = 0, A_b = 1 }; + static const int message[] = {0, 1}; + enum A a; + + if (a < 2) + return 0; + +#if defined(SIGNED) && !defined(SILENCE) + if (a < sizeof(message)/sizeof(message[0])) // expected-warning {{comparison of integers of different signs: 'enum A' and 'unsigned long long'}} + return 0; +#else + // expected-no-diagnostics + if (a < 2U) + return 0; + if (a < sizeof(message)/sizeof(message[0])) + return 0; +#endif +} -- GitLab From 50ce061d121f04c1343d481840af4433d8208aa0 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Tue, 24 Oct 2017 21:31:50 +0000 Subject: [PATCH 0050/1682] mplement __has_unique_object_representations A helper builtin to facilitate implementing the std::has_unique_object_representations type trait. Requested here: https://bugs.llvm.org/show_bug.cgi?id=34942 Also already exists in GCC and MSVC. Differential Revision: https://reviews.llvm.org/D39064 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316518 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Type.h | 6 + include/clang/Basic/TokenKinds.def | 2 + include/clang/Basic/TypeTraits.h | 3 +- lib/AST/Type.cpp | 146 ++++++++++++++++++ lib/Parse/ParseExpr.cpp | 1 + lib/Sema/SemaExprCXX.cpp | 3 + test/SemaCXX/type-traits.cpp | 233 +++++++++++++++++++++++++++++ 7 files changed, 393 insertions(+), 1 deletion(-) diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 30804b7b3f..e1956473ac 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -770,6 +770,10 @@ public: /// Return true if this is a trivially copyable type (C++0x [basic.types]p9) bool isTriviallyCopyableType(const ASTContext &Context) const; + /// Return true if this has unique object representations according to (C++17 + /// [meta.unary.prop]p9) + bool hasUniqueObjectRepresentations(const ASTContext &Context) const; + // Don't promise in the API that anything besides 'const' can be // easily added. @@ -1114,6 +1118,8 @@ public: QualType getAtomicUnqualifiedType() const; private: + bool unionHasUniqueObjectRepresentations(const ASTContext& Context) const; + bool structHasUniqueObjectRepresentations(const ASTContext& Context) const; // These methods are implemented in a separate translation unit; // "static"-ize them to avoid creating temporary QualTypes in the // caller. diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 4f5e515657..9bb7b6a7d6 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -455,6 +455,8 @@ TYPE_TRAIT_1(__is_pod, IsPOD, KEYCXX) TYPE_TRAIT_1(__is_polymorphic, IsPolymorphic, KEYCXX) TYPE_TRAIT_1(__is_trivial, IsTrivial, KEYCXX) TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX) +TYPE_TRAIT_1(__has_unique_object_representations, + HasUniqueObjectRepresentations, KEYCXX) // Clang-only C++ Type Traits TYPE_TRAIT_N(__is_trivially_constructible, IsTriviallyConstructible, KEYCXX) diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h index 6aadf795d8..8ecd63f9c3 100644 --- a/include/clang/Basic/TypeTraits.h +++ b/include/clang/Basic/TypeTraits.h @@ -70,7 +70,8 @@ namespace clang { UTT_IsUnsigned, UTT_IsVoid, UTT_IsVolatile, - UTT_Last = UTT_IsVolatile, + UTT_HasUniqueObjectRepresentations, + UTT_Last = UTT_HasUniqueObjectRepresentations, BTT_IsBaseOf, BTT_IsConvertible, BTT_IsConvertibleTo, diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index cc5a00b584..15af195064 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -2166,6 +2166,152 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const { return false; } +bool QualType::unionHasUniqueObjectRepresentations( + const ASTContext &Context) const { + assert((*this)->isUnionType() && "must be union type"); + CharUnits UnionSize = Context.getTypeSizeInChars(*this); + const RecordDecl *Union = getTypePtr()->getAs()->getDecl(); + + for (const auto *Field : Union->fields()) { + if (!Field->getType().hasUniqueObjectRepresentations(Context)) + return false; + CharUnits FieldSize = Context.getTypeSizeInChars(Field->getType()); + if (FieldSize != UnionSize) + return false; + } + return true; +} + +bool isStructEmpty(QualType Ty) { + assert(Ty.getTypePtr()->isStructureOrClassType() && + "Must be struct or class"); + const RecordDecl *RD = Ty.getTypePtr()->getAs()->getDecl(); + + if (!RD->field_empty()) + return false; + + if (const CXXRecordDecl *ClassDecl = dyn_cast(RD)) { + return ClassDecl->isEmpty(); + } + + return true; +} + +bool QualType::structHasUniqueObjectRepresentations( + const ASTContext &Context) const { + assert((*this)->isStructureOrClassType() && "Must be struct or class"); + const RecordDecl *RD = getTypePtr()->getAs()->getDecl(); + + if (isStructEmpty(*this)) + return false; + + // Check base types. + CharUnits BaseSize{}; + if (const CXXRecordDecl *ClassDecl = dyn_cast(RD)) { + for (const auto Base : ClassDecl->bases()) { + if (Base.isVirtual()) + return false; + + // Empty bases are permitted, otherwise ensure base has unique + // representation. Also, Empty Base Optimization means that an + // Empty base takes up 0 size. + if (!isStructEmpty(Base.getType())) { + if (!Base.getType().structHasUniqueObjectRepresentations(Context)) + return false; + BaseSize += Context.getTypeSizeInChars(Base.getType()); + } + } + } + + CharUnits StructSize = Context.getTypeSizeInChars(*this); + + // This struct obviously has bases that keep it from being 'empty', so + // checking fields is no longer required. Ensure that the struct size + // is the sum of the bases. + if (RD->field_empty()) + return StructSize == BaseSize; + ; + + CharUnits CurOffset = + Context.toCharUnitsFromBits(Context.getFieldOffset(*RD->field_begin())); + + // If the first field isn't at the sum of the size of the bases, there + // is padding somewhere. + if (BaseSize != CurOffset) + return false; + + for (const auto *Field : RD->fields()) { + if (!Field->getType().hasUniqueObjectRepresentations(Context)) + return false; + CharUnits FieldSize = Context.getTypeSizeInChars(Field->getType()); + CharUnits FieldOffset = + Context.toCharUnitsFromBits(Context.getFieldOffset(Field)); + // Has padding between fields. + if (FieldOffset != CurOffset) + return false; + CurOffset += FieldSize; + } + // Check for tail padding. + return CurOffset == StructSize; +} + +bool QualType::hasUniqueObjectRepresentations(const ASTContext &Context) const { + // C++17 [meta.unary.prop]: + // The predicate condition for a template specialization + // has_unique_object_representations shall be + // satisfied if and only if: + // (9.1) — T is trivially copyable, and + // (9.2) — any two objects of type T with the same value have the same + // object representation, where two objects + // of array or non-union class type are considered to have the same value + // if their respective sequences of + // direct subobjects have the same values, and two objects of union type + // are considered to have the same + // value if they have the same active member and the corresponding members + // have the same value. + // The set of scalar types for which this condition holds is + // implementation-defined. [ Note: If a type has padding + // bits, the condition does not hold; otherwise, the condition holds true + // for unsigned integral types. — end + // note ] + if (isNull()) + return false; + + // Arrays are unique only if their element type is unique. + if ((*this)->isArrayType()) + return Context.getBaseElementType(*this).hasUniqueObjectRepresentations( + Context); + + // (9.1) — T is trivially copyable, and + if (!isTriviallyCopyableType(Context)) + return false; + + // Functions are not unique. + if ((*this)->isFunctionType()) + return false; + + // All integrals and enums are unique! + if ((*this)->isIntegralOrEnumerationType()) + return true; + + // All pointers are unique, since they're just integrals. + if ((*this)->isPointerType() || (*this)->isMemberPointerType()) + return true; + + if ((*this)->isRecordType()) { + const RecordDecl *Record = getTypePtr()->getAs()->getDecl(); + + // Lambda types are not unique, so exclude them immediately. + if (Record->isLambda()) + return false; + + if (Record->isUnion()) + return unionHasUniqueObjectRepresentations(Context); + return structHasUniqueObjectRepresentations(Context); + } + return false; +} + bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const { return !Context.getLangOpts().ObjCAutoRefCount && Context.getLangOpts().ObjCWeak && diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 5e0688ca58..bff6d9cc19 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -716,6 +716,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { /// '__is_sealed' [MS] /// '__is_trivial' /// '__is_union' +/// '__has_unique_object_representations' /// /// [Clang] unary-type-trait: /// '__is_aggregate' diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 7f5b792e8c..1ed714f8c8 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -4175,6 +4175,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, case UTT_IsDestructible: case UTT_IsNothrowDestructible: case UTT_IsTriviallyDestructible: + case UTT_HasUniqueObjectRepresentations: if (ArgTy->isIncompleteArrayType() || ArgTy->isVoidType()) return true; @@ -4614,6 +4615,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, // Returns True if and only if T is a complete type at the point of the // function call. return !T->isIncompleteType(); + case UTT_HasUniqueObjectRepresentations: + return T.hasUniqueObjectRepresentations(C); } } diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp index 5879a77dd5..d6a3574f93 100644 --- a/test/SemaCXX/type-traits.cpp +++ b/test/SemaCXX/type-traits.cpp @@ -2352,3 +2352,236 @@ void is_trivially_destructible_test() { { int arr[F(__is_trivially_destructible(void))]; } { int arr[F(__is_trivially_destructible(const volatile void))]; } } + +// Instantiation of __has_unique_object_representations +template +struct has_unique_object_representations { + static const bool value = __has_unique_object_representations(T); +}; + +static_assert(!has_unique_object_representations::value, "void is never unique"); +static_assert(!has_unique_object_representations::value, "void is never unique"); +static_assert(!has_unique_object_representations::value, "void is never unique"); +static_assert(!has_unique_object_representations::value, "void is never unique"); + +static_assert(has_unique_object_representations::value, "integrals are"); +static_assert(has_unique_object_representations::value, "integrals are"); +static_assert(has_unique_object_representations::value, "integrals are"); +static_assert(has_unique_object_representations::value, "integrals are"); + +static_assert(has_unique_object_representations::value, "as are pointers"); +static_assert(has_unique_object_representations::value, "as are pointers"); +static_assert(has_unique_object_representations::value, "are pointers"); +static_assert(has_unique_object_representations::value, "as are pointers"); + +static_assert(has_unique_object_representations::value, "as are pointers"); +static_assert(has_unique_object_representations::value, "as are pointers"); +static_assert(has_unique_object_representations::value, "as are pointers"); +static_assert(has_unique_object_representations::value, "as are pointers"); + +class C {}; +using FP = int (*)(int); +using PMF = int (C::*)(int); +using PMD = int C::*; + +static_assert(has_unique_object_representations::value, "even function pointers"); +static_assert(has_unique_object_representations::value, "even function pointers"); +static_assert(has_unique_object_representations::value, "even function pointers"); +static_assert(has_unique_object_representations::value, "even function pointers"); + +static_assert(has_unique_object_representations::value, "and pointer to members"); +static_assert(has_unique_object_representations::value, "and pointer to members"); +static_assert(has_unique_object_representations::value, "and pointer to members"); +static_assert(has_unique_object_representations::value, "and pointer to members"); + +static_assert(has_unique_object_representations::value, "and pointer to members"); +static_assert(has_unique_object_representations::value, "and pointer to members"); +static_assert(has_unique_object_representations::value, "and pointer to members"); +static_assert(has_unique_object_representations::value, "and pointer to members"); + +static_assert(has_unique_object_representations::value, "yes, all integral types"); +static_assert(has_unique_object_representations::value, "yes, all integral types"); +static_assert(has_unique_object_representations::value, "yes, all integral types"); +static_assert(has_unique_object_representations::value, "yes, all integral types"); +static_assert(has_unique_object_representations::value, "yes, all integral types"); +static_assert(has_unique_object_representations::value, "yes, all integral types"); +static_assert(has_unique_object_representations::value, "yes, all integral types"); +static_assert(has_unique_object_representations::value, "yes, all integral types"); +static_assert(has_unique_object_representations::value, "yes, all integral types"); +static_assert(has_unique_object_representations::value, "yes, all integral types"); +static_assert(has_unique_object_representations::value, "yes, all integral types"); +static_assert(has_unique_object_representations::value, "yes, all integral types"); +static_assert(has_unique_object_representations::value, "yes, all integral types"); +static_assert(has_unique_object_representations::value, "yes, all integral types"); +static_assert(has_unique_object_representations::value, "yes, all integral types"); + +static_assert(!has_unique_object_representations::value, "but not void!"); +static_assert(!has_unique_object_representations::value, "or nullptr_t"); +static_assert(!has_unique_object_representations::value, "definitely not Floating Point"); +static_assert(!has_unique_object_representations::value, "definitely not Floating Point"); +static_assert(!has_unique_object_representations::value, "definitely not Floating Point"); + +struct NoPadding { + int a; + int b; +}; + +static_assert(has_unique_object_representations::value, "types without padding are"); + +struct InheritsFromNoPadding : NoPadding { + int c; + int d; +}; + +static_assert(has_unique_object_representations::value, "types without padding are"); + +struct VirtuallyInheritsFromNoPadding : virtual NoPadding { + int c; + int d; +}; + +static_assert(!has_unique_object_representations::value, "No virtual inheritence"); + +struct Padding { + char a; + int b; +}; + +static_assert(!has_unique_object_representations::value, "but not with padding"); + +struct InheritsFromPadding : Padding { + int c; + int d; +}; + +static_assert(!has_unique_object_representations::value, "or its subclasses"); + +struct TailPadding { + int a; + char b; +}; + +static_assert(!has_unique_object_representations::value, "even at the end"); + +struct TinyStruct { + char a; +}; + +static_assert(has_unique_object_representations::value, "Should be no padding"); + +struct InheritsFromTinyStruct : TinyStruct { + int b; +}; + +static_assert(!has_unique_object_representations::value, "Inherit causes padding"); + +union NoPaddingUnion { + int a; + unsigned int b; +}; + +static_assert(has_unique_object_representations::value, "unions follow the same rules as structs"); + +union PaddingUnion { + int a; + long long b; +}; + +static_assert(!has_unique_object_representations::value, "unions follow the same rules as structs"); + +struct NotTriviallyCopyable { + int x; + NotTriviallyCopyable(const NotTriviallyCopyable &) {} +}; + +static_assert(!has_unique_object_representations::value, "must be trivially copyable"); + +struct HasNonUniqueMember { + float x; +}; + +static_assert(!has_unique_object_representations::value, "all members must be unique"); + +enum ExampleEnum { xExample, + yExample }; +enum LLEnum : long long { xLongExample, + yLongExample }; + +static_assert(has_unique_object_representations::value, "Enums are integrals, so unique!"); +static_assert(has_unique_object_representations::value, "Enums are integrals, so unique!"); + +enum class ExampleEnumClass { xExample, + yExample }; +enum class LLEnumClass : long long { xLongExample, + yLongExample }; + +static_assert(has_unique_object_representations::value, "Enums are integrals, so unique!"); +static_assert(has_unique_object_representations::value, "Enums are integrals, so unique!"); + +// because reference types aren't object types +static_assert(!has_unique_object_representations::value, "No references!"); +static_assert(!has_unique_object_representations::value, "No references!"); +static_assert(!has_unique_object_representations::value, "No references!"); +static_assert(!has_unique_object_representations::value, "No references!"); + +static_assert(!has_unique_object_representations::value, "No empty types!"); + +class Compressed : Empty { + int x; +}; + +static_assert(has_unique_object_representations::value, "But inheriting from one is ok"); + +class EmptyInheritor : Compressed {}; + +static_assert(has_unique_object_representations::value, "As long as the base has items, empty is ok"); + +class Dynamic { + virtual void A(); + int i; +}; + +static_assert(!has_unique_object_representations::value, "Dynamic types are not valid"); + +class InheritsDynamic : Dynamic { + int j; +}; + +static_assert(!has_unique_object_representations::value, "Dynamic types are not valid"); + +static_assert(has_unique_object_representations::value, "Arrays are fine, as long as their value type is"); +static_assert(has_unique_object_representations::value, "Arrays are fine, as long as their value type is"); +static_assert(has_unique_object_representations::value, "Arrays are fine, as long as their value type is"); +static_assert(!has_unique_object_representations::value, "So no array of doubles!"); +static_assert(!has_unique_object_representations::value, "So no array of doubles!"); +static_assert(!has_unique_object_representations::value, "So no array of doubles!"); + +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); + +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); +static_assert(!has_unique_object_representations::value, "Functions are not unique"); + +static auto lambda = []() {}; +static_assert(!has_unique_object_representations::value, "Lambdas are not unique"); + -- GitLab From 62e08f4f12f4370fd3e3b31074b2de91fd1db53b Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Tue, 24 Oct 2017 22:00:25 +0000 Subject: [PATCH 0051/1682] Replaced unicode characters with ASCII, as introduced in r316518. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316521 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/Type.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 15af195064..5e7cf34704 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -2260,8 +2260,8 @@ bool QualType::hasUniqueObjectRepresentations(const ASTContext &Context) const { // The predicate condition for a template specialization // has_unique_object_representations shall be // satisfied if and only if: - // (9.1) — T is trivially copyable, and - // (9.2) — any two objects of type T with the same value have the same + // (9.1) - T is trivially copyable, and + // (9.2) - any two objects of type T with the same value have the same // object representation, where two objects // of array or non-union class type are considered to have the same value // if their respective sequences of @@ -2272,8 +2272,7 @@ bool QualType::hasUniqueObjectRepresentations(const ASTContext &Context) const { // The set of scalar types for which this condition holds is // implementation-defined. [ Note: If a type has padding // bits, the condition does not hold; otherwise, the condition holds true - // for unsigned integral types. — end - // note ] + // for unsigned integral types. -- end note ] if (isNull()) return false; @@ -2282,7 +2281,7 @@ bool QualType::hasUniqueObjectRepresentations(const ASTContext &Context) const { return Context.getBaseElementType(*this).hasUniqueObjectRepresentations( Context); - // (9.1) — T is trivially copyable, and + // (9.1) - T is trivially copyable, and if (!isTriviallyCopyableType(Context)) return false; -- GitLab From 15627d62634ea98431990fff026a04629f9e378e Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Tue, 24 Oct 2017 22:24:13 +0000 Subject: [PATCH 0052/1682] [Analyzer] Fix bug in testing scripts, which always marked result as failure. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316522 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/analyzer/SATestBuild.py | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py index c13109593b..c70219cb68 100755 --- a/utils/analyzer/SATestBuild.py +++ b/utils/analyzer/SATestBuild.py @@ -732,6 +732,7 @@ def testAll(IsReferenceBuild=False, Strictness=0): for (ProjName, ProjBuildMode) in iterateOverProjects(PMapFile): TestsPassed &= testProject( ProjName, int(ProjBuildMode), IsReferenceBuild, Strictness) + return TestsPassed if __name__ == '__main__': -- GitLab From 5c484035ac41e9af5907ec574faa6e8c43cc00a2 Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Tue, 24 Oct 2017 23:12:01 +0000 Subject: [PATCH 0053/1682] Correct behavior of fastcall when default CC is set. Fastcall doesn't support variadic function calls, so setting the default calling convention to Fastcall would result in incorrect code being emitted for these conditions. This patch adds a 'variadic' test to the default calling conv test, as well as fixes the behavior of fastcall. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316528 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/ASTContext.cpp | 2 +- test/CodeGenCXX/default_calling_conv.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index a7ff9e10e9..87d096dab0 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -9269,7 +9269,7 @@ CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic, case LangOptions::DCC_CDecl: return CC_C; case LangOptions::DCC_FastCall: - if (getTargetInfo().hasFeature("sse2")) + if (getTargetInfo().hasFeature("sse2") && !IsVariadic) return CC_X86FastCall; break; case LangOptions::DCC_StdCall: diff --git a/test/CodeGenCXX/default_calling_conv.cpp b/test/CodeGenCXX/default_calling_conv.cpp index 95c214a223..15eedc8e31 100644 --- a/test/CodeGenCXX/default_calling_conv.cpp +++ b/test/CodeGenCXX/default_calling_conv.cpp @@ -10,6 +10,13 @@ // VECTORCALL: define x86_vectorcallcc void @_Z5test1v void test1() {} +// fastcall, stdcall, and vectorcall all do not support variadic functions. +// CDECL: define void @_Z12testVariadicz +// FASTCALL: define void @_Z12testVariadicz +// STDCALL: define void @_Z12testVariadicz +// VECTORCALL: define void @_Z12testVariadicz +void testVariadic(...){} + // ALL: define void @_Z5test2v void __attribute__((cdecl)) test2() {} -- GitLab From b7b9efb69316b7e4414c6300d7a651b1117fb8ae Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Tue, 24 Oct 2017 23:38:14 +0000 Subject: [PATCH 0054/1682] [Sema][ObjC] Look for either objc_bridge or objc_bridge_mutable when determining whether a RecordDecl is CFError. CFErrorRef used to be declared with "objc_bridge(NSError)" but is now declared with "objc_bridge_mutable(NSError)". Look for either when checking whether a RecordDecl is CFError. rdar://problem/35034779 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316531 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaType.cpp | 19 +++++++++++++------ .../Inputs/nullability-completeness-cferror.h | 13 +++++++++++++ .../nullability-completeness-cferror.mm | 5 +++++ 3 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 test/SemaObjCXX/Inputs/nullability-completeness-cferror.h create mode 100644 test/SemaObjCXX/nullability-completeness-cferror.mm diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 80b6c1d00d..ec0d93cf67 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -3482,13 +3482,20 @@ classifyPointerDeclarator(Sema &S, QualType type, Declarator &declarator, isCFError = (S.CFError == recordDecl); } else { // Check whether this is CFError, which we identify based on its bridge - // to NSError. + // to NSError. CFErrorRef used to be declared with "objc_bridge" but is + // now declared with "objc_bridge_mutable", so look for either one of + // the two attributes. if (recordDecl->getTagKind() == TTK_Struct && numNormalPointers > 0) { - if (auto bridgeAttr = recordDecl->getAttr()) { - if (bridgeAttr->getBridgedType() == S.getNSErrorIdent()) { - S.CFError = recordDecl; - isCFError = true; - } + IdentifierInfo *bridgedType = nullptr; + if (auto bridgeAttr = recordDecl->getAttr()) + bridgedType = bridgeAttr->getBridgedType(); + else if (auto bridgeAttr = + recordDecl->getAttr()) + bridgedType = bridgeAttr->getBridgedType(); + + if (bridgedType == S.getNSErrorIdent()) { + S.CFError = recordDecl; + isCFError = true; } } } diff --git a/test/SemaObjCXX/Inputs/nullability-completeness-cferror.h b/test/SemaObjCXX/Inputs/nullability-completeness-cferror.h new file mode 100644 index 0000000000..4988a7491c --- /dev/null +++ b/test/SemaObjCXX/Inputs/nullability-completeness-cferror.h @@ -0,0 +1,13 @@ +@class NSError; + +#pragma clang assume_nonnull begin + +#ifdef USE_MUTABLE +typedef struct __attribute__((objc_bridge_mutable(NSError))) __CFError * CFErrorRef; +#else +typedef struct __attribute__((objc_bridge(NSError))) __CFError * CFErrorRef; +#endif + +void func1(CFErrorRef *error); + +#pragma clang assume_nonnull end diff --git a/test/SemaObjCXX/nullability-completeness-cferror.mm b/test/SemaObjCXX/nullability-completeness-cferror.mm new file mode 100644 index 0000000000..4cea9fba92 --- /dev/null +++ b/test/SemaObjCXX/nullability-completeness-cferror.mm @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -fsyntax-only -I %S/Inputs -x objective-c -Wnullability-completeness -Werror -verify %s +// RUN: %clang_cc1 -fsyntax-only -I %S/Inputs -x objective-c -Wnullability-completeness -Werror -verify -DUSE_MUTABLE %s +// expected-no-diagnostics + +#include "nullability-completeness-cferror.h" -- GitLab From 7ffb1b28fb076bf42863e76533ead4eb686e59d1 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Tue, 24 Oct 2017 23:52:46 +0000 Subject: [PATCH 0055/1682] [Analyzer] [Tests] Remove temporary fields from generated reference results. Pointer to HTML diagnostics is removed (as it is not stored) as well as the version (as it would be available from the commit message). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316534 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/analyzer/SATestBuild.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py index c70219cb68..947cb5341a 100755 --- a/utils/analyzer/SATestBuild.py +++ b/utils/analyzer/SATestBuild.py @@ -493,6 +493,14 @@ def normalizeReferenceResults(Dir, SBOutputDir, ProjectBuildMode): if SourceFile.startswith(PathPrefix) else SourceFile for SourceFile in Data['files']] Data['files'] = Paths + + # Remove transient fields which change from run to run. + for Diag in Data['diagnostics']: + if 'HTMLDiagnostics_files' in Diag: + Diag.pop('HTMLDiagnostics_files') + if 'clang_version' in Data: + Data.pop('clang_version') + plistlib.writePlist(Data, Plist) -- GitLab From d8eca0ac0820ec3df63a9e44f8b4b4b80922eb9a Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Tue, 24 Oct 2017 23:52:48 +0000 Subject: [PATCH 0056/1682] [Analyzer] [Tests] Minor refactor of testing infrastructure: Move utilities functions into a separate file to make comprehension easier. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316535 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/analyzer/SATestBuild.py | 129 ++++------------------------------ utils/analyzer/SATestUtils.py | 108 ++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 115 deletions(-) create mode 100644 utils/analyzer/SATestUtils.py diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py index 947cb5341a..5853cf438a 100755 --- a/utils/analyzer/SATestBuild.py +++ b/utils/analyzer/SATestBuild.py @@ -43,6 +43,7 @@ For testing additional checkers, use the SA_ADDITIONAL_CHECKERS environment variable. It should contain a comma separated list. """ import CmpRuns +import SATestUtils import os import csv @@ -53,7 +54,7 @@ import shutil import time import plistlib import argparse -from subprocess import check_call, check_output, CalledProcessError +from subprocess import check_call, CalledProcessError import multiprocessing #------------------------------------------------------------------------------ @@ -61,51 +62,7 @@ import multiprocessing #------------------------------------------------------------------------------ -def which(command, paths=None): - """which(command, [paths]) - Look up the given command in the paths string - (or the PATH environment variable, if unspecified).""" - - if paths is None: - paths = os.environ.get('PATH', '') - - # Check for absolute match first. - if os.path.exists(command): - return command - - # Would be nice if Python had a lib function for this. - if not paths: - paths = os.defpath - - # Get suffixes to search. - # On Cygwin, 'PATHEXT' may exist but it should not be used. - if os.pathsep == ';': - pathext = os.environ.get('PATHEXT', '').split(';') - else: - pathext = [''] - - # Search the paths... - for path in paths.split(os.pathsep): - for ext in pathext: - p = os.path.join(path, command + ext) - if os.path.exists(p): - return p - - return None - - -class flushfile(object): - """ - Wrapper to flush the output after every print statement. - """ - def __init__(self, f): - self.f = f - - def write(self, x): - self.f.write(x) - self.f.flush() - - -sys.stdout = flushfile(sys.stdout) +sys.stdout = SATestUtils.flushfile(sys.stdout) def getProjectMapPath(): @@ -137,7 +94,7 @@ def getSBOutputDirName(IsReferenceBuild): if 'CC' in os.environ: Clang = os.environ['CC'] else: - Clang = which("clang", os.environ['PATH']) + Clang = SATestUtils.which("clang", os.environ['PATH']) if not Clang: print "Error: cannot find 'clang' in PATH" sys.exit(-1) @@ -215,7 +172,7 @@ def runCleanupScript(Dir, PBuildLogFile): """ Cwd = os.path.join(Dir, PatchedSourceDirName) ScriptPath = os.path.join(Dir, CleanupScript) - runScript(ScriptPath, PBuildLogFile, Cwd) + SATestUtils.runScript(ScriptPath, PBuildLogFile, Cwd) def runDownloadScript(Dir, PBuildLogFile): @@ -223,29 +180,7 @@ def runDownloadScript(Dir, PBuildLogFile): Run the script to download the project, if it exists. """ ScriptPath = os.path.join(Dir, DownloadScript) - runScript(ScriptPath, PBuildLogFile, Dir) - - -def runScript(ScriptPath, PBuildLogFile, Cwd): - """ - Run the provided script if it exists. - """ - if os.path.exists(ScriptPath): - try: - if Verbose == 1: - print " Executing: %s" % (ScriptPath,) - check_call("chmod +x '%s'" % ScriptPath, cwd=Cwd, - stderr=PBuildLogFile, - stdout=PBuildLogFile, - shell=True) - check_call("'%s'" % ScriptPath, cwd=Cwd, - stderr=PBuildLogFile, - stdout=PBuildLogFile, - shell=True) - except: - print "Error: Running %s failed. See %s for details." % ( - ScriptPath, PBuildLogFile.name) - sys.exit(-1) + SATestUtils.runScript(ScriptPath, PBuildLogFile, Dir) def downloadAndPatch(Dir, PBuildLogFile): @@ -343,28 +278,6 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile): raise -def hasNoExtension(FileName): - (Root, Ext) = os.path.splitext(FileName) - return (Ext == "") - - -def isValidSingleInputFile(FileName): - (Root, Ext) = os.path.splitext(FileName) - return Ext in (".i", ".ii", ".c", ".cpp", ".m", "") - - -def getSDKPath(SDKName): - """ - Get the path to the SDK for the given SDK name. Returns None if - the path cannot be determined. - """ - if which("xcrun") is None: - return None - - Cmd = "xcrun --sdk " + SDKName + " --show-sdk-path" - return check_output(Cmd, shell=True).rstrip() - - def runAnalyzePreprocessed(Dir, SBOutputDir, Mode): """ Run analysis on a set of preprocessed files. @@ -378,7 +291,7 @@ def runAnalyzePreprocessed(Dir, SBOutputDir, Mode): # For now, we assume the preprocessed files should be analyzed # with the OS X SDK. - SDKPath = getSDKPath("macosx") + SDKPath = SATestUtils.getSDKPath("macosx") if SDKPath is not None: CmdPrefix += "-isysroot " + SDKPath + " " @@ -398,9 +311,9 @@ def runAnalyzePreprocessed(Dir, SBOutputDir, Mode): Failed = False # Only run the analyzes on supported files. - if (hasNoExtension(FileName)): + if SATestUtils.hasNoExtension(FileName): continue - if (not isValidSingleInputFile(FileName)): + if not SATestUtils.isValidSingleInputFile(FileName): print "Error: Invalid single input file %s." % (FullFileName,) raise Exception() @@ -563,14 +476,6 @@ def checkBuild(SBOutputDir): sys.exit(-1) -class Discarder(object): - """ - Auxiliary object to discard stdout. - """ - def write(self, text): - pass # do nothing - - def runCmpResults(Dir, Strictness=0): """ Compare the warnings produced by scan-build. @@ -624,7 +529,7 @@ def runCmpResults(Dir, Strictness=0): # Discard everything coming out of stdout # (CmpRun produces a lot of them). OLD_STDOUT = sys.stdout - sys.stdout = Discarder() + sys.stdout = SATestUtils.Discarder() # Scan the results, delete empty plist files. NumDiffs, ReportsInRef, ReportsInNew = \ CmpRuns.dumpScanBuildResultsDiff(RefDir, NewDir, Opts, False) @@ -694,13 +599,6 @@ def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Strictness=0): return TestsPassed -def isCommentCSVLine(Entries): - """ - Treat CSV lines starting with a '#' as a comment. - """ - return len(Entries) > 0 and Entries[0].startswith("#") - - def projectFileHandler(): return open(getProjectMapPath(), "rb") @@ -712,7 +610,7 @@ def iterateOverProjects(PMapFile): """ PMapFile.seek(0) for I in csv.reader(PMapFile): - if (isCommentCSVLine(I)): + if (SATestUtils.isCommentCSVLine(I)): continue yield I @@ -722,10 +620,10 @@ def validateProjectFile(PMapFile): Validate project file. """ for I in iterateOverProjects(PMapFile): - if (len(I) != 2): + if len(I) != 2: print "Error: Rows in the ProjectMapFile should have 2 entries." raise Exception() - if (not ((I[1] == "0") | (I[1] == "1") | (I[1] == "2"))): + if I[1] not in ('0', '1', '2'): print "Error: Second entry in the ProjectMapFile should be 0" \ " (single file), 1 (project), or 2(single file c++11)." raise Exception() @@ -763,4 +661,5 @@ if __name__ == '__main__': TestsPassed = testAll(IsReference, Strictness) if not TestsPassed: + print "ERROR: Tests failed." sys.exit(-1) diff --git a/utils/analyzer/SATestUtils.py b/utils/analyzer/SATestUtils.py new file mode 100644 index 0000000000..961ebfac13 --- /dev/null +++ b/utils/analyzer/SATestUtils.py @@ -0,0 +1,108 @@ +import os +from subprocess import check_output, check_call +import sys + + +Verbose = 1 + +def which(command, paths=None): + """which(command, [paths]) - Look up the given command in the paths string + (or the PATH environment variable, if unspecified).""" + + if paths is None: + paths = os.environ.get('PATH', '') + + # Check for absolute match first. + if os.path.exists(command): + return command + + # Would be nice if Python had a lib function for this. + if not paths: + paths = os.defpath + + # Get suffixes to search. + # On Cygwin, 'PATHEXT' may exist but it should not be used. + if os.pathsep == ';': + pathext = os.environ.get('PATHEXT', '').split(';') + else: + pathext = [''] + + # Search the paths... + for path in paths.split(os.pathsep): + for ext in pathext: + p = os.path.join(path, command + ext) + if os.path.exists(p): + return p + + return None + + +class flushfile(object): + """ + Wrapper to flush the output after every print statement. + """ + def __init__(self, f): + self.f = f + + def write(self, x): + self.f.write(x) + self.f.flush() + + +def hasNoExtension(FileName): + (Root, Ext) = os.path.splitext(FileName) + return (Ext == "") + + +def isValidSingleInputFile(FileName): + (Root, Ext) = os.path.splitext(FileName) + return Ext in (".i", ".ii", ".c", ".cpp", ".m", "") + + +def getSDKPath(SDKName): + """ + Get the path to the SDK for the given SDK name. Returns None if + the path cannot be determined. + """ + if which("xcrun") is None: + return None + + Cmd = "xcrun --sdk " + SDKName + " --show-sdk-path" + return check_output(Cmd, shell=True).rstrip() + + +def runScript(ScriptPath, PBuildLogFile, Cwd): + """ + Run the provided script if it exists. + """ + if os.path.exists(ScriptPath): + try: + if Verbose == 1: + print " Executing: %s" % (ScriptPath,) + check_call("chmod +x '%s'" % ScriptPath, cwd=Cwd, + stderr=PBuildLogFile, + stdout=PBuildLogFile, + shell=True) + check_call("'%s'" % ScriptPath, cwd=Cwd, + stderr=PBuildLogFile, + stdout=PBuildLogFile, + shell=True) + except: + print "Error: Running %s failed. See %s for details." % ( + ScriptPath, PBuildLogFile.name) + sys.exit(-1) + + +class Discarder(object): + """ + Auxiliary object to discard stdout. + """ + def write(self, text): + pass # do nothing + + +def isCommentCSVLine(Entries): + """ + Treat CSV lines starting with a '#' as a comment. + """ + return len(Entries) > 0 and Entries[0].startswith("#") -- GitLab From de45a2e1b73ff6509f99c707ee553a6319ed25c7 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Tue, 24 Oct 2017 23:53:19 +0000 Subject: [PATCH 0057/1682] [Analyzer] Store BodyFarm in std::unique_ptr Differential Revision: https://reviews.llvm.org/D39220 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316536 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Analysis/AnalysisDeclContext.h | 4 +--- lib/Analysis/AnalysisDeclContext.cpp | 9 ++------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/include/clang/Analysis/AnalysisDeclContext.h b/include/clang/Analysis/AnalysisDeclContext.h index 1486071891..c9762818ad 100644 --- a/include/clang/Analysis/AnalysisDeclContext.h +++ b/include/clang/Analysis/AnalysisDeclContext.h @@ -421,7 +421,7 @@ class AnalysisDeclContextManager { /// Pointer to a factory for creating and caching implementations for common /// methods during the analysis. - BodyFarm *BdyFrm = nullptr; + std::unique_ptr BdyFrm; /// Flag to indicate whether or not bodies should be synthesized /// for well-known functions. @@ -438,8 +438,6 @@ public: bool addCXXNewAllocator = true, CodeInjector *injector = nullptr); - ~AnalysisDeclContextManager(); - AnalysisDeclContext *getContext(const Decl *D); bool getUseUnoptimizedCFG() const { diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp index 4408a0e0e4..17749db37c 100644 --- a/lib/Analysis/AnalysisDeclContext.cpp +++ b/lib/Analysis/AnalysisDeclContext.cpp @@ -306,8 +306,8 @@ AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) { BodyFarm *AnalysisDeclContextManager::getBodyFarm() { if (!BdyFrm) - BdyFrm = new BodyFarm(ASTCtx, Injector.get()); - return BdyFrm; + BdyFrm = llvm::make_unique(ASTCtx, Injector.get()); + return BdyFrm.get(); } const StackFrameContext * @@ -603,11 +603,6 @@ AnalysisDeclContext::~AnalysisDeclContext() { } } -AnalysisDeclContextManager::~AnalysisDeclContextManager() { - if (BdyFrm) - delete BdyFrm; -} - LocationContext::~LocationContext() {} LocationContextManager::~LocationContextManager() { -- GitLab From 207aa590d0843db47c1438c35bd782a30799a4c0 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Wed, 25 Oct 2017 00:03:45 +0000 Subject: [PATCH 0058/1682] [Analyzer] Remove unnecessary semicolon in analyzer tests. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316538 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/Analysis/call_once.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Analysis/call_once.cpp b/test/Analysis/call_once.cpp index 2154be6f48..5013cd423e 100644 --- a/test/Analysis/call_once.cpp +++ b/test/Analysis/call_once.cpp @@ -295,7 +295,7 @@ void test_mutator_noref() { // even when an ampersand is not explicitly set. void callbackn(int ¶m) { param = 42; -}; +} void test_implicit_funcptr() { int x = 0; static std::once_flag flagn; -- GitLab From 394bf73d81c550b9f084d0a6b465665696c4a238 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Wed, 25 Oct 2017 00:03:45 +0000 Subject: [PATCH 0059/1682] [Analyzer] Remove spaces inside comments mentioning the parameter name, to aid clang-tidy comprehension. Requested by @alexfh in https://reviews.llvm.org/D39015 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316539 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/BodyFarm.cpp | 68 +++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp index 8a56b761ec..58a129c411 100644 --- a/lib/Analysis/BodyFarm.cpp +++ b/lib/Analysis/BodyFarm.cpp @@ -168,10 +168,10 @@ ASTMaker::makeLvalueToRvalue(const VarDecl *Arg, ImplicitCastExpr *ASTMaker::makeImplicitCast(const Expr *Arg, QualType Ty, CastKind CK) { return ImplicitCastExpr::Create(C, Ty, - /* CastKind= */ CK, - /* Expr= */ const_cast(Arg), - /* CXXCastPath= */ nullptr, - /* ExprValueKind= */ VK_RValue); + /* CastKind=*/ CK, + /* Expr=*/ const_cast(Arg), + /* CXXCastPath=*/ nullptr, + /* ExprValueKind=*/ VK_RValue); } Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) { @@ -222,7 +222,7 @@ MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl, C, base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(), SourceLocation(), MemberDecl, FoundDecl, DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()), - /* TemplateArgumentListInfo= */ nullptr, MemberDecl->getType(), ValueKind, + /* TemplateArgumentListInfo=*/ nullptr, MemberDecl->getType(), ValueKind, OK_Ordinary); } @@ -231,7 +231,7 @@ ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) { CXXBasePaths Paths( /* FindAmbiguities=*/false, /* RecordPaths=*/false, - /* DetectVirtual= */ false); + /* DetectVirtual=*/ false); const IdentifierInfo &II = C.Idents.get(Name); DeclarationName DeclName = C.DeclarationNames.getIdentifier(&II); @@ -282,14 +282,14 @@ static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M, assert(callOperatorDecl != nullptr); DeclRefExpr *callOperatorDeclRef = - DeclRefExpr::Create(/* Ctx = */ C, - /* QualifierLoc = */ NestedNameSpecifierLoc(), - /* TemplateKWLoc = */ SourceLocation(), + DeclRefExpr::Create(/* Ctx =*/ C, + /* QualifierLoc =*/ NestedNameSpecifierLoc(), + /* TemplateKWLoc =*/ SourceLocation(), const_cast(callOperatorDecl), - /* RefersToEnclosingVariableOrCapture= */ false, - /* NameLoc = */ SourceLocation(), - /* T = */ callOperatorDecl->getType(), - /* VK = */ VK_LValue); + /* RefersToEnclosingVariableOrCapture=*/ false, + /* NameLoc =*/ SourceLocation(), + /* T =*/ callOperatorDecl->getType(), + /* VK =*/ VK_LValue); return new (C) CXXOperatorCallExpr(/*AstContext=*/C, OO_Call, callOperatorDeclRef, @@ -372,7 +372,7 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { // Lambda requires callback itself inserted as a first parameter. CallArgs.push_back( M.makeDeclRefExpr(Callback, - /* RefersToEnclosingVariableOrCapture= */ true)); + /* RefersToEnclosingVariableOrCapture=*/ true)); CallbackFunctionType = CallbackRecordDecl->getLambdaCallOperator() ->getType() ->getAs(); @@ -429,13 +429,13 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { // Negation predicate. UnaryOperator *FlagCheck = new (C) UnaryOperator( - /* input= */ + /* input=*/ M.makeImplicitCast(M.makeLvalueToRvalue(Deref, DerefType), DerefType, CK_IntegralToBoolean), - /* opc= */ UO_LNot, - /* QualType= */ C.IntTy, - /* ExprValueKind= */ VK_RValue, - /* ExprObjectKind= */ OK_Ordinary, SourceLocation()); + /* opc=*/ UO_LNot, + /* QualType=*/ C.IntTy, + /* ExprValueKind=*/ VK_RValue, + /* ExprObjectKind=*/ OK_Ordinary, SourceLocation()); // Create assignment. BinaryOperator *FlagAssignment = M.makeAssignment( @@ -443,11 +443,11 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { IfStmt *Out = new (C) IfStmt(C, SourceLocation(), - /* IsConstexpr= */ false, - /* init= */ nullptr, - /* var= */ nullptr, - /* cond= */ FlagCheck, - /* then= */ M.makeCompound({CallbackCall, FlagAssignment})); + /* IsConstexpr=*/ false, + /* init=*/ nullptr, + /* var=*/ nullptr, + /* cond=*/ FlagCheck, + /* then=*/ M.makeCompound({CallbackCall, FlagAssignment})); return Out; } @@ -522,19 +522,19 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { PredicateTy); UnaryOperator *UO = new (C) UnaryOperator( - /* input= */ LValToRval, - /* opc= */ UO_LNot, - /* QualType= */ C.IntTy, - /* ExprValueKind= */ VK_RValue, - /* ExprObjectKind= */ OK_Ordinary, SourceLocation()); + /* input=*/ LValToRval, + /* opc=*/ UO_LNot, + /* QualType=*/ C.IntTy, + /* ExprValueKind=*/ VK_RValue, + /* ExprObjectKind=*/ OK_Ordinary, SourceLocation()); // (5) Create the 'if' statement. IfStmt *If = new (C) IfStmt(C, SourceLocation(), - /* IsConstexpr= */ false, - /* init= */ nullptr, - /* var= */ nullptr, - /* cond= */ UO, - /* then= */ CS); + /* IsConstexpr=*/ false, + /* init=*/ nullptr, + /* var=*/ nullptr, + /* cond=*/ UO, + /* then=*/ CS); return If; } -- GitLab From 74154ad51df98d68aaa721ed57f02fb13deeec9a Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Wed, 25 Oct 2017 01:11:27 +0000 Subject: [PATCH 0060/1682] [clang-refactor] Use add_clang_tool CMake template This allows including clang-refactor in LLVM_DISTRIBUTION_COMPONENTS to build clang-refactor as part of the toolchain distribution. Differential Revision: https://reviews.llvm.org/D39266 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316540 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/clang-refactor/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/clang-refactor/CMakeLists.txt b/tools/clang-refactor/CMakeLists.txt index a472c40878..c20e83bacf 100644 --- a/tools/clang-refactor/CMakeLists.txt +++ b/tools/clang-refactor/CMakeLists.txt @@ -3,7 +3,7 @@ set(LLVM_LINK_COMPONENTS Support ) -add_clang_executable(clang-refactor +add_clang_tool(clang-refactor ClangRefactor.cpp TestSupport.cpp ) -- GitLab From 1a88ad380cc374c02bb8cf593812812afda4ea79 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Wed, 25 Oct 2017 02:31:38 +0000 Subject: [PATCH 0061/1682] [CMake] Include clang-refactor in Fuchsia toolchain This includes the clang-refactor in the toolchain distribution. Differential Revision: https://reviews.llvm.org/D39270 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316541 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/caches/Fuchsia-stage2.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/caches/Fuchsia-stage2.cmake b/cmake/caches/Fuchsia-stage2.cmake index 7b2f2213d3..c54ae9fbc1 100644 --- a/cmake/caches/Fuchsia-stage2.cmake +++ b/cmake/caches/Fuchsia-stage2.cmake @@ -97,6 +97,7 @@ set(LLVM_DISTRIBUTION_COMPONENTS LTO clang-format clang-headers + clang-refactor clang-tidy clangd builtins -- GitLab From da2ddee084120e1d31c63ee8a1f281980182bea8 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Wed, 25 Oct 2017 02:35:22 +0000 Subject: [PATCH 0062/1682] [CMake] Build host builtins in Fuchsia toolchain even on Darwin This is nedeeded for the toolchain to be actually usable as a host toolchain on Darwin. Differential Revision: https://reviews.llvm.org/D39273 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316542 91177308-0d34-0410-b5e6-96231b3b80d8 --- cmake/caches/Fuchsia-stage2.cmake | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cmake/caches/Fuchsia-stage2.cmake b/cmake/caches/Fuchsia-stage2.cmake index c54ae9fbc1..d2f19fd6d0 100644 --- a/cmake/caches/Fuchsia-stage2.cmake +++ b/cmake/caches/Fuchsia-stage2.cmake @@ -33,16 +33,12 @@ set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "") set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -gline-tables-only -DNDEBUG" CACHE STRING "") -set(LLVM_BUILTIN_TARGETS "x86_64-fuchsia;aarch64-fuchsia" CACHE STRING "") +set(LLVM_BUILTIN_TARGETS "default;x86_64-fuchsia;aarch64-fuchsia" CACHE STRING "") foreach(target x86_64;aarch64) set(BUILTINS_${target}-fuchsia_CMAKE_SYSROOT ${FUCHSIA_${target}_SYSROOT} CACHE PATH "") set(BUILTINS_${target}-fuchsia_CMAKE_SYSTEM_NAME Fuchsia CACHE STRING "") endforeach() -if(NOT APPLE) - set(LLVM_BUILTIN_TARGETS "default;${LLVM_BUILTIN_TARGETS}" CACHE STRING "" FORCE) -endif() - set(LLVM_RUNTIME_TARGETS "default;x86_64-fuchsia;aarch64-fuchsia;x86_64-fuchsia-asan:x86_64-fuchsia;aarch64-fuchsia-asan:aarch64-fuchsia" CACHE STRING "") foreach(target x86_64;aarch64) set(RUNTIMES_${target}-fuchsia_CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "") -- GitLab From fcbf0e691cc9ae899dc900f9634e18a20b2b141c Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 25 Oct 2017 03:58:15 +0000 Subject: [PATCH 0063/1682] CodeGen: fix a case of incorrect checks for ivars Ensure that we check the ivar containing decl for the DLL storage attribute rather than the ivar itself as the dll storage is associated to the interface decl not the ivar decl. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316545 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGObjCMac.cpp | 12 ++++++++---- test/CodeGenObjC/dllstorage.m | 10 ++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 98435fefbd..85901a6d65 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -6615,10 +6615,14 @@ CGObjCNonFragileABIMac::ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID, Ivar->getAccessControl() == ObjCIvarDecl::Private || Ivar->getAccessControl() == ObjCIvarDecl::Package; - if (ID->hasAttr() && !IsPrivateOrPackage) - IvarOffsetGV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); - else if (ID->hasAttr()) - IvarOffsetGV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + const ObjCInterfaceDecl *ContainingID = Ivar->getContainingInterface(); + + if (ContainingID->hasAttr()) + IvarOffsetGV + ->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + else if (ContainingID->hasAttr() && !IsPrivateOrPackage) + IvarOffsetGV + ->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); } } return IvarOffsetGV; diff --git a/test/CodeGenObjC/dllstorage.m b/test/CodeGenObjC/dllstorage.m index 4bdbd50915..a2665eefad 100644 --- a/test/CodeGenObjC/dllstorage.m +++ b/test/CodeGenObjC/dllstorage.m @@ -1,3 +1,4 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -fdeclspec -fobjc-runtime=ios -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -check-prefix CHECK-IR %s // RUN: %clang_cc1 -triple i686-windows-itanium -fms-extensions -fobjc-runtime=macosx -fdeclspec -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -check-prefix CHECK-IR %s // RUN: %clang_cc1 -triple i686-windows-itanium -fms-extensions -fobjc-runtime=objfw -fdeclspec -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -check-prefix CHECK-FW %s @@ -114,6 +115,15 @@ __attribute__((__objc_exception__)) // CHECK-IR-DAG: @"OBJC_EHTYPE_$_P" = external global %struct._objc_typeinfo +@interface Q : M +@end + +id f(Q *q) { + return q->_ivar; +} + +// CHECK-IR-DAG: @"OBJC_IVAR_$_M._ivar" = external dllimport global i32 + int g() { @autoreleasepool { M *mi = [M new]; -- GitLab From 890783b5e028a061bb51a4a978e8114b55073932 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 25 Oct 2017 08:25:25 +0000 Subject: [PATCH 0064/1682] [clang-rename] Fix and enable the failing TemplatedClassFunction test. Reviewers: ioeric Reviewed By: ioeric Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D39241 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316561 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Refactoring/Rename/USRFindingAction.cpp | 20 +++++++++++++++++++ test/clang-rename/TemplatedClassFunction.cpp | 17 ++++++++++------ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp b/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp index 0c746bbbcb..40b70d8a05 100644 --- a/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp +++ b/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp @@ -73,6 +73,7 @@ public: if (checkIfOverriddenFunctionAscends(OverriddenMethod)) USRSet.insert(getUSRForDecl(OverriddenMethod)); } + addUSRsOfInstantiatedMethods(MethodDecl); } else if (const auto *RecordDecl = dyn_cast(FoundDecl)) { handleCXXRecordDecl(RecordDecl); } else if (const auto *TemplateDecl = @@ -84,9 +85,13 @@ public: return std::vector(USRSet.begin(), USRSet.end()); } + bool shouldVisitTemplateInstantiations() const { return true; } + bool VisitCXXMethodDecl(const CXXMethodDecl *MethodDecl) { if (MethodDecl->isVirtual()) OverriddenMethods.push_back(MethodDecl); + if (MethodDecl->getInstantiatedFromMemberFunction()) + InstantiatedMethods.push_back(MethodDecl); return true; } @@ -137,6 +142,20 @@ private: addUSRsOfOverridenFunctions(OverriddenMethod); } + void addUSRsOfInstantiatedMethods(const CXXMethodDecl *MethodDecl) { + // For renaming a class template method, all references of the instantiated + // member methods should be renamed too, so add USRs of the instantiated + // methods to the USR set. + USRSet.insert(getUSRForDecl(MethodDecl)); + if (const auto *FT = MethodDecl->getInstantiatedFromMemberFunction()) + USRSet.insert(getUSRForDecl(FT)); + for (const auto *Method : InstantiatedMethods) { + if (USRSet.find(getUSRForDecl( + Method->getInstantiatedFromMemberFunction())) != USRSet.end()) + USRSet.insert(getUSRForDecl(Method)); + } + } + bool checkIfOverriddenFunctionAscends(const CXXMethodDecl *MethodDecl) { for (const auto &OverriddenMethod : MethodDecl->overridden_methods()) { if (USRSet.find(getUSRForDecl(OverriddenMethod)) != USRSet.end()) @@ -150,6 +169,7 @@ private: ASTContext &Context; std::set USRSet; std::vector OverriddenMethods; + std::vector InstantiatedMethods; std::vector PartialSpecs; }; } // namespace diff --git a/test/clang-rename/TemplatedClassFunction.cpp b/test/clang-rename/TemplatedClassFunction.cpp index 1f5b0b52ba..d7f21e0847 100644 --- a/test/clang-rename/TemplatedClassFunction.cpp +++ b/test/clang-rename/TemplatedClassFunction.cpp @@ -6,17 +6,22 @@ public: int main(int argc, char **argv) { A a; - a.foo(); /* Test 2 */ // CHECK: a.bar() /* Test 2 */ + A b; + A c; + a.foo(); /* Test 2 */ // CHECK: a.bar(); /* Test 2 */ + b.foo(); /* Test 3 */ // CHECK: b.bar(); /* Test 3 */ + c.foo(); /* Test 4 */ // CHECK: c.bar(); /* Test 4 */ return 0; } // Test 1. -// RUN: clang-refactor rename -offset=48 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s +// RUN: clang-rename -offset=48 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s // Test 2. -// RUN: clang-refactor rename -offset=162 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s -// -// Currently unsupported test. -// XFAIL: * +// RUN: clang-rename -offset=191 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 3. +// RUN: clang-rename -offset=255 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s +// Test 4. +// RUN: clang-rename -offset=319 -new-name=bar %s -- | sed 's,//.*,,' | FileCheck %s // To find offsets after modifying the file, use: // grep -Ubo 'foo.*' -- GitLab From 2bcd2d052e5508c12374390e4a2d572988622caf Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 25 Oct 2017 11:54:45 +0000 Subject: [PATCH 0065/1682] [rename] support renaming class member. Reviewers: ioeric Reviewed By: ioeric Subscribers: klimek, cfe-commits, mgorny Differential Revision: https://reviews.llvm.org/D39178 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316571 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Refactoring/Rename/USRLocFinder.cpp | 49 ++++ unittests/Rename/CMakeLists.txt | 1 + unittests/Rename/RenameMemberTest.cpp | 229 ++++++++++++++++++ 3 files changed, 279 insertions(+) create mode 100644 unittests/Rename/RenameMemberTest.cpp diff --git a/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp b/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp index 38b2a624ea..c77304a173 100644 --- a/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp +++ b/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp @@ -212,6 +212,41 @@ public: return true; } + bool VisitMemberExpr(const MemberExpr *Expr) { + const NamedDecl *Decl = Expr->getFoundDecl(); + auto StartLoc = Expr->getMemberLoc(); + auto EndLoc = Expr->getMemberLoc(); + if (isInUSRSet(Decl)) { + RenameInfos.push_back({StartLoc, EndLoc, + /*FromDecl=*/nullptr, + /*Context=*/nullptr, + /*Specifier=*/nullptr, + /*IgnorePrefixQualifiers=*/true}); + } + return true; + } + + bool VisitCXXConstructorDecl(const CXXConstructorDecl *CD) { + // Fix the constructor initializer when renaming class members. + for (const auto *Initializer : CD->inits()) { + // Ignore implicit initializers. + if (!Initializer->isWritten()) + continue; + + if (const FieldDecl *FD = Initializer->getMember()) { + if (isInUSRSet(FD)) { + auto Loc = Initializer->getSourceLocation(); + RenameInfos.push_back({Loc, Loc, + /*FromDecl=*/nullptr, + /*Context=*/nullptr, + /*Specifier=*/nullptr, + /*IgnorePrefixQualifiers=*/true}); + } + } + } + return true; + } + bool VisitDeclRefExpr(const DeclRefExpr *Expr) { const NamedDecl *Decl = Expr->getFoundDecl(); // Get the underlying declaration of the shadow declaration introduced by a @@ -227,6 +262,20 @@ public: ? Expr->getLAngleLoc().getLocWithOffset(-1) : Expr->getLocEnd(); + if (const auto *MD = llvm::dyn_cast(Decl)) { + if (isInUSRSet(MD)) { + // Handle renaming static template class methods, we only rename the + // name without prefix qualifiers and restrict the source range to the + // name. + RenameInfos.push_back({EndLoc, EndLoc, + /*FromDecl=*/nullptr, + /*Context=*/nullptr, + /*Specifier=*/nullptr, + /*IgnorePrefixQualifiers=*/true}); + return true; + } + } + // In case of renaming an enum declaration, we have to explicitly handle // unscoped enum constants referenced in expressions (e.g. // "auto r = ns1::ns2::Green" where Green is an enum constant of an unscoped diff --git a/unittests/Rename/CMakeLists.txt b/unittests/Rename/CMakeLists.txt index 1c50fde37d..cecb2d39b9 100644 --- a/unittests/Rename/CMakeLists.txt +++ b/unittests/Rename/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_unittest(ClangRenameTests RenameClassTest.cpp RenameEnumTest.cpp RenameAliasTest.cpp + RenameMemberTest.cpp RenameFunctionTest.cpp ) diff --git a/unittests/Rename/RenameMemberTest.cpp b/unittests/Rename/RenameMemberTest.cpp new file mode 100644 index 0000000000..463f7c70de --- /dev/null +++ b/unittests/Rename/RenameMemberTest.cpp @@ -0,0 +1,229 @@ +//===-- ClangMemberTests.cpp - unit tests for renaming class members ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ClangRenameTest.h" + +namespace clang { +namespace clang_rename { +namespace test { +namespace { + +class RenameMemberTest : public ClangRenameTest { +public: + RenameMemberTest() { + AppendToHeader(R"( + struct NA { + void Foo(); + void NotFoo(); + static void SFoo(); + static void SNotFoo(); + int Moo; + }; + struct A { + virtual void Foo(); + void NotFoo(); + static void SFoo(); + static void SNotFoo(); + int Moo; + int NotMoo; + static int SMoo; + }; + struct B : public A { + void Foo() override; + }; + template struct TA { + T* Foo(); + T* NotFoo(); + static T* SFoo(); + static T* NotSFoo(); + }; + template struct TB : public TA {}; + namespace ns { + template struct TA { + T* Foo(); + T* NotFoo(); + static T* SFoo(); + static T* NotSFoo(); + static int SMoo; + }; + template struct TB : public TA {}; + struct A { + void Foo(); + void NotFoo(); + static void SFoo(); + static void SNotFoo(); + }; + struct B : public A {}; + struct C { + template + void SFoo(const T& t) {} + template + void Foo() {} + }; + })"); + } +}; + +INSTANTIATE_TEST_CASE_P( + DISABLED_RenameTemplatedClassStaticVariableTest, RenameMemberTest, + testing::ValuesIn(std::vector({ + // FIXME: support renaming static variables for template classes. + {"void f() { ns::TA::SMoo; }", + "void f() { ns::TA::SMeh; }", "ns::TA::SMoo", "ns::TA::SMeh"}, + })), ); + +INSTANTIATE_TEST_CASE_P( + RenameMemberTest, RenameMemberTest, + testing::ValuesIn(std::vector({ + // Normal methods and fields. + {"void f() { A a; a.Foo(); }", "void f() { A a; a.Bar(); }", "A::Foo", + "A::Bar"}, + {"void f() { ns::A a; a.Foo(); }", "void f() { ns::A a; a.Bar(); }", + "ns::A::Foo", "ns::A::Bar"}, + {"void f() { A a; int x = a.Moo; }", "void f() { A a; int x = a.Meh; }", + "A::Moo", "A::Meh"}, + {"void f() { B b; b.Foo(); }", "void f() { B b; b.Bar(); }", "B::Foo", + "B::Bar"}, + {"void f() { ns::B b; b.Foo(); }", "void f() { ns::B b; b.Bar(); }", + "ns::A::Foo", "ns::A::Bar"}, + {"void f() { B b; int x = b.Moo; }", "void f() { B b; int x = b.Meh; }", + "A::Moo", "A::Meh"}, + + // Static methods. + {"void f() { A::SFoo(); }", "void f() { A::SBar(); }", "A::SFoo", + "A::SBar"}, + {"void f() { ns::A::SFoo(); }", "void f() { ns::A::SBar(); }", + "ns::A::SFoo", "ns::A::SBar"}, + {"void f() { TA::SFoo(); }", "void f() { TA::SBar(); }", + "TA::SFoo", "TA::SBar"}, + {"void f() { ns::TA::SFoo(); }", + "void f() { ns::TA::SBar(); }", "ns::TA::SFoo", "ns::TA::SBar"}, + + // Static variables. + {"void f() { A::SMoo; }", + "void f() { A::SMeh; }", "A::SMoo", "A::SMeh"}, + + // Templated methods. + {"void f() { TA a; a.Foo(); }", "void f() { TA a; a.Bar(); }", + "TA::Foo", "TA::Bar"}, + {"void f() { ns::TA a; a.Foo(); }", + "void f() { ns::TA a; a.Bar(); }", "ns::TA::Foo", "ns::TA::Bar"}, + {"void f() { TB b; b.Foo(); }", "void f() { TB b; b.Bar(); }", + "TA::Foo", "TA::Bar"}, + {"void f() { ns::TB b; b.Foo(); }", + "void f() { ns::TB b; b.Bar(); }", "ns::TA::Foo", "ns::TA::Bar"}, + {"void f() { ns::C c; int x; c.SFoo(x); }", + "void f() { ns::C c; int x; c.SBar(x); }", "ns::C::SFoo", + "ns::C::SBar"}, + {"void f() { ns::C c; c.Foo(); }", + "void f() { ns::C c; c.Bar(); }", "ns::C::Foo", "ns::C::Bar"}, + + // Pointers to methods. + {"void f() { auto p = &A::Foo; }", "void f() { auto p = &A::Bar; }", + "A::Foo", "A::Bar"}, + {"void f() { auto p = &A::SFoo; }", "void f() { auto p = &A::SBar; }", + "A::SFoo", "A::SBar"}, + {"void f() { auto p = &B::Foo; }", "void f() { auto p = &B::Bar; }", + "B::Foo", "B::Bar"}, + {"void f() { auto p = &ns::A::Foo; }", + "void f() { auto p = &ns::A::Bar; }", "ns::A::Foo", "ns::A::Bar"}, + {"void f() { auto p = &ns::A::SFoo; }", + "void f() { auto p = &ns::A::SBar; }", "ns::A::SFoo", "ns::A::SBar"}, + {"void f() { auto p = &ns::C::SFoo; }", + "void f() { auto p = &ns::C::SBar; }", "ns::C::SFoo", + "ns::C::SBar"}, + + // These methods are not declared or overrided in the subclass B, we + // have to use the qualified name with parent class A to identify them. + {"void f() { auto p = &ns::B::Foo; }", + "void f() { auto p = &ns::B::Bar; }", "ns::A::Foo", "ns::B::Bar"}, + {"void f() { B::SFoo(); }", "void f() { B::SBar(); }", "A::SFoo", + "B::SBar"}, + {"void f() { ns::B::SFoo(); }", "void f() { ns::B::SBar(); }", + "ns::A::SFoo", "ns::B::SBar"}, + {"void f() { auto p = &B::SFoo; }", "void f() { auto p = &B::SBar; }", + "A::SFoo", "B::SBar"}, + {"void f() { auto p = &ns::B::SFoo; }", + "void f() { auto p = &ns::B::SBar; }", "ns::A::SFoo", "ns::B::SBar"}, + {"void f() { TB::SFoo(); }", "void f() { TB::SBar(); }", + "TA::SFoo", "TB::SBar"}, + {"void f() { ns::TB::SFoo(); }", + "void f() { ns::TB::SBar(); }", "ns::TA::SFoo", "ns::TB::SBar"}, + })), ); + +TEST_P(RenameMemberTest, RenameMembers) { + auto Param = GetParam(); + assert(!Param.OldName.empty()); + assert(!Param.NewName.empty()); + std::string Actual = + runClangRenameOnCode(Param.Before, Param.OldName, Param.NewName); + CompareSnippets(Param.After, Actual); +} + +TEST_F(RenameMemberTest, RenameMemberInsideClassMethods) { + std::string Before = R"( + struct X { + int Moo; + void Baz() { Moo = 1; } + };)"; + std::string Expected = R"( + struct X { + int Meh; + void Baz() { Meh = 1; } + };)"; + std::string After = runClangRenameOnCode(Before, "X::Moo", "Y::Meh"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameMemberTest, RenameMethodInsideClassMethods) { + std::string Before = R"( + struct X { + void Foo() {} + void Baz() { Foo(); } + };)"; + std::string Expected = R"( + struct X { + void Bar() {} + void Baz() { Bar(); } + };)"; + std::string After = runClangRenameOnCode(Before, "X::Foo", "X::Bar"); + CompareSnippets(Expected, After); +} + +TEST_F(RenameMemberTest, RenameCtorInitializer) { + std::string Before = R"( + class X { + public: + X(); + A a; + A a2; + B b; + }; + + X::X():a(), b() {} + )"; + std::string Expected = R"( + class X { + public: + X(); + A bar; + A a2; + B b; + }; + + X::X():bar(), b() {} + )"; + std::string After = runClangRenameOnCode(Before, "X::a", "X::bar"); + CompareSnippets(Expected, After); +} + +} // anonymous namespace +} // namespace test +} // namespace clang_rename +} // namesdpace clang -- GitLab From c995e069f7d65eaec90a380e6977248bad6c3dc6 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Wed, 25 Oct 2017 14:21:33 +0000 Subject: [PATCH 0066/1682] Add support of the next Ubuntu (Ubuntu 18.04 - Bionic Beaver) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316577 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Driver/Distro.h | 1 + lib/Driver/Distro.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/include/clang/Driver/Distro.h b/include/clang/Driver/Distro.h index fab49862a4..6574fbca38 100644 --- a/include/clang/Driver/Distro.h +++ b/include/clang/Driver/Distro.h @@ -58,6 +58,7 @@ public: UbuntuYakkety, UbuntuZesty, UbuntuArtful, + UbuntuBionic, UnknownDistro }; diff --git a/lib/Driver/Distro.cpp b/lib/Driver/Distro.cpp index 2df297f3cf..437641b23d 100644 --- a/lib/Driver/Distro.cpp +++ b/lib/Driver/Distro.cpp @@ -48,6 +48,7 @@ static Distro::DistroType DetectDistro(vfs::FileSystem &VFS) { .Case("yakkety", Distro::UbuntuYakkety) .Case("zesty", Distro::UbuntuZesty) .Case("artful", Distro::UbuntuArtful) + .Case("bionic", Distro::UbuntuBionic) .Default(Distro::UnknownDistro); if (Version != Distro::UnknownDistro) return Version; -- GitLab From d26e800a52facae18ce2324dcd328ba575995c82 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Wed, 25 Oct 2017 14:23:27 +0000 Subject: [PATCH 0067/1682] Also update IsUbuntu() with Ubuntu Bionic Follow up of r316577 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316578 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Driver/Distro.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/clang/Driver/Distro.h b/include/clang/Driver/Distro.h index 6574fbca38..f079ceb73e 100644 --- a/include/clang/Driver/Distro.h +++ b/include/clang/Driver/Distro.h @@ -112,7 +112,7 @@ public: } bool IsUbuntu() const { - return DistroVal >= UbuntuHardy && DistroVal <= UbuntuArtful; + return DistroVal >= UbuntuHardy && DistroVal <= UbuntuBionic; } /// @} -- GitLab From b3749a3005224bbd2941a3517088a19002d81134 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Wed, 25 Oct 2017 14:25:28 +0000 Subject: [PATCH 0068/1682] Add support of the next Debian (Debian buster - version 10) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316579 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Driver/Distro.h | 3 ++- lib/Driver/Distro.cpp | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/clang/Driver/Distro.h b/include/clang/Driver/Distro.h index f079ceb73e..eeb4f25f34 100644 --- a/include/clang/Driver/Distro.h +++ b/include/clang/Driver/Distro.h @@ -32,6 +32,7 @@ public: DebianWheezy, DebianJessie, DebianStretch, + DebianBuster, Exherbo, RHEL5, RHEL6, @@ -108,7 +109,7 @@ public: } bool IsDebian() const { - return DistroVal >= DebianLenny && DistroVal <= DebianStretch; + return DistroVal >= DebianLenny && DistroVal <= DebianBuster; } bool IsUbuntu() const { diff --git a/lib/Driver/Distro.cpp b/lib/Driver/Distro.cpp index 437641b23d..9a0b854e32 100644 --- a/lib/Driver/Distro.cpp +++ b/lib/Driver/Distro.cpp @@ -89,6 +89,8 @@ static Distro::DistroType DetectDistro(vfs::FileSystem &VFS) { return Distro::DebianJessie; case 9: return Distro::DebianStretch; + case 10: + return Distro::DebianBuster; default: return Distro::UnknownDistro; } -- GitLab From f5a3eef96117aae3537285eac87e375adab1e2ff Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Wed, 25 Oct 2017 15:44:52 +0000 Subject: [PATCH 0069/1682] [OPENMP] Constify function parameters, NFC. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316584 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaOpenMP.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index bf89eb0b2f..82e7967fb2 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -4322,7 +4322,7 @@ static bool FitsInto(unsigned Bits, bool Signed, Expr *E, Sema &SemaRef) { /// Build preinits statement for the given declarations. static Stmt *buildPreInits(ASTContext &Context, - SmallVectorImpl &PreInits) { + MutableArrayRef PreInits) { if (!PreInits.empty()) { return new (Context) DeclStmt( DeclGroupRef::Create(Context, PreInits.begin(), PreInits.size()), @@ -4332,8 +4332,9 @@ static Stmt *buildPreInits(ASTContext &Context, } /// Build preinits statement for the given declarations. -static Stmt *buildPreInits(ASTContext &Context, - llvm::MapVector &Captures) { +static Stmt * +buildPreInits(ASTContext &Context, + const llvm::MapVector &Captures) { if (!Captures.empty()) { SmallVector PreInits; for (auto &Pair : Captures) -- GitLab From 1596739a8b396239d79587ca47c17239e04e8fa2 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Wed, 25 Oct 2017 15:54:04 +0000 Subject: [PATCH 0070/1682] [OPENMP] Improve debug info for taskgroup implicitly generated expressions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316585 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaOpenMP.cpp | 28 +++++++++---------- .../taskgroup_task_reduction_codegen.cpp | 20 +++++++------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 82e7967fb2..941ac75fa6 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -835,10 +835,10 @@ void DSAStackTy::addTaskgroupReductionData(ValueDecl *D, SourceRange SR, Expr *&TaskgroupReductionRef = Stack.back().first.back().TaskgroupReductionRef; if (!TaskgroupReductionRef) { - auto *VD = buildVarDecl(SemaRef, SourceLocation(), + auto *VD = buildVarDecl(SemaRef, SR.getBegin(), SemaRef.Context.VoidPtrTy, ".task_red."); - TaskgroupReductionRef = buildDeclRefExpr( - SemaRef, VD, SemaRef.Context.VoidPtrTy, SourceLocation()); + TaskgroupReductionRef = + buildDeclRefExpr(SemaRef, VD, SemaRef.Context.VoidPtrTy, SR.getBegin()); } } @@ -858,10 +858,10 @@ void DSAStackTy::addTaskgroupReductionData(ValueDecl *D, SourceRange SR, Expr *&TaskgroupReductionRef = Stack.back().first.back().TaskgroupReductionRef; if (!TaskgroupReductionRef) { - auto *VD = buildVarDecl(SemaRef, SourceLocation(), - SemaRef.Context.VoidPtrTy, ".task_red."); - TaskgroupReductionRef = buildDeclRefExpr( - SemaRef, VD, SemaRef.Context.VoidPtrTy, SourceLocation()); + auto *VD = buildVarDecl(SemaRef, SR.getBegin(), SemaRef.Context.VoidPtrTy, + ".task_red."); + TaskgroupReductionRef = + buildDeclRefExpr(SemaRef, VD, SemaRef.Context.VoidPtrTy, SR.getBegin()); } } @@ -9720,8 +9720,7 @@ static bool ActOnOMPReductionKindClause( // (type of the variable or single array element). PrivateTy = Context.getVariableArrayType( Type, - new (Context) OpaqueValueExpr(SourceLocation(), Context.getSizeType(), - VK_RValue), + new (Context) OpaqueValueExpr(ELoc, Context.getSizeType(), VK_RValue), ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange()); } else if (!ASE && !OASE && Context.getAsArrayType(D->getType().getNonReferenceType())) @@ -9803,8 +9802,7 @@ static bool ActOnOMPReductionKindClause( if (Type->isPointerType()) { // Cast to pointer type. auto CastExpr = S.BuildCStyleCastExpr( - SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc), - SourceLocation(), Init); + ELoc, Context.getTrivialTypeSourceInfo(Type, ELoc), ELoc, Init); if (CastExpr.isInvalid()) continue; Init = CastExpr.get(); @@ -9898,9 +9896,9 @@ static bool ActOnOMPReductionKindClause( S.BuildBinOp(Stack->getCurScope(), ReductionId.getLocStart(), BO_Assign, LHSDRE, ReductionOp.get()); } else { - auto *ConditionalOp = new (Context) ConditionalOperator( - ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(), - RHSDRE, Type, VK_LValue, OK_Ordinary); + auto *ConditionalOp = new (Context) + ConditionalOperator(ReductionOp.get(), ELoc, LHSDRE, ELoc, RHSDRE, + Type, VK_LValue, OK_Ordinary); ReductionOp = S.BuildBinOp(Stack->getCurScope(), ReductionId.getLocStart(), BO_Assign, LHSDRE, ConditionalOp); @@ -10782,7 +10780,7 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, } bool Suppress = getDiagnostics().getSuppressAllDiagnostics(); getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); - ExprResult Res = CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, + ExprResult Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RefExpr->IgnoreParenImpCasts()); getDiagnostics().setSuppressAllDiagnostics(Suppress); if (!Res.isUsable() && !isa(SimpleExpr)) { diff --git a/test/OpenMP/taskgroup_task_reduction_codegen.cpp b/test/OpenMP/taskgroup_task_reduction_codegen.cpp index 884d0022a8..63e0151824 100644 --- a/test/OpenMP/taskgroup_task_reduction_codegen.cpp +++ b/test/OpenMP/taskgroup_task_reduction_codegen.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -x c++ -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ %s -verify -debug-info-kind=limited -emit-llvm -o - -triple x86_64-apple-darwin10 | FileCheck %s --check-prefix=CHECK --check-prefix=DEBUG // expected-no-diagnostics #ifndef HEADER #define HEADER @@ -34,7 +35,7 @@ int main(int argc, char **argv) { // CHECK: [[A:%.+]] = alloca i32, // CHECK: [[B:%.+]] = alloca float, // CHECK: [[C:%.+]] = alloca [5 x %struct.S], -// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(%ident_t* @0) +// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(%ident_t* // CHECK: [[RD_IN1:%.+]] = alloca [3 x [[T1:%[^,]+]]], // CHECK: [[TD1:%.+]] = alloca i8*, // CHECK: [[RD_IN2:%.+]] = alloca [2 x [[T2:%[^,]+]]], @@ -42,7 +43,7 @@ int main(int argc, char **argv) { // CHECK: [[VLA:%.+]] = alloca i16, i64 [[VLA_SIZE:%[^,]+]], -// CHECK: call void @__kmpc_taskgroup(%ident_t* @0, i32 [[GTID]]) +// CHECK: call void @__kmpc_taskgroup(%ident_t* {{[^,]+}}, i32 [[GTID]]) // CHECK-DAG: [[BC_A:%.+]] = bitcast i32* [[A]] to i8* // CHECK-DAG: store i8* [[BC_A]], i8** [[A_REF:[^,]+]], // CHECK-DAG: [[A_REF]] = getelementptr inbounds [[T1]], [[T1]]* [[GEPA:%[^,]+]], i32 0, i32 0 @@ -90,8 +91,9 @@ int main(int argc, char **argv) { // CHECK-DAG: call void @llvm.memset.p0i8.i64(i8* [[TMP27]], i8 0, i64 4, i32 8, i1 false) // CHECK-DAG: [[TMP28:%.+]] = bitcast [3 x [[T1]]]* [[RD_IN1]] to i8* // CHECK-DAG: [[TMP29:%.+]] = call i8* @__kmpc_task_reduction_init(i32 [[GTID]], i32 3, i8* [[TMP28]]) +// DEBUG-DAG: call void @llvm.dbg.declare(metadata i8** [[TD1]], // CHECK-DAG: store i8* [[TMP29]], i8** [[TD1]], -// CHECK-DAG: call void @__kmpc_taskgroup(%ident_t* @0, i32 [[GTID]]) +// CHECK-DAG: call void @__kmpc_taskgroup(%ident_t* {{[^,]+}}, i32 [[GTID]]) // CHECK-DAG: [[TMP31:%.+]] = bitcast [5 x %struct.S]* [[C]] to i8* // CHECK-DAG: store i8* [[TMP31]], i8** [[TMP30:%[^,]+]], // CHECK-DAG: [[TMP30]] = getelementptr inbounds [[T2]], [[T2]]* [[GEPC:%[^,]+]], i32 0, i32 0 @@ -126,8 +128,8 @@ int main(int argc, char **argv) { // CHECK: [[TMP47:%.+]] = bitcast [2 x [[T2]]]* [[RD_IN2]] to i8* // CHECK: [[TMP48:%.+]] = call i8* @__kmpc_task_reduction_init(i32 [[GTID]], i32 2, i8* [[TMP47]]) // CHECK: store i8* [[TMP48]], i8** [[TD2]], -// CHECK: call void @__kmpc_end_taskgroup(%ident_t* @0, i32 [[GTID]]) -// CHECK: call void @__kmpc_end_taskgroup(%ident_t* @0, i32 [[GTID]]) +// CHECK: call void @__kmpc_end_taskgroup(%ident_t* {{[^,]+}}, i32 [[GTID]]) +// CHECK: call void @__kmpc_end_taskgroup(%ident_t* {{[^,]+}}, i32 [[GTID]]) // CHECK-DAG: define internal void [[AINIT]](i8*) // CHECK-DAG: store i32 0, i32* % @@ -187,8 +189,8 @@ int main(int argc, char **argv) { // CHECK_DAG: } // CHECK-DAG: define internal void [[VLAINIT]](i8*) -// CHECK-DAG: call i32 @__kmpc_global_thread_num(%ident_t* @0) -// CHECK-DAG: call i8* @__kmpc_threadprivate_cached(%ident_t* @0, i32 % +// CHECK-DAG: call i32 @__kmpc_global_thread_num(%ident_t* {{[^,]+}}) +// CHECK-DAG: call i8* @__kmpc_threadprivate_cached(%ident_t* // CHECK-DAG: phi i16* [ // CHECK-DAG: store i16 0, i16* % // CHECK-DAG: br i1 % @@ -196,8 +198,8 @@ int main(int argc, char **argv) { // CHECK-DAG: } // CHECK-DAG: define internal void [[VLACOMB]](i8*, i8*) -// CHECK-DAG: call i32 @__kmpc_global_thread_num(%ident_t* @0) -// CHECK-DAG: call i8* @__kmpc_threadprivate_cached(%ident_t* @0, i32 % +// CHECK-DAG: call i32 @__kmpc_global_thread_num(%ident_t* {{[^,]+}}) +// CHECK-DAG: call i8* @__kmpc_threadprivate_cached(%ident_t* // CHECK-DAG: phi i16* [ // CHECK-DAG: phi i16* [ // CHECK-DAG: sext i16 %{{.+}} to i32 -- GitLab From 8dd10149220bca422ddbcd7dfa56aa51363c6e6a Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Wed, 25 Oct 2017 17:10:58 +0000 Subject: [PATCH 0071/1682] [X86] Add avx512vpopcntdq to Knights Mill As indicated by Table 1-1 in Intel Architecture Instruction Set Extensions and Future Features Programming Reference from October 2017. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316593 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Basic/Targets/X86.cpp | 2 ++ test/Preprocessor/predefined-arch-macros.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/Basic/Targets/X86.cpp b/lib/Basic/Targets/X86.cpp index 644cf467b0..d2716ac670 100644 --- a/lib/Basic/Targets/X86.cpp +++ b/lib/Basic/Targets/X86.cpp @@ -231,6 +231,8 @@ bool X86TargetInfo::initFeatureMap( case CK_KNM: // TODO: Add avx5124fmaps/avx5124vnniw. + setFeatureEnabledImpl(Features, "avx512vpopcntdq", true); + LLVM_FALLTHROUGH; case CK_KNL: setFeatureEnabledImpl(Features, "avx512f", true); setFeatureEnabledImpl(Features, "avx512cd", true); diff --git a/test/Preprocessor/predefined-arch-macros.c b/test/Preprocessor/predefined-arch-macros.c index 06faf0eade..43dc469d3e 100644 --- a/test/Preprocessor/predefined-arch-macros.c +++ b/test/Preprocessor/predefined-arch-macros.c @@ -793,6 +793,7 @@ // CHECK_KNM_M32: #define __AVX512ER__ 1 // CHECK_KNM_M32: #define __AVX512F__ 1 // CHECK_KNM_M32: #define __AVX512PF__ 1 +// CHECK_KNM_M32: #define __AVX512VPOPCNTDQ__ 1 // CHECK_KNM_M32: #define __AVX__ 1 // CHECK_KNM_M32: #define __BMI2__ 1 // CHECK_KNM_M32: #define __BMI__ 1 @@ -826,6 +827,7 @@ // CHECK_KNM_M64: #define __AVX512ER__ 1 // CHECK_KNM_M64: #define __AVX512F__ 1 // CHECK_KNM_M64: #define __AVX512PF__ 1 +// CHECK_KNM_M64: #define __AVX512VPOPCNTDQ__ 1 // CHECK_KNM_M64: #define __AVX__ 1 // CHECK_KNM_M64: #define __BMI2__ 1 // CHECK_KNM_M64: #define __BMI__ 1 -- GitLab From 5da49565c168f50d865783a0b7f6e6881ecbee34 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 25 Oct 2017 17:56:50 +0000 Subject: [PATCH 0072/1682] CodeGen: fix PPC Darwin variadics Darwin uses char * for the variadic list type (va_list). We use the PPC SVR4 ABI for PPC, which uses a structure type for the va_list. When constructing the GEP, we would fail due to the incorrect handling for the va_list. Correct this to use the right type. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316599 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/TargetInfo.cpp | 38 ++++++++++++++++++++++++++++++- test/CodeGen/darwin-ppc-varargs.c | 28 +++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 test/CodeGen/darwin-ppc-varargs.c diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 2651d87389..b1773b7090 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -4036,7 +4036,10 @@ Address WinX86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, namespace { /// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information. class PPC32_SVR4_ABIInfo : public DefaultABIInfo { -bool IsSoftFloatABI; + bool IsSoftFloatABI; + + CharUnits getParamTypeAlignment(QualType Ty) const; + public: PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, bool SoftFloatABI) : DefaultABIInfo(CGT), IsSoftFloatABI(SoftFloatABI) {} @@ -4058,13 +4061,46 @@ public: bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; }; +} + +CharUnits PPC32_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const { + // Complex types are passed just like their elements + if (const ComplexType *CTy = Ty->getAs()) + Ty = CTy->getElementType(); + + if (Ty->isVectorType()) + return CharUnits::fromQuantity(getContext().getTypeSize(Ty) == 128 ? 16 + : 4); + // For single-element float/vector structs, we consider the whole type + // to have the same alignment requirements as its single element. + const Type *AlignTy = nullptr; + if (const Type *EltType = isSingleElementStruct(Ty, getContext())) { + const BuiltinType *BT = EltType->getAs(); + if ((EltType->isVectorType() && getContext().getTypeSize(EltType) == 128) || + (BT && BT->isFloatingPoint())) + AlignTy = EltType; + } + + if (AlignTy) + return CharUnits::fromQuantity(AlignTy->isVectorType() ? 16 : 4); + return CharUnits::fromQuantity(4); } // TODO: this implementation is now likely redundant with // DefaultABIInfo::EmitVAArg. Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList, QualType Ty) const { + if (getTarget().getTriple().isOSDarwin()) { + auto TI = getContext().getTypeInfoInChars(Ty); + TI.second = getParamTypeAlignment(Ty); + + CharUnits SlotSize = CharUnits::fromQuantity(4); + return emitVoidPtrVAArg(CGF, VAList, Ty, + classifyArgumentType(Ty).isIndirect(), TI, SlotSize, + /*AllowHigherAlign=*/true); + } + const unsigned OverflowLimit = 8; if (const ComplexType *CTy = Ty->getAs()) { // TODO: Implement this. For now ignore. diff --git a/test/CodeGen/darwin-ppc-varargs.c b/test/CodeGen/darwin-ppc-varargs.c new file mode 100644 index 0000000000..c2a0d19223 --- /dev/null +++ b/test/CodeGen/darwin-ppc-varargs.c @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple powerpc-apple-macosx10.5.0 -target-feature +altivec -Os -emit-llvm -o - %s | FileCheck %s + +int f(__builtin_va_list args) { return __builtin_va_arg(args, int); } + +// CHECK: @f(i8* {{.*}}[[PARAM:%[a-zA-Z0-9]+]]) +// CHECK: [[BITCAST:%[0-9]+]] = bitcast i8* [[PARAM]] to i32* +// CHECK: [[VALUE:%[0-9]+]] = load i32, i32* [[BITCAST]], align 4 +// CHECK: ret i32 [[VALUE]] + +void h(vector int); +int g(__builtin_va_list args) { + int i = __builtin_va_arg(args, int); + h(__builtin_va_arg(args, vector int)); + int j = __builtin_va_arg(args, int); + return i + j; +} + +// CHECK: @g(i8* {{.*}}[[PARAM:%[a-zA-Z0-9]+]]) +// CHECK: [[NEXT:%[-_.a-zA-Z0-9]+]] = getelementptr inbounds i8, i8* [[PARAM]], i32 4 +// CHECK: [[BITCAST:%[0-9]+]] = bitcast i8* [[PARAM]] to i32* +// CHECK: [[LOAD:%[0-9]+]] = load i32, i32* [[BITCAST]], align 4 +// CHECK: [[PTRTOINT:%[0-9]+]] = ptrtoint i8* [[NEXT]] to i32 +// CHECK: [[ADD:%[0-9]+]] = add i32 [[PTRTOINT]], 15 +// CHECK: [[AND:%[0-9]+]] = and i32 [[ADD]], -16 +// CHECK: [[INTTOPTR:%[0-9]+]] = inttoptr i32 [[AND]] to <4 x i32>* +// CHECK: [[ARG:%[0-9]]] = load <4 x i32>, <4 x i32>* [[INTTOPTR]], align 16 +// CHECK: call void @h(<4 x i32> [[ARG]] + -- GitLab From 1c6ec39fd744fa88b373ec68d31a5ddb43cf932f Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Wed, 25 Oct 2017 20:23:13 +0000 Subject: [PATCH 0073/1682] Ignore implicity casts for zero-as-null-pointer-constant warning The repro in https://bugs.llvm.org/show_bug.cgi?id=34362 caused the left nullptr to be cast to a int* implicitly, which resulted diagnosing this falsely. Differential Revision: https://reviews.llvm.org/D39301 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316605 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/Sema.cpp | 2 +- test/SemaCXX/warn-zero-nullptr.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 548f336c3b..a9d6cb4c58 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -438,7 +438,7 @@ void Sema::diagnoseNullableToNonnullConversion(QualType DstType, void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) { if (Kind != CK_NullToPointer && Kind != CK_NullToMemberPointer) return; - if (E->getType()->isNullPtrType()) + if (E->IgnoreParenImpCasts()->getType()->isNullPtrType()) return; // nullptr only exists from C++11 on, so don't warn on its absence earlier. if (!getLangOpts().CPlusPlus11) diff --git a/test/SemaCXX/warn-zero-nullptr.cpp b/test/SemaCXX/warn-zero-nullptr.cpp index edd2a759b7..72280405d7 100644 --- a/test/SemaCXX/warn-zero-nullptr.cpp +++ b/test/SemaCXX/warn-zero-nullptr.cpp @@ -25,3 +25,10 @@ void g() { // Warn on these too. Matches gcc and arguably makes sense. void* pp = (decltype(nullptr))0; // expected-warning{{zero as null pointer constant}} void* pp2 = static_cast(0); // expected-warning{{zero as null pointer constant}} + +// Shouldn't warn. +namespace pr34362 { +struct A { operator int*() { return nullptr; } }; +void func() { if (nullptr == A()) {} } +void func2() { if ((nullptr) == A()) {} } +} -- GitLab From 516d04abee63e7db72f97c5c8c269b7928245e07 Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Wed, 25 Oct 2017 20:39:22 +0000 Subject: [PATCH 0074/1682] Enable -pie and --enable-new-dtags by default on Android. Summary: Also enable -no-pie on Gnu toolchain (previously available on Darwin only). Non-PIE executables won't even start on recent Android, and DT_RPATH is ignored by the loader. Reviewers: srhines, danalbert Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D38430 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316606 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Driver/SanitizerArgs.cpp | 2 +- lib/Driver/ToolChains/Gnu.cpp | 15 ++++++-- lib/Driver/ToolChains/Linux.cpp | 7 +++- test/Driver/android-pie.c | 66 +++++++++++++++++++++++++++++++++ test/Driver/fsanitize.c | 8 +++- test/Driver/linux-ld.c | 26 +------------ test/Driver/pic.c | 43 +++++++++++++++++++-- test/Driver/sanitizer-ld.c | 4 +- 8 files changed, 134 insertions(+), 37 deletions(-) create mode 100644 test/Driver/android-pie.c diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp index 5eeaeb3ac6..037989680f 100644 --- a/lib/Driver/SanitizerArgs.cpp +++ b/lib/Driver/SanitizerArgs.cpp @@ -622,7 +622,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, ImplicitCfiRuntime = TC.getTriple().isAndroid(); if (AllAddedKinds & Address) { - NeedPIE |= TC.getTriple().isAndroid() || TC.getTriple().isOSFuchsia(); + NeedPIE |= TC.getTriple().isOSFuchsia(); if (Arg *A = Args.getLastArg(options::OPT_fsanitize_address_field_padding)) { StringRef S = A->getValue(); diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp index 757ebda46d..08d4aa51f2 100644 --- a/lib/Driver/ToolChains/Gnu.cpp +++ b/lib/Driver/ToolChains/Gnu.cpp @@ -282,6 +282,17 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { } } +static bool getPIE(const ArgList &Args, const toolchains::Linux &ToolChain) { + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static)) + return false; + + Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie, + options::OPT_nopie); + if (!A) + return ToolChain.isPIEDefault(); + return A->getOption().matches(options::OPT_pie); +} + void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -296,9 +307,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool isAndroid = ToolChain.getTriple().isAndroid(); const bool IsIAMCU = ToolChain.getTriple().isOSIAMCU(); - const bool IsPIE = - !Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_static) && - (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault()); + const bool IsPIE = getPIE(Args, ToolChain); const bool HasCRTBeginEndFiles = ToolChain.getTriple().hasEnvironment() || (ToolChain.getTriple().getVendor() != llvm::Triple::MipsTechnologies); diff --git a/lib/Driver/ToolChains/Linux.cpp b/lib/Driver/ToolChains/Linux.cpp index 1adf9f7070..d99f98038b 100644 --- a/lib/Driver/ToolChains/Linux.cpp +++ b/lib/Driver/ToolChains/Linux.cpp @@ -248,7 +248,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) ExtraOpts.push_back("--build-id"); #endif - if (Distro.IsOpenSUSE()) + if (IsAndroid || Distro.IsOpenSUSE()) ExtraOpts.push_back("--enable-new-dtags"); // The selection of paths to try here is designed to match the patterns which @@ -810,7 +810,10 @@ void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs, } } -bool Linux::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } +bool Linux::isPIEDefault() const { + return (getTriple().isAndroid() && !getTriple().isAndroidVersionLT(16)) || + getSanitizerArgs().requiresPIE(); +} SanitizerMask Linux::getSupportedSanitizers() const { const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; diff --git a/test/Driver/android-pie.c b/test/Driver/android-pie.c new file mode 100644 index 0000000000..2569c55d58 --- /dev/null +++ b/test/Driver/android-pie.c @@ -0,0 +1,66 @@ +// NO-PIE-NOT: "-pie" +// PIE: "-pie" + +// RUN: %clang %s -### -o %t.o 2>&1 --target=arm-linux-androideabi \ +// RUN: | FileCheck --check-prefix=NO-PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 --target=arm-linux-android \ +// RUN: | FileCheck --check-prefix=NO-PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 --target=arm-linux-android14 \ +// RUN: | FileCheck --check-prefix=NO-PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 --target=arm-linux-android16 \ +// RUN: | FileCheck --check-prefix=PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 --target=arm-linux-android24 \ +// RUN: | FileCheck --check-prefix=PIE %s + +// RUN: %clang %s -### -o %t.o 2>&1 --target=mipsel-linux-android \ +// RUN: | FileCheck --check-prefix=NO-PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 --target=mipsel-linux-android14 \ +// RUN: | FileCheck --check-prefix=NO-PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 --target=mipsel-linux-android16 \ +// RUN: | FileCheck --check-prefix=PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 --target=mipsel-linux-android24 \ +// RUN: | FileCheck --check-prefix=PIE %s + +// RUN: %clang %s -### -o %t.o 2>&1 --target=i686-linux-android \ +// RUN: | FileCheck --check-prefix=NO-PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 --target=i686-linux-android14 \ +// RUN: | FileCheck --check-prefix=NO-PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 --target=i686-linux-android16 \ +// RUN: | FileCheck --check-prefix=PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 --target=i686-linux-android24 \ +// RUN: | FileCheck --check-prefix=PIE %s + +// RUN: %clang %s -### -o %t.o 2>&1 --target=aarch64-linux-android \ +// RUN: | FileCheck --check-prefix=PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 --target=aarch64-linux-android24 \ +// RUN: | FileCheck --check-prefix=PIE %s + +// RUN: %clang %s -### -o %t.o 2>&1 --target=arm64-linux-android \ +// RUN: | FileCheck --check-prefix=PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 --target=arm64-linux-android24 \ +// RUN: | FileCheck --check-prefix=PIE %s + +// RUN: %clang %s -### -o %t.o 2>&1 --target=mips64el-linux-android \ +// RUN: | FileCheck --check-prefix=PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 --target=mips64el-linux-android24 \ +// RUN: | FileCheck --check-prefix=PIE %s + +// RUN: %clang %s -### -o %t.o 2>&1 --target=x86_64-linux-android \ +// RUN: | FileCheck --check-prefix=PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 --target=x86_64-linux-android24 \ +// RUN: | FileCheck --check-prefix=PIE %s + +// Override toolchain default setting. +// RUN: %clang %s -### -o %t.o 2>&1 -pie --target=arm-linux-androideabi \ +// RUN: | FileCheck --check-prefix=PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 -pie --target=arm-linux-androideabi14 \ +// RUN: | FileCheck --check-prefix=PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 -no-pie -pie --target=arm-linux-androideabi24 \ +// RUN: | FileCheck --check-prefix=PIE %s + +// RUN: %clang %s -### -o %t.o 2>&1 -no-pie --target=arm-linux-androideabi24 \ +// RUN: | FileCheck --check-prefix=NO-PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 -nopie --target=arm-linux-androideabi24 \ +// RUN: | FileCheck --check-prefix=NO-PIE %s +// RUN: %clang %s -### -o %t.o 2>&1 -pie -no-pie --target=arm-linux-androideabi24 \ +// RUN: | FileCheck --check-prefix=NO-PIE %s diff --git a/test/Driver/fsanitize.c b/test/Driver/fsanitize.c index 0f37070dd4..d6f0f198b4 100644 --- a/test/Driver/fsanitize.c +++ b/test/Driver/fsanitize.c @@ -202,7 +202,9 @@ // RUN: %clang -target x86_64-linux-gnu -fsanitize=memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-PIE // RUN: %clang -target x86_64-unknown-freebsd -fsanitize=memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PIE // RUN: %clang -target aarch64-linux-gnu -fsanitize=memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PIE -// RUN: %clang -target arm-linux-androideabi -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PIE +// RUN: %clang -target arm-linux-androideabi -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PIC-NO-PIE +// RUN: %clang -target arm-linux-androideabi24 -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PIE +// RUN: %clang -target aarch64-linux-android -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PIE // RUN: %clang -target x86_64-linux-gnu -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-PIE // RUN: %clang -target i386-linux-gnu -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-PIE @@ -210,6 +212,10 @@ // CHECK-NO-PIE: "-mrelocation-model" "static" // CHECK-NO-PIE-NOT: "-pie" +// CHECK-PIC-NO-PIE-NOT: "-pie" +// CHECK-PIC-NO-PIE: "-mrelocation-model" "pic" +// CHECK-PIC-NO-PIE-NOT: "-pie" + // CHECK-PIE: "-mrelocation-model" "pic" "-pic-level" "2" "-pic-is-pie" // CHECK-PIE: "-pie" diff --git a/test/Driver/linux-ld.c b/test/Driver/linux-ld.c index a47afe3924..662aabb867 100644 --- a/test/Driver/linux-ld.c +++ b/test/Driver/linux-ld.c @@ -1133,6 +1133,7 @@ // RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \ // RUN: | FileCheck --check-prefix=CHECK-ANDROID %s // CHECK-ANDROID: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-ANDROID: "--enable-new-dtags" // CHECK-ANDROID: "{{.*}}{{/|\\\\}}crtbegin_dynamic.o" // CHECK-ANDROID: "-L[[SYSROOT]]/usr/lib" // CHECK-ANDROID-NOT: "gcc_s" @@ -1307,31 +1308,6 @@ // CHECK-ANDROID-PIE: "{{.*}}{{/|\\\\}}crtend_android.o" // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ // RUN: --target=arm-linux-androideabi \ -// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s -// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ -// RUN: --target=arm-linux-android \ -// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s -// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ -// RUN: --target=aarch64-linux-android \ -// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s -// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ -// RUN: --target=arm64-linux-android \ -// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s -// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ -// RUN: --target=mipsel-linux-android \ -// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s -// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ -// RUN: --target=mips64el-linux-android \ -// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s -// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ -// RUN: --target=i686-linux-android \ -// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s -// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ -// RUN: --target=x86_64-linux-android \ -// RUN: | FileCheck --check-prefix=CHECK-ANDROID-NO-DEFAULT-PIE %s -// CHECK-ANDROID-NO-DEFAULT-PIE-NOT: -pie -// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ -// RUN: --target=arm-linux-androideabi \ // RUN: --gcc-toolchain="" \ // RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \ // RUN: | FileCheck --check-prefix=CHECK-ANDROID-32 %s diff --git a/test/Driver/pic.c b/test/Driver/pic.c index 6b01c583b8..f2618eede3 100644 --- a/test/Driver/pic.c +++ b/test/Driver/pic.c @@ -251,17 +251,54 @@ // RUN: %clang %s -target i386-pc-openbsd -no-pie -### 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECK-NOPIE-LD // -// On Android PIC is enabled by default +// On Android PIC is enabled by default, and PIE is enabled by default starting +// with API16. // RUN: %clang -c %s -target i686-linux-android -### 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECK-PIC2 +// RUN: %clang -c %s -target i686-linux-android14 -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-PIC2 +// RUN: %clang -c %s -target i686-linux-android16 -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-PIE2 +// RUN: %clang -c %s -target i686-linux-android24 -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-PIE2 +// // RUN: %clang -c %s -target arm-linux-androideabi -### 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECK-PIC1 +// RUN: %clang -c %s -target arm-linux-androideabi14 -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-PIC1 +// RUN: %clang -c %s -target arm-linux-androideabi16 -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-PIE2 +// RUN: %clang -c %s -target arm-linux-androideabi24 -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-PIE2 +// // RUN: %clang -c %s -target mipsel-linux-android -### 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECK-PIC1 -// RUN: %clang -c %s -target aarch64-linux-android -### 2>&1 \ +// RUN: %clang -c %s -target mipsel-linux-android14 -### 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECK-PIC1 +// RUN: %clang -c %s -target mipsel-linux-android16 -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-PIE2 +// RUN: %clang -c %s -target mipsel-linux-android24 -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-PIE2 +// +// 64-bit Android targets are always PIE. +// RUN: %clang -c %s -target aarch64-linux-android -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-PIE2 +// RUN: %clang -c %s -target aarch64-linux-android24 -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-PIE2 // RUN: %clang -c %s -target arm64-linux-android -### 2>&1 \ -// RUN: | FileCheck %s --check-prefix=CHECK-PIC1 +// RUN: | FileCheck %s --check-prefix=CHECK-PIE2 +// +// Default value of PIE can be overwritten, even on 64-bit targets. +// RUN: %clang -c %s -target arm-linux-androideabi -fPIE -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-PIE2 +// RUN: %clang -c %s -target i686-linux-android14 -fPIE -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-PIE2 +// RUN: %clang -c %s -target i686-linux-android16 -fno-PIE -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC +// RUN: %clang -c %s -target aarch64-linux-android -fno-PIE -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC +// RUN: %clang -c %s -target aarch64-linux-android24 -fno-PIE -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC // // On Windows-X64 PIC is enabled by default // RUN: %clang -c %s -target x86_64-pc-windows-msvc18.0.0 -### 2>&1 \ diff --git a/test/Driver/sanitizer-ld.c b/test/Driver/sanitizer-ld.c index 68eab30879..f03714c4b5 100644 --- a/test/Driver/sanitizer-ld.c +++ b/test/Driver/sanitizer-ld.c @@ -140,7 +140,7 @@ // // CHECK-ASAN-ANDROID: "{{(.*[^.0-9A-Z_a-z])?}}ld{{(.exe)?}}" // CHECK-ASAN-ANDROID-NOT: "-lc" -// CHECK-ASAN-ANDROID: "-pie" +// CHECK-ASAN-ANDROID-NOT: "-pie" // CHECK-ASAN-ANDROID-NOT: "-lpthread" // CHECK-ASAN-ANDROID: libclang_rt.asan-arm-android.so" // CHECK-ASAN-ANDROID-NOT: "-lpthread" @@ -185,7 +185,7 @@ // // CHECK-ASAN-ANDROID-X86: "{{(.*[^.0-9A-Z_a-z])?}}ld{{(.exe)?}}" // CHECK-ASAN-ANDROID-X86-NOT: "-lc" -// CHECK-ASAN-ANDROID-X86: "-pie" +// CHECK-ASAN-ANDROID-X86-NOT: "-pie" // CHECK-ASAN-ANDROID-X86-NOT: "-lpthread" // CHECK-ASAN-ANDROID-X86: libclang_rt.asan-i686-android.so" // CHECK-ASAN-ANDROID-X86-NOT: "-lpthread" -- GitLab From ae2ecba319e91dbefe5096943ca96afe4d7572a7 Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Wed, 25 Oct 2017 21:32:06 +0000 Subject: [PATCH 0075/1682] [CUDA] Print an error if you try to compile with < sm_30 on CUDA 9. Summary: CUDA 9's minimum sm is sm_30. Ideally we should also make sm_30 the default when compiling with CUDA 9, but that seems harder than it should be. Subscribers: sanjoy Differential Revision: https://reviews.llvm.org/D39109 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316611 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Cuda.h | 4 ++++ include/clang/Basic/DiagnosticDriverKinds.td | 7 ++++--- lib/Basic/Cuda.cpp | 12 ++++++++++++ lib/Driver/ToolChains/Cuda.cpp | 16 +++++++++------- lib/Driver/ToolChains/Cuda.h | 2 +- .../Inputs/CUDA_90/usr/local/cuda/bin/.keep | 0 .../Inputs/CUDA_90/usr/local/cuda/include/.keep | 0 .../Inputs/CUDA_90/usr/local/cuda/lib/.keep | 0 .../Inputs/CUDA_90/usr/local/cuda/lib64/.keep | 0 .../local/cuda/nvvm/libdevice/libdevice.10.bc | 0 .../Inputs/CUDA_90/usr/local/cuda/version.txt | 1 + test/Driver/cuda-bad-arch.cu | 6 ++++++ 12 files changed, 37 insertions(+), 11 deletions(-) create mode 100644 test/Driver/Inputs/CUDA_90/usr/local/cuda/bin/.keep create mode 100644 test/Driver/Inputs/CUDA_90/usr/local/cuda/include/.keep create mode 100644 test/Driver/Inputs/CUDA_90/usr/local/cuda/lib/.keep create mode 100644 test/Driver/Inputs/CUDA_90/usr/local/cuda/lib64/.keep create mode 100644 test/Driver/Inputs/CUDA_90/usr/local/cuda/nvvm/libdevice/libdevice.10.bc create mode 100644 test/Driver/Inputs/CUDA_90/usr/local/cuda/version.txt diff --git a/include/clang/Basic/Cuda.h b/include/clang/Basic/Cuda.h index b273365975..1a0731c37a 100644 --- a/include/clang/Basic/Cuda.h +++ b/include/clang/Basic/Cuda.h @@ -22,6 +22,7 @@ enum class CudaVersion { CUDA_75, CUDA_80, CUDA_90, + LATEST = CUDA_90, }; const char *CudaVersionToString(CudaVersion V); @@ -75,6 +76,9 @@ CudaVirtualArch VirtualArchForCudaArch(CudaArch A); /// Get the earliest CudaVersion that supports the given CudaArch. CudaVersion MinVersionForCudaArch(CudaArch A); +/// Get the latest CudaVersion that supports the given CudaArch. +CudaVersion MaxVersionForCudaArch(CudaArch A); + } // namespace clang #endif diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index 67472a5964..dd72c958d1 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -29,9 +29,10 @@ def err_drv_no_cuda_installation : Error< def err_drv_no_cuda_libdevice : Error< "cannot find libdevice for %0. Provide path to different CUDA installation " "via --cuda-path, or pass -nocudalib to build without linking with libdevice.">; -def err_drv_cuda_version_too_low : Error< - "GPU arch %1 requires CUDA version at least %3, but installation at %0 is %2. " - "Use --cuda-path to specify a different CUDA install, or pass " +def err_drv_cuda_version_unsupported : Error< + "GPU arch %0 is supported by CUDA versions between %1 and %2 (inclusive), " + "but installation at %3 is %4. Use --cuda-path to specify a different CUDA " + "install, pass a different GPU arch with --cuda-gpu-arch, or pass " "--no-cuda-version-check.">; def err_drv_cuda_nvptx_host : Error<"unsupported use of NVPTX for host compilation.">; def err_drv_invalid_thread_model_for_target : Error< diff --git a/lib/Basic/Cuda.cpp b/lib/Basic/Cuda.cpp index 3a5297b0c6..58b99a3b58 100644 --- a/lib/Basic/Cuda.cpp +++ b/lib/Basic/Cuda.cpp @@ -180,4 +180,16 @@ CudaVersion MinVersionForCudaArch(CudaArch A) { llvm_unreachable("invalid enum"); } +CudaVersion MaxVersionForCudaArch(CudaArch A) { + switch (A) { + case CudaArch::UNKNOWN: + return CudaVersion::UNKNOWN; + case CudaArch::SM_20: + case CudaArch::SM_21: + return CudaVersion::CUDA_80; + default: + return CudaVersion::LATEST; + } +} + } // namespace clang diff --git a/lib/Driver/ToolChains/Cuda.cpp b/lib/Driver/ToolChains/Cuda.cpp index 4f740fc952..44ec16e8b8 100644 --- a/lib/Driver/ToolChains/Cuda.cpp +++ b/lib/Driver/ToolChains/Cuda.cpp @@ -205,15 +205,17 @@ void CudaInstallationDetector::AddCudaIncludeArgs( void CudaInstallationDetector::CheckCudaVersionSupportsArch( CudaArch Arch) const { if (Arch == CudaArch::UNKNOWN || Version == CudaVersion::UNKNOWN || - ArchsWithVersionTooLowErrors.count(Arch) > 0) + ArchsWithBadVersion.count(Arch) > 0) return; - auto RequiredVersion = MinVersionForCudaArch(Arch); - if (Version < RequiredVersion) { - ArchsWithVersionTooLowErrors.insert(Arch); - D.Diag(diag::err_drv_cuda_version_too_low) - << InstallPath << CudaArchToString(Arch) << CudaVersionToString(Version) - << CudaVersionToString(RequiredVersion); + auto MinVersion = MinVersionForCudaArch(Arch); + auto MaxVersion = MaxVersionForCudaArch(Arch); + if (Version < MinVersion || Version > MaxVersion) { + ArchsWithBadVersion.insert(Arch); + D.Diag(diag::err_drv_cuda_version_unsupported) + << CudaArchToString(Arch) << CudaVersionToString(MinVersion) + << CudaVersionToString(MaxVersion) << InstallPath + << CudaVersionToString(Version); } } diff --git a/lib/Driver/ToolChains/Cuda.h b/lib/Driver/ToolChains/Cuda.h index 1e30aa7270..414c9445c7 100644 --- a/lib/Driver/ToolChains/Cuda.h +++ b/lib/Driver/ToolChains/Cuda.h @@ -40,7 +40,7 @@ private: // CUDA architectures for which we have raised an error in // CheckCudaVersionSupportsArch. - mutable llvm::SmallSet ArchsWithVersionTooLowErrors; + mutable llvm::SmallSet ArchsWithBadVersion; public: CudaInstallationDetector(const Driver &D, const llvm::Triple &HostTriple, diff --git a/test/Driver/Inputs/CUDA_90/usr/local/cuda/bin/.keep b/test/Driver/Inputs/CUDA_90/usr/local/cuda/bin/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Driver/Inputs/CUDA_90/usr/local/cuda/include/.keep b/test/Driver/Inputs/CUDA_90/usr/local/cuda/include/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Driver/Inputs/CUDA_90/usr/local/cuda/lib/.keep b/test/Driver/Inputs/CUDA_90/usr/local/cuda/lib/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Driver/Inputs/CUDA_90/usr/local/cuda/lib64/.keep b/test/Driver/Inputs/CUDA_90/usr/local/cuda/lib64/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Driver/Inputs/CUDA_90/usr/local/cuda/nvvm/libdevice/libdevice.10.bc b/test/Driver/Inputs/CUDA_90/usr/local/cuda/nvvm/libdevice/libdevice.10.bc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/Driver/Inputs/CUDA_90/usr/local/cuda/version.txt b/test/Driver/Inputs/CUDA_90/usr/local/cuda/version.txt new file mode 100644 index 0000000000..24e1fd4ece --- /dev/null +++ b/test/Driver/Inputs/CUDA_90/usr/local/cuda/version.txt @@ -0,0 +1 @@ +CUDA Version 9.0.103 diff --git a/test/Driver/cuda-bad-arch.cu b/test/Driver/cuda-bad-arch.cu index cbc2d11f90..a6559b0c78 100644 --- a/test/Driver/cuda-bad-arch.cu +++ b/test/Driver/cuda-bad-arch.cu @@ -12,6 +12,12 @@ // BAD: error: Unsupported CUDA gpu architecture +// RUN: %clang -### -v --target=x86_64-linux-gnu --cuda-gpu-arch=sm_21 \ +// RUN: --cuda-path=%S/Inputs/CUDA_90/usr/local/cuda %s 2>&1 \ +// RUN: | FileCheck -check-prefix BAD_CUDA9 %s + +// BAD_CUDA9: GPU arch sm_21 is supported by CUDA versions between 7.0 and 8.0 + // 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 \ -- GitLab From a535f1e292c1266239723115754e4060d25f2ffb Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Wed, 25 Oct 2017 21:49:41 +0000 Subject: [PATCH 0076/1682] [Analyzer] Give more descriptive name to BdyFrm field. Discussion at: https://reviews.llvm.org/D39220 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316617 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Analysis/AnalysisDeclContext.h | 2 +- lib/Analysis/AnalysisDeclContext.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/clang/Analysis/AnalysisDeclContext.h b/include/clang/Analysis/AnalysisDeclContext.h index c9762818ad..ecd99f8054 100644 --- a/include/clang/Analysis/AnalysisDeclContext.h +++ b/include/clang/Analysis/AnalysisDeclContext.h @@ -421,7 +421,7 @@ class AnalysisDeclContextManager { /// Pointer to a factory for creating and caching implementations for common /// methods during the analysis. - std::unique_ptr BdyFrm; + std::unique_ptr FunctionBodyFarm; /// Flag to indicate whether or not bodies should be synthesized /// for well-known functions. diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp index 17749db37c..c7c720eb77 100644 --- a/lib/Analysis/AnalysisDeclContext.cpp +++ b/lib/Analysis/AnalysisDeclContext.cpp @@ -305,9 +305,9 @@ AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) { } BodyFarm *AnalysisDeclContextManager::getBodyFarm() { - if (!BdyFrm) - BdyFrm = llvm::make_unique(ASTCtx, Injector.get()); - return BdyFrm.get(); + if (!FunctionBodyFarm) + FunctionBodyFarm = llvm::make_unique(ASTCtx, Injector.get()); + return FunctionBodyFarm.get(); } const StackFrameContext * -- GitLab From d67bfb9c5a824cda77728809d0e86fce71c364ae Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Wed, 25 Oct 2017 21:49:46 +0000 Subject: [PATCH 0077/1682] [Analyzer] [Tests] Do not discard output from CmpRuns.py when running integration tests Contrary to the deleted comment, in most cases CmpRuns.py produces a fairly small amount of output, which is useful to see straight away to see what has changed when executing the integration tests. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316618 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/analyzer/SATestBuild.py | 8 +------- utils/analyzer/SATestUtils.py | 8 -------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py index 5853cf438a..2cf02ea64a 100755 --- a/utils/analyzer/SATestBuild.py +++ b/utils/analyzer/SATestBuild.py @@ -526,17 +526,11 @@ def runCmpResults(Dir, Strictness=0): DiffsPath = os.path.join(NewDir, DiffsSummaryFileName) PatchedSourceDirPath = os.path.join(Dir, PatchedSourceDirName) Opts = CmpRuns.CmpOptions(DiffsPath, "", PatchedSourceDirPath) - # Discard everything coming out of stdout - # (CmpRun produces a lot of them). - OLD_STDOUT = sys.stdout - sys.stdout = SATestUtils.Discarder() # Scan the results, delete empty plist files. NumDiffs, ReportsInRef, ReportsInNew = \ CmpRuns.dumpScanBuildResultsDiff(RefDir, NewDir, Opts, False) - sys.stdout = OLD_STDOUT if (NumDiffs > 0): - print "Warning: %r differences in diagnostics. See %s" % \ - (NumDiffs, DiffsPath,) + print "Warning: %s differences in diagnostics." % NumDiffs if Strictness >= 2 and NumDiffs > 0: print "Error: Diffs found in strict mode (2)." TestsPassed = False diff --git a/utils/analyzer/SATestUtils.py b/utils/analyzer/SATestUtils.py index 961ebfac13..9220acc1bd 100644 --- a/utils/analyzer/SATestUtils.py +++ b/utils/analyzer/SATestUtils.py @@ -93,14 +93,6 @@ def runScript(ScriptPath, PBuildLogFile, Cwd): sys.exit(-1) -class Discarder(object): - """ - Auxiliary object to discard stdout. - """ - def write(self, text): - pass # do nothing - - def isCommentCSVLine(Entries): """ Treat CSV lines starting with a '#' as a comment. -- GitLab From 2150c7da3d9103acdaa3e09a99a9aaa0275549ee Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Wed, 25 Oct 2017 22:01:23 +0000 Subject: [PATCH 0078/1682] Handle PragmaDebug in PPChainedCallbacks The test is in clang-tools-extra/test/pp-trace git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316621 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Lex/PPCallbacks.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h index 8cb1656270..19bce4dd32 100644 --- a/include/clang/Lex/PPCallbacks.h +++ b/include/clang/Lex/PPCallbacks.h @@ -410,6 +410,11 @@ public: Second->PragmaDetectMismatch(Loc, Name, Value); } + void PragmaDebug(SourceLocation Loc, StringRef DebugType) override { + First->PragmaDebug(Loc, DebugType); + Second->PragmaDebug(Loc, DebugType); + } + void PragmaMessage(SourceLocation Loc, StringRef Namespace, PragmaMessageKind Kind, StringRef Str) override { First->PragmaMessage(Loc, Namespace, Kind, Str); -- GitLab From f19ada140e21a47e9ee3b1ce5e36a2b219cb6f40 Mon Sep 17 00:00:00 2001 From: Alex Lorenz Date: Thu, 26 Oct 2017 00:56:54 +0000 Subject: [PATCH 0079/1682] Allow StmtPrinter to supress implicit 'this' and 'self' base expressions This will be useful for certain refactoring actions. rdar://34202062 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316631 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/PrettyPrinter.h | 7 ++- lib/AST/StmtPrinter.cpp | 42 ++++++++++++++---- unittests/AST/StmtPrinterTest.cpp | 74 ++++++++++++++++++++++++++++--- 3 files changed, 105 insertions(+), 18 deletions(-) diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h index 54fe398337..953ecada6c 100644 --- a/include/clang/AST/PrettyPrinter.h +++ b/include/clang/AST/PrettyPrinter.h @@ -51,7 +51,7 @@ struct PrintingPolicy { TerseOutput(false), PolishForDeclaration(false), Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true), MSVCFormatting(false), - ConstantsAsWritten(false) { } + ConstantsAsWritten(false), SuppressImplicitBase(false) { } /// \brief Adjust this printing policy for cases where it's known that /// we're printing C++ code (for instance, if AST dumping reaches a @@ -218,7 +218,10 @@ struct PrintingPolicy { /// 0x10 /// 2.5e3 /// \endcode - bool ConstantsAsWritten; + bool ConstantsAsWritten : 1; + + /// \brief When true, don't print the implicit 'self' or 'this' expressions. + bool SuppressImplicitBase : 1; }; } // end namespace clang diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 9cbd1ef760..371d3e181d 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1346,10 +1346,25 @@ void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { OS, Node->template_arguments(), Policy); } +static bool isImplicitSelf(const Expr *E) { + if (const auto *DRE = dyn_cast(E)) { + if (const ImplicitParamDecl *PD = + dyn_cast(DRE->getDecl())) { + if (PD->getParameterKind() == ImplicitParamDecl::ObjCSelf && + DRE->getLocStart().isInvalid()) + return true; + } + } + return false; +} + void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { if (Node->getBase()) { - PrintExpr(Node->getBase()); - OS << (Node->isArrow() ? "->" : "."); + if (!Policy.SuppressImplicitBase || + !isImplicitSelf(Node->getBase()->IgnoreImpCasts())) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + } } OS << *Node->getDecl(); } @@ -1670,16 +1685,25 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) { PrintCallArgs(Call); OS << ")"; } + +static bool isImplicitThis(const Expr *E) { + if (const auto *TE = dyn_cast(E)) + return TE->isImplicit(); + return false; +} + void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { - // FIXME: Suppress printing implicit bases (like "this") - PrintExpr(Node->getBase()); + if (!Policy.SuppressImplicitBase || !isImplicitThis(Node->getBase())) { + PrintExpr(Node->getBase()); - MemberExpr *ParentMember = dyn_cast(Node->getBase()); - FieldDecl *ParentDecl = ParentMember - ? dyn_cast(ParentMember->getMemberDecl()) : nullptr; + MemberExpr *ParentMember = dyn_cast(Node->getBase()); + FieldDecl *ParentDecl = + ParentMember ? dyn_cast(ParentMember->getMemberDecl()) + : nullptr; - if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion()) - OS << (Node->isArrow() ? "->" : "."); + if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion()) + OS << (Node->isArrow() ? "->" : "."); + } if (FieldDecl *FD = dyn_cast(Node->getMemberDecl())) if (FD->isAnonymousStructOrUnion()) diff --git a/unittests/AST/StmtPrinterTest.cpp b/unittests/AST/StmtPrinterTest.cpp index 12b203236c..a0644401a7 100644 --- a/unittests/AST/StmtPrinterTest.cpp +++ b/unittests/AST/StmtPrinterTest.cpp @@ -31,18 +31,26 @@ using namespace tooling; namespace { -void PrintStmt(raw_ostream &Out, const ASTContext *Context, const Stmt *S) { +using PolicyAdjusterType = + Optional>; + +void PrintStmt(raw_ostream &Out, const ASTContext *Context, const Stmt *S, + PolicyAdjusterType PolicyAdjuster) { assert(S != nullptr && "Expected non-null Stmt"); PrintingPolicy Policy = Context->getPrintingPolicy(); + if (PolicyAdjuster) + (*PolicyAdjuster)(Policy); S->printPretty(Out, /*Helper*/ nullptr, Policy); } class PrintMatch : public MatchFinder::MatchCallback { SmallString<1024> Printed; unsigned NumFoundStmts; + PolicyAdjusterType PolicyAdjuster; public: - PrintMatch() : NumFoundStmts(0) {} + PrintMatch(PolicyAdjusterType PolicyAdjuster) + : NumFoundStmts(0), PolicyAdjuster(PolicyAdjuster) {} void run(const MatchFinder::MatchResult &Result) override { const Stmt *S = Result.Nodes.getNodeAs("id"); @@ -53,7 +61,7 @@ public: return; llvm::raw_svector_ostream Out(Printed); - PrintStmt(Out, Result.Context, S); + PrintStmt(Out, Result.Context, S, PolicyAdjuster); } StringRef getPrinted() const { @@ -68,9 +76,10 @@ public: template ::testing::AssertionResult PrintedStmtMatches(StringRef Code, const std::vector &Args, - const T &NodeMatch, StringRef ExpectedPrinted) { + const T &NodeMatch, StringRef ExpectedPrinted, + PolicyAdjusterType PolicyAdjuster = None) { - PrintMatch Printer; + PrintMatch Printer(PolicyAdjuster); MatchFinder Finder; Finder.addMatcher(NodeMatch, &Printer); std::unique_ptr Factory( @@ -122,11 +131,13 @@ PrintedStmtCXX98Matches(StringRef Code, const StatementMatcher &NodeMatch, ::testing::AssertionResult PrintedStmtCXX11Matches(StringRef Code, const StatementMatcher &NodeMatch, - StringRef ExpectedPrinted) { + StringRef ExpectedPrinted, + PolicyAdjusterType PolicyAdjuster = None) { std::vector Args; Args.push_back("-std=c++11"); Args.push_back("-Wno-unused-value"); - return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted); + return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted, + PolicyAdjuster); } ::testing::AssertionResult PrintedStmtMSMatches( @@ -146,6 +157,17 @@ PrintedStmtCXX11Matches(StringRef Code, const StatementMatcher &NodeMatch, ExpectedPrinted); } +::testing::AssertionResult +PrintedStmtObjCMatches(StringRef Code, const StatementMatcher &NodeMatch, + StringRef ExpectedPrinted, + PolicyAdjusterType PolicyAdjuster = None) { + std::vector Args; + Args.push_back("-ObjC"); + Args.push_back("-fobjc-runtime=macosx-10.12.0"); + return PrintedStmtMatches(Code, Args, NodeMatch, ExpectedPrinted, + PolicyAdjuster); +} + } // unnamed namespace TEST(StmtPrinter, TestIntegerLiteral) { @@ -214,3 +236,41 @@ TEST(StmtPrinter, TestCXXConversionDeclExplicit) { "(a & b)")); // WRONG; Should be: (a & b).operator void *() } + +TEST(StmtPrinter, TestNoImplicitBases) { + const char *CPPSource = R"( +class A { + int field; + int member() { return field; } +}; +)"; + // No implicit 'this'. + ASSERT_TRUE(PrintedStmtCXX11Matches( + CPPSource, memberExpr(anything()).bind("id"), "field", + PolicyAdjusterType( + [](PrintingPolicy &PP) { PP.SuppressImplicitBase = true; }))); + // Print implicit 'this'. + ASSERT_TRUE(PrintedStmtCXX11Matches( + CPPSource, memberExpr(anything()).bind("id"), "this->field")); + + const char *ObjCSource = R"( +@interface I { + int ivar; +} +@end +@implementation I +- (int) method { + return ivar; +} +@end + )"; + // No implicit 'self'. + ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"), + "return ivar;\n", + PolicyAdjusterType([](PrintingPolicy &PP) { + PP.SuppressImplicitBase = true; + }))); + // Print implicit 'self'. + ASSERT_TRUE(PrintedStmtObjCMatches(ObjCSource, returnStmt().bind("id"), + "return self->ivar;\n")); +} -- GitLab From 9107ad9e5f2f8551e9b6b90af76d25bd26735d27 Mon Sep 17 00:00:00 2001 From: George Karpenkov Date: Thu, 26 Oct 2017 01:13:22 +0000 Subject: [PATCH 0080/1682] [Analyzer] [Tests] Consistently use exit codes. Use code=42 to signify different results git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316632 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/analyzer/SATestBuild.py | 19 +++++++++++-------- utils/analyzer/SATestUpdateDiffs.py | 4 ++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py index 2cf02ea64a..74a5f6ebda 100755 --- a/utils/analyzer/SATestBuild.py +++ b/utils/analyzer/SATestBuild.py @@ -71,7 +71,7 @@ def getProjectMapPath(): if not os.path.exists(ProjectMapPath): print "Error: Cannot find the Project Map file " + ProjectMapPath +\ "\nRunning script for the wrong directory?" - sys.exit(-1) + sys.exit(1) return ProjectMapPath @@ -97,7 +97,7 @@ else: Clang = SATestUtils.which("clang", os.environ['PATH']) if not Clang: print "Error: cannot find 'clang' in PATH" - sys.exit(-1) + sys.exit(1) # Number of jobs. Jobs = int(math.ceil(multiprocessing.cpu_count() * 0.75)) @@ -196,7 +196,7 @@ def downloadAndPatch(Dir, PBuildLogFile): if not os.path.exists(CachedSourceDirPath): print "Error: '%s' not found after download." % ( CachedSourceDirPath) - exit(-1) + exit(1) PatchedSourceDirPath = os.path.join(Dir, PatchedSourceDirName) @@ -225,7 +225,7 @@ def applyPatch(Dir, PBuildLogFile): shell=True) except: print "Error: Patch failed. See %s for details." % (PBuildLogFile.name) - sys.exit(-1) + sys.exit(1) def runScanBuild(Dir, SBOutputDir, PBuildLogFile): @@ -236,7 +236,7 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile): BuildScriptPath = os.path.join(Dir, BuildScript) if not os.path.exists(BuildScriptPath): print "Error: build script is not defined: %s" % BuildScriptPath - sys.exit(-1) + sys.exit(1) AllCheckers = Checkers if 'SA_ADDITIONAL_CHECKERS' in os.environ: @@ -473,7 +473,7 @@ def checkBuild(SBOutputDir): shutil.copyfileobj(FailLogI, SummaryLog) print "Error: analysis failed. See ", SummaryPath - sys.exit(-1) + sys.exit(1) def runCmpResults(Dir, Strictness=0): @@ -503,7 +503,10 @@ def runCmpResults(Dir, Strictness=0): RefList.remove(RefLogDir) NewList.remove(os.path.join(NewDir, LogFolderName)) - assert(len(RefList) == len(NewList)) + if len(RefList) != len(NewList): + print "Mismatch in number of results folders: %s vs %s" % ( + RefList, NewList) + sys.exit(1) # There might be more then one folder underneath - one per each scan-build # command (Ex: one for configure and one for make). @@ -656,4 +659,4 @@ if __name__ == '__main__': TestsPassed = testAll(IsReference, Strictness) if not TestsPassed: print "ERROR: Tests failed." - sys.exit(-1) + sys.exit(42) diff --git a/utils/analyzer/SATestUpdateDiffs.py b/utils/analyzer/SATestUpdateDiffs.py index a60c625245..c1c3a25cf5 100755 --- a/utils/analyzer/SATestUpdateDiffs.py +++ b/utils/analyzer/SATestUpdateDiffs.py @@ -32,7 +32,7 @@ def updateReferenceResults(ProjName, ProjBuildMode): if not os.path.exists(CreatedResultsPath): print >> sys.stderr, "New results not found, was SATestBuild.py "\ "previously run?" - sys.exit(-1) + sys.exit(1) # Remove reference results: in git, and then again for a good measure # with rm, as git might not remove things fully if there are empty @@ -75,7 +75,7 @@ def main(argv): print >> sys.stderr, "Update static analyzer reference results based "\ "\non the previous run of SATestBuild.py.\n"\ "\nN.B.: Assumes that SATestBuild.py was just run" - sys.exit(-1) + sys.exit(1) with SATestBuild.projectFileHandler() as f: for (ProjName, ProjBuildMode) in SATestBuild.iterateOverProjects(f): -- GitLab From e367d87861964e630d684b5780794c34fabf6a46 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 26 Oct 2017 03:09:53 +0000 Subject: [PATCH 0081/1682] [LSan] Enable -fsanitize=leak for PPC64 Linux. Summary: . Reviewers: eugenis Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D39312 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316636 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Driver/ToolChains/Linux.cpp | 2 +- test/Driver/fsanitize.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Driver/ToolChains/Linux.cpp b/lib/Driver/ToolChains/Linux.cpp index d99f98038b..613a9f3c88 100644 --- a/lib/Driver/ToolChains/Linux.cpp +++ b/lib/Driver/ToolChains/Linux.cpp @@ -837,7 +837,7 @@ SanitizerMask Linux::getSupportedSanitizers() const { Res |= SanitizerKind::SafeStack; if (IsX86_64 || IsMIPS64 || IsAArch64) Res |= SanitizerKind::DataFlow; - if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch) + if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64) Res |= SanitizerKind::Leak; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64) Res |= SanitizerKind::Thread; diff --git a/test/Driver/fsanitize.c b/test/Driver/fsanitize.c index d6f0f198b4..92d5c5da72 100644 --- a/test/Driver/fsanitize.c +++ b/test/Driver/fsanitize.c @@ -286,6 +286,9 @@ // RUN: %clang -target mips-unknown-linux -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL-MIPS // CHECK-SANL-MIPS: unsupported option '-fsanitize=leak' for target 'mips-unknown-linux' +// RUN: %clang -target powerpc64-unknown-linux -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL-PPC64 +// RUN: %clang -target powerpc64le-unknown-linux -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL-PPC64 +// CHECK-SANL-PPC64: "-fsanitize=leak" // RUN: %clang -target powerpc-unknown-linux -fsanitize=leak %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANL-PPC // CHECK-SANL-PPC: unsupported option '-fsanitize=leak' for target 'powerpc-unknown-linux' -- GitLab From 9bc9ee5d23d2b0b3c18dd86ce6b8aeae0aeb1bde Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Thu, 26 Oct 2017 08:41:28 +0000 Subject: [PATCH 0082/1682] Fix overloaded static functions in SemaCodeComplete https://bugs.llvm.org/show_bug.cgi?id=33904 Happens when static function is accessed via the class variable. That leads to incorrect overloads number because the variable is considered as the first argument. struct Bar { static void foo(); static void foo(int); }; int main() { Bar b; b.foo(/*complete here*/); // did not work before Bar::foo(/*complete here*/); // worked fine } Patch by Ivan Donchevskii! Differential Revision: https://reviews.llvm.org/D36390 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316646 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 3 +- lib/Sema/SemaCodeComplete.cpp | 4 ++- lib/Sema/SemaOverload.cpp | 28 +++++++++++----- test/Index/complete-call.cpp | 61 +++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 10 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ba9b604ebc..a156e88da6 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2707,7 +2707,8 @@ public: OverloadCandidateSet &CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, bool SuppressUserConversions = false, - bool PartialOverloading = false); + bool PartialOverloading = false, + bool FirstArgumentIsBase = false); void AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr::Classification ObjectClassification, diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 06246d469f..a0d8c9941e 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -4396,9 +4396,11 @@ void Sema::CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef Args) { ArgExprs.append(Args.begin(), Args.end()); UnresolvedSet<8> Decls; Decls.append(UME->decls_begin(), UME->decls_end()); + const bool FirstArgumentIsBase = !UME->isImplicitAccess() && UME->getBase(); AddFunctionCandidates(Decls, ArgExprs, CandidateSet, TemplateArgs, /*SuppressUsedConversions=*/false, - /*PartialOverloading=*/true); + /*PartialOverloading=*/true, + FirstArgumentIsBase); } else { FunctionDecl *FD = nullptr; if (auto MCE = dyn_cast(NakedFn)) diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 49e9126afc..8efb7c69d3 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -6343,24 +6343,36 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, OverloadCandidateSet& CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs, bool SuppressUserConversions, - bool PartialOverloading) { + bool PartialOverloading, + bool FirstArgumentIsBase) { for (UnresolvedSetIterator F = Fns.begin(), E = Fns.end(); F != E; ++F) { NamedDecl *D = F.getDecl()->getUnderlyingDecl(); if (FunctionDecl *FD = dyn_cast(D)) { + ArrayRef FunctionArgs = Args; if (isa(FD) && !cast(FD)->isStatic()) { QualType ObjectType; Expr::Classification ObjectClassification; - if (Expr *E = Args[0]) { - // Use the explit base to restrict the lookup: - ObjectType = E->getType(); - ObjectClassification = E->Classify(Context); - } // .. else there is an implit base. + if (Args.size() > 0) { + if (Expr *E = Args[0]) { + // Use the explit base to restrict the lookup: + ObjectType = E->getType(); + ObjectClassification = E->Classify(Context); + } // .. else there is an implit base. + FunctionArgs = Args.slice(1); + } AddMethodCandidate(cast(FD), F.getPair(), cast(FD)->getParent(), ObjectType, - ObjectClassification, Args.slice(1), CandidateSet, + ObjectClassification, FunctionArgs, CandidateSet, SuppressUserConversions, PartialOverloading); } else { - AddOverloadCandidate(FD, F.getPair(), Args, CandidateSet, + // Slice the first argument (which is the base) when we access + // static method as non-static + if (Args.size() > 0 && (!Args[0] || (FirstArgumentIsBase && isa(FD) && + !isa(FD)))) { + assert(cast(FD)->isStatic()); + FunctionArgs = Args.slice(1); + } + AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet, SuppressUserConversions, PartialOverloading); } } else { diff --git a/test/Index/complete-call.cpp b/test/Index/complete-call.cpp index 9750bd6f71..ca116485ac 100644 --- a/test/Index/complete-call.cpp +++ b/test/Index/complete-call.cpp @@ -94,6 +94,24 @@ int main() { s.foo_7(42,); } +struct Bar { + static void foo_1(); + void foo_1(float); + static void foo_1(int); +}; + +void test() { + Bar::foo_1(); + Bar b; + b.foo_1(); +} + +struct Bar2 : public Bar { + Bar2() { + Bar::foo_1(); + } +}; + // RUN: c-index-test -code-completion-at=%s:47:9 %s | FileCheck -check-prefix=CHECK-CC1 %s // CHECK-CC1: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1) // CHECK-CC1: Completion contexts: @@ -803,3 +821,46 @@ int main() { // CHECK-CC59-NEXT: Class name // CHECK-CC59-NEXT: Nested name specifier // CHECK-CC59-NEXT: Objective-C interface + +// RUN: c-index-test -code-completion-at=%s:104:14 %s | FileCheck -check-prefix=CHECK-CC60 %s +// CHECK-CC60: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1) +// CHECK-CC60: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter float}{RightParen )} (1) +// CHECK-CC60: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter int}{RightParen )} (1) +// CHECK-CC60: Completion contexts: +// CHECK-CC60-NEXT: Any type +// CHECK-CC60-NEXT: Any value +// CHECK-CC60-NEXT: Enum tag +// CHECK-CC60-NEXT: Union tag +// CHECK-CC60-NEXT: Struct tag +// CHECK-CC60-NEXT: Class name +// CHECK-CC60-NEXT: Nested name specifier +// CHECK-CC60-NEXT: Objective-C interface + +// RUN: c-index-test -code-completion-at=%s:106:11 %s | FileCheck -check-prefix=CHECK-CC61 %s +// CHECK-CC61: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1) +// CHECK-CC61: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter float}{RightParen )} (1) +// CHECK-CC61: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter int}{RightParen )} (1) +// CHECK-CC61: Completion contexts: +// CHECK-CC61-NEXT: Any type +// CHECK-CC61-NEXT: Any value +// CHECK-CC61-NEXT: Enum tag +// CHECK-CC61-NEXT: Union tag +// CHECK-CC61-NEXT: Struct tag +// CHECK-CC61-NEXT: Class name +// CHECK-CC61-NEXT: Nested name specifier +// CHECK-CC61-NEXT: Objective-C interface + +// RUN: c-index-test -code-completion-at=%s:111:16 %s | FileCheck -check-prefix=CHECK-CC62 %s +// CHECK-CC62: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{RightParen )} (1) +// CHECK-CC62: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter float}{RightParen )} (1) +// CHECK-CC62: OverloadCandidate:{ResultType void}{Text foo_1}{LeftParen (}{CurrentParameter int}{RightParen )} (1) +// CHECK-CC62: Completion contexts: +// CHECK-CC62-NEXT: Any type +// CHECK-CC62-NEXT: Any value +// CHECK-CC62-NEXT: Enum tag +// CHECK-CC62-NEXT: Union tag +// CHECK-CC62-NEXT: Struct tag +// CHECK-CC62-NEXT: Class name +// CHECK-CC62-NEXT: Nested name specifier +// CHECK-CC62-NEXT: Objective-C interface + -- GitLab From e7a10639e3b56be55f7fa5bf89d82d7b42e6fe3c Mon Sep 17 00:00:00 2001 From: Eric Liu Date: Thu, 26 Oct 2017 10:38:14 +0000 Subject: [PATCH 0083/1682] [Tooling] A new framework for executing clang frontend actions. Summary: This defines a `clang::tooling::ToolExecutor` interface that can be extended to support different execution plans including standalone execution on a given set of TUs or parallel execution on all TUs in a codebase. In order to enable multiprocessing execution, tool actions are expected to output result into a `ToolResults` interface provided by executors. The `ToolResults` interface abstracts how results are stored e.g. in-memory for standalone executions or on-disk for large-scale execution. New executors can be registered as `ToolExecutorPlugin`s via the `ToolExecutorPluginRegistry`. CLI tools can use `createExecutorFromCommandLineArgs` to create a specific registered executor according to the command-line arguments. This patch also implements `StandaloneToolExecutor` which has the same behavior as the current `ClangTool` interface, i.e. execute frontend actions on a given set of TUs. At this point, it's simply a wrapper around `ClangTool` at this point. This is still experimental but expected to replace the existing `ClangTool` interface so that specific tools would not need to worry about execution. Reviewers: klimek, arphaman, hokein, sammccall Reviewed By: klimek Subscribers: cfe-commits, djasper, mgorny, omtcyfz Differential Revision: https://reviews.llvm.org/D34272 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316653 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Tooling/CommonOptionsParser.h | 5 + include/clang/Tooling/Execution.h | 168 +++++++++++++ include/clang/Tooling/StandaloneExecution.h | 97 ++++++++ .../Tooling/ToolExecutorPluginRegistry.h | 24 ++ include/clang/Tooling/Tooling.h | 6 +- lib/Tooling/ArgumentsAdjusters.cpp | 4 + lib/Tooling/CMakeLists.txt | 2 + lib/Tooling/CommonOptionsParser.cpp | 8 +- lib/Tooling/Execution.cpp | 89 +++++++ lib/Tooling/StandaloneExecution.cpp | 91 +++++++ lib/Tooling/Tooling.cpp | 7 +- unittests/Tooling/CMakeLists.txt | 1 + unittests/Tooling/ExecutionTest.cpp | 228 ++++++++++++++++++ 13 files changed, 720 insertions(+), 10 deletions(-) create mode 100644 include/clang/Tooling/Execution.h create mode 100644 include/clang/Tooling/StandaloneExecution.h create mode 100644 include/clang/Tooling/ToolExecutorPluginRegistry.h create mode 100644 lib/Tooling/Execution.cpp create mode 100644 lib/Tooling/StandaloneExecution.cpp create mode 100644 unittests/Tooling/ExecutionTest.cpp diff --git a/include/clang/Tooling/CommonOptionsParser.h b/include/clang/Tooling/CommonOptionsParser.h index e89b59c4c5..15e8161dd7 100644 --- a/include/clang/Tooling/CommonOptionsParser.h +++ b/include/clang/Tooling/CommonOptionsParser.h @@ -109,6 +109,10 @@ public: return SourcePathList; } + /// Returns the argument adjuster calculated from "--extra-arg" and + //"--extra-arg-before" options. + ArgumentsAdjuster getArgumentsAdjuster() { return Adjuster; } + static const char *const HelpMessage; private: @@ -121,6 +125,7 @@ private: std::unique_ptr Compilations; std::vector SourcePathList; + ArgumentsAdjuster Adjuster; }; class ArgumentsAdjustingCompilations : public CompilationDatabase { diff --git a/include/clang/Tooling/Execution.h b/include/clang/Tooling/Execution.h new file mode 100644 index 0000000000..9d07c5659e --- /dev/null +++ b/include/clang/Tooling/Execution.h @@ -0,0 +1,168 @@ +//===--- Execution.h - Executing clang frontend actions -*- C++ ---------*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines framework for executing clang frontend actions. +// +// The framework can be extended to support different execution plans including +// standalone execution on the given TUs or parallel execution on all TUs in +// the codebase. +// +// In order to enable multiprocessing execution, tool actions are expected to +// output result into the ToolResults provided by the executor. The +// `ToolResults` is an interface that abstracts how results are stored e.g. +// in-memory for standalone execution or on-disk for large-scale execution. +// +// New executors can be registered as ToolExecutorPlugins via the +// `ToolExecutorPluginRegistry`. CLI tools can use +// `createExecutorFromCommandLineArgs` to create a specific registered executor +// according to the command-line arguments. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_EXECUTION_H +#define LLVM_CLANG_TOOLING_EXECUTION_H + +#include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Registry.h" + +namespace clang { +namespace tooling { + +/// \brief An abstraction for the result of a tool execution. For example, the +/// underlying result can be in-memory or on-disk. +/// +/// Results should be string key-value pairs. For example, a refactoring tool +/// can use source location as key and a replacement in YAML format as value. +class ToolResults { +public: + virtual ~ToolResults() = default; + virtual void addResult(StringRef Key, StringRef Value) = 0; + virtual std::vector> AllKVResults() = 0; + virtual void forEachResult( + llvm::function_ref Callback) = 0; +}; + +class InMemoryToolResults : public ToolResults { +public: + void addResult(StringRef Key, StringRef Value) override; + std::vector> AllKVResults() override; + void forEachResult(llvm::function_ref + Callback) override; + +private: + std::vector> KVResults; +}; + +/// \brief The context of an execution, including the information about +/// compilation and results. +class ExecutionContext { +public: + virtual ~ExecutionContext() {} + + /// \brief Initializes a context. This does not take ownership of `Results`. + explicit ExecutionContext(ToolResults *Results) : Results(Results) {} + + /// \brief Adds a KV pair to the result container of this execution. + void reportResult(StringRef Key, StringRef Value); + + // Returns the source control system's revision number if applicable. + // Otherwise returns an empty string. + virtual std::string getRevision() { return ""; } + + // Returns the corpus being analyzed, e.g. "llvm" for the LLVM codebase, if + // applicable. + virtual std::string getCorpus() { return ""; } + + // Returns the currently processed compilation unit if available. + virtual std::string getCurrentCompilationUnit() { return ""; } + +private: + ToolResults *Results; +}; + +/// \brief Interface for executing clang frontend actions. +/// +/// This can be extended to support running tool actions in different +/// execution mode, e.g. on a specific set of TUs or many TUs in parallel. +/// +/// New executors can be registered as ToolExecutorPlugins via the +/// `ToolExecutorPluginRegistry`. CLI tools can use +/// `createExecutorFromCommandLineArgs` to create a specific registered +/// executor according to the command-line arguments. +class ToolExecutor { +public: + virtual ~ToolExecutor() {} + + /// \brief Returns the name of a specific executor. + virtual StringRef getExecutorName() const = 0; + + /// \brief Executes each action with a corresponding arguments adjuster. + virtual llvm::Error + execute(llvm::ArrayRef< + std::pair, ArgumentsAdjuster>> + Actions) = 0; + + /// \brief Convenient functions for the above `execute`. + llvm::Error execute(std::unique_ptr Action); + /// Executes an action with an argument adjuster. + llvm::Error execute(std::unique_ptr Action, + ArgumentsAdjuster Adjuster); + + /// \brief Returns a reference to the execution context. + /// + /// This should be passed to tool callbacks, and tool callbacks should report + /// results via the returned context. + virtual ExecutionContext *getExecutionContext() = 0; + + /// \brief Returns a reference to the result container. + /// + /// NOTE: This should only be used after the execution finishes. Tool + /// callbacks should report results via `ExecutionContext` instead. + virtual ToolResults *getToolResults() = 0; + + /// \brief Map a virtual file to be used while running the tool. + /// + /// \param FilePath The path at which the content will be mapped. + /// \param Content A buffer of the file's content. + virtual void mapVirtualFile(StringRef FilePath, StringRef Content) = 0; +}; + +/// \brief Interface for factories that create specific executors. This is also +/// used as a plugin to be registered into ToolExecutorPluginRegistry. +class ToolExecutorPlugin { +public: + virtual ~ToolExecutorPlugin() {} + + /// \brief Create an `ToolExecutor`. + /// + /// `OptionsParser` can be consumed (e.g. moved) if the creation succeeds. + virtual llvm::Expected> + create(CommonOptionsParser &OptionsParser) = 0; +}; + +/// \brief This creates a ToolExecutor that is in the global registry based on +/// commandline arguments. +/// +/// This picks the right executor based on the `--executor` option. This parses +/// the commandline arguments with `CommonOptionsParser`, so caller does not +/// need to parse again. +/// +/// By default, this creates a `StandaloneToolExecutor` ("standalone") if +/// `--executor` is not provided. +llvm::Expected> +createExecutorFromCommandLineArgs(int &argc, const char **argv, + llvm::cl::OptionCategory &Category, + const char *Overview = nullptr); + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_EXECUTION_H diff --git a/include/clang/Tooling/StandaloneExecution.h b/include/clang/Tooling/StandaloneExecution.h new file mode 100644 index 0000000000..f5f32d737a --- /dev/null +++ b/include/clang/Tooling/StandaloneExecution.h @@ -0,0 +1,97 @@ +//===--- StandaloneExecution.h - Standalone execution. -*- C++ ----------*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines standalone execution of clang tools. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_STANDALONEEXECUTION_H +#define LLVM_CLANG_TOOLING_STANDALONEEXECUTION_H + +#include "clang/Tooling/ArgumentsAdjusters.h" +#include "clang/Tooling/Execution.h" + +namespace clang { +namespace tooling { + +/// \brief A standalone executor that runs FrontendActions on a given set of +/// TUs in sequence. +/// +/// By default, this executor uses the following arguments adjusters (as defined +/// in `clang/Tooling/ArgumentsAdjusters.h`): +/// - `getClangStripOutputAdjuster()` +/// - `getClangSyntaxOnlyAdjuster()` +/// - `getClangStripDependencyFileAdjuster()` +class StandaloneToolExecutor : public ToolExecutor { +public: + static const char *ExecutorName; + + /// \brief Init with \p CompilationDatabase and the paths of all files to be + /// proccessed. + StandaloneToolExecutor( + const CompilationDatabase &Compilations, + llvm::ArrayRef SourcePaths, + std::shared_ptr PCHContainerOps = + std::make_shared()); + + /// \brief Init with \p CommonOptionsParser. This is expected to be used by + /// `createExecutorFromCommandLineArgs` based on commandline options. + /// + /// The executor takes ownership of \p Options. + StandaloneToolExecutor( + CommonOptionsParser Options, + std::shared_ptr PCHContainerOps = + std::make_shared()); + + StringRef getExecutorName() const override { return ExecutorName; } + + using ToolExecutor::execute; + + llvm::Error + execute(llvm::ArrayRef< + std::pair, ArgumentsAdjuster>> + Actions) override; + + /// \brief Set a \c DiagnosticConsumer to use during parsing. + void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer) { + Tool.setDiagnosticConsumer(DiagConsumer); + } + + ExecutionContext *getExecutionContext() override { return &Context; }; + + ToolResults *getToolResults() override { return &Results; } + + llvm::ArrayRef getSourcePaths() const { + return Tool.getSourcePaths(); + } + + void mapVirtualFile(StringRef FilePath, StringRef Content) override { + Tool.mapVirtualFile(FilePath, Content); + } + + /// \brief Returns the file manager used in the tool. + /// + /// The file manager is shared between all translation units. + FileManager &getFiles() { return Tool.getFiles(); } + +private: + // Used to store the parser when the executor is initialized with parser. + llvm::Optional OptionsParser; + // FIXME: The standalone executor is currently just a wrapper of `ClangTool`. + // Merge `ClangTool` implementation into the this. + ClangTool Tool; + ExecutionContext Context; + InMemoryToolResults Results; + ArgumentsAdjuster ArgsAdjuster; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_STANDALONEEXECUTION_H diff --git a/include/clang/Tooling/ToolExecutorPluginRegistry.h b/include/clang/Tooling/ToolExecutorPluginRegistry.h new file mode 100644 index 0000000000..11ba89546e --- /dev/null +++ b/include/clang/Tooling/ToolExecutorPluginRegistry.h @@ -0,0 +1,24 @@ +//===--- ToolExecutorPluginRegistry.h - -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H +#define LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H + +#include "clang/Tooling/Execution.h" +#include "llvm/Support/Registry.h" + +namespace clang { +namespace tooling { + +typedef llvm::Registry ToolExecutorPluginRegistry; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_TOOLEXECUTORPLUGINREGISTRY_H diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h index 6f9bc9e1a1..e64be07d9a 100644 --- a/include/clang/Tooling/Tooling.h +++ b/include/clang/Tooling/Tooling.h @@ -31,12 +31,12 @@ #define LLVM_CLANG_TOOLING_TOOLING_H #include "clang/AST/ASTConsumer.h" -#include "clang/Frontend/PCHContainerOperations.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LLVM.h" #include "clang/Driver/Util.h" #include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/PCHContainerOperations.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Tooling/CompilationDatabase.h" @@ -337,7 +337,9 @@ class ClangTool { /// The file manager is shared between all translation units. FileManager &getFiles() { return *Files; } - private: + llvm::ArrayRef getSourcePaths() const { return SourcePaths; } + +private: const CompilationDatabase &Compilations; std::vector SourcePaths; std::shared_ptr PCHContainerOps; diff --git a/lib/Tooling/ArgumentsAdjusters.cpp b/lib/Tooling/ArgumentsAdjusters.cpp index ac9fd3c5ca..962ea45258 100644 --- a/lib/Tooling/ArgumentsAdjusters.cpp +++ b/lib/Tooling/ArgumentsAdjusters.cpp @@ -96,6 +96,10 @@ ArgumentsAdjuster getInsertArgumentAdjuster(const char *Extra, ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First, ArgumentsAdjuster Second) { + if (!First) + return Second; + if (!Second) + return First; return [First, Second](const CommandLineArguments &Args, StringRef File) { return Second(First(Args, File), File); }; diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt index 32a1935b3f..ee681bbb45 100644 --- a/lib/Tooling/CMakeLists.txt +++ b/lib/Tooling/CMakeLists.txt @@ -11,11 +11,13 @@ add_clang_library(clangTooling ArgumentsAdjusters.cpp CommonOptionsParser.cpp CompilationDatabase.cpp + Execution.cpp FileMatchTrie.cpp FixIt.cpp JSONCompilationDatabase.cpp Refactoring.cpp RefactoringCallbacks.cpp + StandaloneExecution.cpp Tooling.cpp DEPENDS diff --git a/lib/Tooling/CommonOptionsParser.cpp b/lib/Tooling/CommonOptionsParser.cpp index 9ad15cc8b2..74ad4e83ee 100644 --- a/lib/Tooling/CommonOptionsParser.cpp +++ b/lib/Tooling/CommonOptionsParser.cpp @@ -147,10 +147,12 @@ llvm::Error CommonOptionsParser::init( auto AdjustingCompilations = llvm::make_unique( std::move(Compilations)); - AdjustingCompilations->appendArgumentsAdjuster( - getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN)); - AdjustingCompilations->appendArgumentsAdjuster( + Adjuster = + getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN); + Adjuster = combineAdjusters( + std::move(Adjuster), getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END)); + AdjustingCompilations->appendArgumentsAdjuster(Adjuster); Compilations = std::move(AdjustingCompilations); return llvm::Error::success(); } diff --git a/lib/Tooling/Execution.cpp b/lib/Tooling/Execution.cpp new file mode 100644 index 0000000000..1a078ef7e1 --- /dev/null +++ b/lib/Tooling/Execution.cpp @@ -0,0 +1,89 @@ +//===- lib/Tooling/Execution.cpp - Implements tool execution framework. ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Execution.h" +#include "clang/Tooling/ToolExecutorPluginRegistry.h" +#include "clang/Tooling/Tooling.h" + +LLVM_INSTANTIATE_REGISTRY(clang::tooling::ToolExecutorPluginRegistry) + +namespace clang { +namespace tooling { + +static llvm::cl::opt + ExecutorName("executor", llvm::cl::desc("The name of the executor to use."), + llvm::cl::init("standalone")); + +void InMemoryToolResults::addResult(StringRef Key, StringRef Value) { + KVResults.push_back({Key.str(), Value.str()}); +} + +std::vector> +InMemoryToolResults::AllKVResults() { + return KVResults; +} + +void InMemoryToolResults::forEachResult( + llvm::function_ref Callback) { + for (const auto &KV : KVResults) { + Callback(KV.first, KV.second); + } +} + +void ExecutionContext::reportResult(StringRef Key, StringRef Value) { + Results->addResult(Key, Value); +} + +llvm::Error +ToolExecutor::execute(std::unique_ptr Action) { + return execute(std::move(Action), ArgumentsAdjuster()); +} + +llvm::Error ToolExecutor::execute(std::unique_ptr Action, + ArgumentsAdjuster Adjuster) { + std::vector< + std::pair, ArgumentsAdjuster>> + Actions; + Actions.emplace_back(std::move(Action), std::move(Adjuster)); + return execute(Actions); +} + +llvm::Expected> +createExecutorFromCommandLineArgs(int &argc, const char **argv, + llvm::cl::OptionCategory &Category, + const char *Overview) { + auto OptionsParser = + CommonOptionsParser::create(argc, argv, Category, llvm::cl::ZeroOrMore, + /*Overview=*/nullptr); + if (!OptionsParser) + return OptionsParser.takeError(); + for (auto I = ToolExecutorPluginRegistry::begin(), + E = ToolExecutorPluginRegistry::end(); + I != E; ++I) { + if (I->getName() != ExecutorName) { + continue; + } + std::unique_ptr Plugin(I->instantiate()); + llvm::Expected> Executor = + Plugin->create(*OptionsParser); + if (!Executor) { + return llvm::make_error( + llvm::Twine("Failed to create '") + I->getName() + + "': " + llvm::toString(Executor.takeError()) + "\n", + llvm::inconvertibleErrorCode()); + } + return std::move(*Executor); + } + return llvm::make_error( + llvm::Twine("Executor \"") + ExecutorName + "\" is not registered.", + llvm::inconvertibleErrorCode()); +} + +} // end namespace tooling +} // end namespace clang diff --git a/lib/Tooling/StandaloneExecution.cpp b/lib/Tooling/StandaloneExecution.cpp new file mode 100644 index 0000000000..aade40b62a --- /dev/null +++ b/lib/Tooling/StandaloneExecution.cpp @@ -0,0 +1,91 @@ +//===- lib/Tooling/Execution.cpp - Standalone clang action execution. -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/StandaloneExecution.h" +#include "clang/Tooling/ToolExecutorPluginRegistry.h" + +namespace clang { +namespace tooling { + +static llvm::Error make_string_error(const llvm::Twine &Message) { + return llvm::make_error(Message, + llvm::inconvertibleErrorCode()); +} + +const char *StandaloneToolExecutor::ExecutorName = "StandaloneToolExecutor"; + +static ArgumentsAdjuster getDefaultArgumentsAdjusters() { + return combineAdjusters( + getClangStripOutputAdjuster(), + combineAdjusters(getClangSyntaxOnlyAdjuster(), + getClangStripDependencyFileAdjuster())); +} + +StandaloneToolExecutor::StandaloneToolExecutor( + const CompilationDatabase &Compilations, + llvm::ArrayRef SourcePaths, + std::shared_ptr PCHContainerOps) + : Tool(Compilations, SourcePaths), Context(&Results), + ArgsAdjuster(getDefaultArgumentsAdjusters()) { + // Use self-defined default argument adjusters instead of the default + // adjusters that come with the old `ClangTool`. + Tool.clearArgumentsAdjusters(); +} + +StandaloneToolExecutor::StandaloneToolExecutor( + CommonOptionsParser Options, + std::shared_ptr PCHContainerOps) + : OptionsParser(std::move(Options)), + Tool(OptionsParser->getCompilations(), OptionsParser->getSourcePathList(), + PCHContainerOps), + Context(&Results), ArgsAdjuster(getDefaultArgumentsAdjusters()) { + Tool.clearArgumentsAdjusters(); +} + +llvm::Error StandaloneToolExecutor::execute( + llvm::ArrayRef< + std::pair, ArgumentsAdjuster>> + Actions) { + if (Actions.empty()) + return make_string_error("No action to execute."); + + if (Actions.size() != 1) + return make_string_error( + "Only support executing exactly 1 action at this point."); + + auto &Action = Actions.front(); + Tool.appendArgumentsAdjuster(Action.second); + Tool.appendArgumentsAdjuster(ArgsAdjuster); + if (int Ret = Tool.run(Action.first.get())) + return make_string_error("Failed to run action."); + + return llvm::Error::success(); +} + +class StandaloneToolExecutorPlugin : public ToolExecutorPlugin { +public: + llvm::Expected> + create(CommonOptionsParser &OptionsParser) override { + if (OptionsParser.getSourcePathList().empty()) + return make_string_error( + "[StandaloneToolExecutorPlugin] No positional argument found."); + return llvm::make_unique(std::move(OptionsParser)); + } +}; + +// This anchor is used to force the linker to link in the generated object file +// and thus register the plugin. +volatile int ToolExecutorPluginAnchorSource = 0; + +static ToolExecutorPluginRegistry::Add + X("standalone", "Runs FrontendActions on a set of files provided " + "via positional arguments."); + +} // end namespace tooling +} // end namespace clang diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp index df9d7df694..4fbfa4f004 100644 --- a/lib/Tooling/Tooling.cpp +++ b/lib/Tooling/Tooling.cpp @@ -29,6 +29,7 @@ #include "llvm/Config/llvm-config.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" @@ -347,11 +348,7 @@ void ClangTool::mapVirtualFile(StringRef FilePath, StringRef Content) { } void ClangTool::appendArgumentsAdjuster(ArgumentsAdjuster Adjuster) { - if (ArgsAdjuster) - ArgsAdjuster = - combineAdjusters(std::move(ArgsAdjuster), std::move(Adjuster)); - else - ArgsAdjuster = std::move(Adjuster); + ArgsAdjuster = combineAdjusters(std::move(ArgsAdjuster), std::move(Adjuster)); } void ClangTool::clearArgumentsAdjusters() { diff --git a/unittests/Tooling/CMakeLists.txt b/unittests/Tooling/CMakeLists.txt index abd82c7580..f9ddf7ffc1 100644 --- a/unittests/Tooling/CMakeLists.txt +++ b/unittests/Tooling/CMakeLists.txt @@ -16,6 +16,7 @@ add_clang_unittest(ToolingTests CommentHandlerTest.cpp CompilationDatabaseTest.cpp DiagnosticsYamlTest.cpp + ExecutionTest.cpp FixItTest.cpp LexicallyOrderedRecursiveASTVisitorTest.cpp LookupTest.cpp diff --git a/unittests/Tooling/ExecutionTest.cpp b/unittests/Tooling/ExecutionTest.cpp new file mode 100644 index 0000000000..da482b88f5 --- /dev/null +++ b/unittests/Tooling/ExecutionTest.cpp @@ -0,0 +1,228 @@ +//===- unittest/Tooling/ExecutionTest.cpp - Tool execution tests. --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/Execution.h" +#include "clang/Tooling/StandaloneExecution.h" +#include "clang/Tooling/ToolExecutorPluginRegistry.h" +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" +#include +#include + +namespace clang { +namespace tooling { + +namespace { + +// This traverses the AST and outputs function name as key and "1" as value for +// each function declaration. +class ASTConsumerWithResult + : public ASTConsumer, + public RecursiveASTVisitor { +public: + using ASTVisitor = RecursiveASTVisitor; + + explicit ASTConsumerWithResult(ExecutionContext *Context) : Context(Context) { + assert(Context != nullptr); + } + + void HandleTranslationUnit(clang::ASTContext &Context) override { + TraverseDecl(Context.getTranslationUnitDecl()); + } + + bool TraverseFunctionDecl(clang::FunctionDecl *Decl) { + Context->reportResult(Decl->getNameAsString(), "1"); + return ASTVisitor::TraverseFunctionDecl(Decl); + } + +private: + ExecutionContext *const Context; +}; + +class ReportResultAction : public ASTFrontendAction { +public: + explicit ReportResultAction(ExecutionContext *Context) : Context(Context) { + assert(Context != nullptr); + } + +protected: + std::unique_ptr + CreateASTConsumer(clang::CompilerInstance &compiler, + StringRef /* dummy */) override { + std::unique_ptr ast_consumer{ + new ASTConsumerWithResult(Context)}; + return ast_consumer; + } + +private: + ExecutionContext *const Context; +}; + +class ReportResultActionFactory : public FrontendActionFactory { +public: + ReportResultActionFactory(ExecutionContext *Context) : Context(Context) {} + FrontendAction *create() override { return new ReportResultAction(Context); } + +private: + ExecutionContext *const Context; +}; + +} // namespace + +class TestToolExecutor : public ToolExecutor { +public: + static const char *ExecutorName; + + TestToolExecutor(CommonOptionsParser Options) + : OptionsParser(std::move(Options)) {} + + StringRef getExecutorName() const override { return ExecutorName; } + + llvm::Error + execute(llvm::ArrayRef, + ArgumentsAdjuster>>) override { + return llvm::Error::success(); + } + + ExecutionContext *getExecutionContext() override { return nullptr; }; + + ToolResults *getToolResults() override { return nullptr; } + + llvm::ArrayRef getSourcePaths() const { + return OptionsParser.getSourcePathList(); + } + + void mapVirtualFile(StringRef FilePath, StringRef Content) override { + VFS[FilePath] = Content; + } + +private: + CommonOptionsParser OptionsParser; + std::string SourcePaths; + std::map VFS; +}; + +const char *TestToolExecutor::ExecutorName = "test-executor"; + +class TestToolExecutorPlugin : public ToolExecutorPlugin { +public: + llvm::Expected> + create(CommonOptionsParser &OptionsParser) override { + return llvm::make_unique(std::move(OptionsParser)); + } +}; + +// This anchor is used to force the linker to link in the generated object file +// and thus register the plugin. +extern volatile int ToolExecutorPluginAnchorSource; + +static int LLVM_ATTRIBUTE_UNUSED TestToolExecutorPluginAnchorDest = + ToolExecutorPluginAnchorSource; + +static ToolExecutorPluginRegistry::Add + X("test-executor", "Plugin for TestToolExecutor."); + +llvm::cl::OptionCategory TestCategory("execution-test options"); + +TEST(CreateToolExecutorTest, FailedCreateExecutorUndefinedFlag) { + std::vector argv = {"prog", "--fake_flag_no_no_no", "f"}; + int argc = argv.size(); + auto Executor = + createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory); + ASSERT_FALSE((bool)Executor); + llvm::consumeError(Executor.takeError()); +} + +TEST(CreateToolExecutorTest, RegisterFlagsBeforeReset) { + llvm::cl::opt BeforeReset( + "before_reset", llvm::cl::desc("Defined before reset."), + llvm::cl::init("")); + + llvm::cl::ResetAllOptionOccurrences(); + + std::vector argv = {"prog", "--before_reset=set", "f"}; + int argc = argv.size(); + auto Executor = + createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory); + ASSERT_TRUE((bool)Executor); + EXPECT_EQ(BeforeReset, "set"); + BeforeReset.removeArgument(); +} + +TEST(CreateToolExecutorTest, CreateStandaloneToolExecutor) { + std::vector argv = {"prog", "standalone.cpp"}; + int argc = argv.size(); + auto Executor = + createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory); + ASSERT_TRUE((bool)Executor); + EXPECT_EQ(Executor->get()->getExecutorName(), + StandaloneToolExecutor::ExecutorName); +} + +TEST(CreateToolExecutorTest, CreateTestToolExecutor) { + std::vector argv = {"prog", "test.cpp", + "--executor=test-executor"}; + int argc = argv.size(); + auto Executor = + createExecutorFromCommandLineArgs(argc, &argv[0], TestCategory); + ASSERT_TRUE((bool)Executor); + EXPECT_EQ(Executor->get()->getExecutorName(), TestToolExecutor::ExecutorName); +} + +TEST(StandaloneToolTest, SynctaxOnlyActionOnSimpleCode) { + FixedCompilationDatabase Compilations("/", std::vector()); + StandaloneToolExecutor Executor(Compilations, + std::vector(1, "/a.cc")); + Executor.mapVirtualFile("/a.cc", "int x = 0;"); + + auto Err = Executor.execute(newFrontendActionFactory(), + getClangSyntaxOnlyAdjuster()); + ASSERT_TRUE(!Err); +} + +TEST(StandaloneToolTest, SimpleAction) { + FixedCompilationDatabase Compilations("/", std::vector()); + StandaloneToolExecutor Executor(Compilations, + std::vector(1, "/a.cc")); + Executor.mapVirtualFile("/a.cc", "int x = 0;"); + + auto Err = Executor.execute(std::unique_ptr( + new ReportResultActionFactory(Executor.getExecutionContext()))); + ASSERT_TRUE(!Err); + auto KVs = Executor.getToolResults()->AllKVResults(); + ASSERT_EQ(KVs.size(), 0u); +} + +TEST(StandaloneToolTest, SimpleActionWithResult) { + FixedCompilationDatabase Compilations("/", std::vector()); + StandaloneToolExecutor Executor(Compilations, + std::vector(1, "/a.cc")); + Executor.mapVirtualFile("/a.cc", "int x = 0; void f() {}"); + + auto Err = Executor.execute(std::unique_ptr( + new ReportResultActionFactory(Executor.getExecutionContext()))); + ASSERT_TRUE(!Err); + auto KVs = Executor.getToolResults()->AllKVResults(); + ASSERT_EQ(KVs.size(), 1u); + EXPECT_EQ("f", KVs[0].first); + EXPECT_EQ("1", KVs[0].second); + + Executor.getToolResults()->forEachResult( + [](StringRef, StringRef Value) { EXPECT_EQ("1", Value); }); +} + +} // end namespace tooling +} // end namespace clang -- GitLab From d090ddde4021a9b9cd81a4abea28487be1c60c55 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Thu, 26 Oct 2017 12:19:02 +0000 Subject: [PATCH 0084/1682] Add a new attribute definition spelling, Clang<"attr">, that expands to two attribute spellings: GNU<"attr"> and CXX11<"clang", "attr">. This is similar to how the GCC spelling works and is intended to be used for attributes introduced for Clang. Changes all existing attributes that currently use GNU<"attr"> and CXX11<"clang", "attr> spellings to instead use the Clang<"attr"> spelling. No additional tests are necessary because the existing tests already use both spellings for the attributes converted to the new spelling. No functional changes are expected. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316658 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Attr.td | 110 +++++++++++----------------- utils/TableGen/ClangAttrEmitter.cpp | 16 ++-- 2 files changed, 53 insertions(+), 73 deletions(-) diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index af3e71641c..0090b99526 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -219,13 +219,17 @@ class Pragma : Spelling { string Namespace = namespace; } -// The GCC spelling implies GNU and CXX11<"gnu", name> and also -// sets KnownToGCC to 1. This spelling should be used for any GCC-compatible +// The GCC spelling implies GNU and CXX11<"gnu", name> and also sets +// KnownToGCC to 1. This spelling should be used for any GCC-compatible // attributes. class GCC : Spelling { let KnownToGCC = 1; } +// The Clang spelling implies GNU and CXX11<"clang", name>. This spelling +// should be used for any Clang-specific attributes. +class Clang : Spelling; + class Accessor spellings> { string Name = name; list Spellings = spellings; @@ -563,23 +567,19 @@ def AlwaysInline : InheritableAttr { } def XRayInstrument : InheritableAttr { - let Spellings = [GNU<"xray_always_instrument">, - CXX11<"clang", "xray_always_instrument">, - GNU<"xray_never_instrument">, - CXX11<"clang", "xray_never_instrument">]; + let Spellings = [Clang<"xray_always_instrument">, + Clang<"xray_never_instrument">]; let Subjects = SubjectList<[CXXMethod, ObjCMethod, Function], WarnDiag, "ExpectedFunctionOrMethod">; let Accessors = [Accessor<"alwaysXRayInstrument", - [GNU<"xray_always_instrument">, - CXX11<"clang", "xray_always_instrument">]>, + [Clang<"xray_always_instrument">]>, Accessor<"neverXRayInstrument", - [GNU<"xray_never_instrument">, - CXX11<"clang", "xray_never_instrument">]>]; + [Clang<"xray_never_instrument">]>]; let Documentation = [XRayDocs]; } def XRayLogArgs : InheritableAttr { - let Spellings = [GNU<"xray_log_args">, CXX11<"clang", "xray_log_args">]; + let Spellings = [Clang<"xray_log_args">]; let Subjects = SubjectList< [CXXMethod, ObjCMethod, Function], WarnDiag, "ExpectedFunctionOrMethod" >; @@ -692,8 +692,7 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) { } def ExternalSourceSymbol : InheritableAttr { - let Spellings = [GNU<"external_source_symbol">, - CXX11<"clang", "external_source_symbol">]; + let Spellings = [Clang<"external_source_symbol">]; let Args = [StringArgument<"language", 1>, StringArgument<"definedIn", 1>, BoolArgument<"generatedDeclaration", 1>]; @@ -1047,8 +1046,7 @@ def FlagEnum : InheritableAttr { } def EnumExtensibility : InheritableAttr { - let Spellings = [GNU<"enum_extensibility">, - CXX11<"clang", "enum_extensibility">]; + let Spellings = [Clang<"enum_extensibility">]; let Subjects = SubjectList<[Enum]>; let Args = [EnumArgument<"Extensibility", "Kind", ["closed", "open"], ["Closed", "Open"]>]; @@ -1238,8 +1236,7 @@ def ReturnsTwice : InheritableAttr { } def DisableTailCalls : InheritableAttr { - let Spellings = [GNU<"disable_tail_calls">, - CXX11<"clang", "disable_tail_calls">]; + let Spellings = [Clang<"disable_tail_calls">]; let Subjects = SubjectList<[Function, ObjCMethod]>; let Documentation = [DisableTailCallsDocs]; } @@ -1264,13 +1261,13 @@ def NoDebug : InheritableAttr { } def NoDuplicate : InheritableAttr { - let Spellings = [GNU<"noduplicate">, CXX11<"clang", "noduplicate">]; + let Spellings = [Clang<"noduplicate">]; let Subjects = SubjectList<[Function]>; let Documentation = [NoDuplicateDocs]; } def Convergent : InheritableAttr { - let Spellings = [GNU<"convergent">, CXX11<"clang", "convergent">]; + let Spellings = [Clang<"convergent">]; let Subjects = SubjectList<[Function]>; let Documentation = [ConvergentDocs]; } @@ -1401,7 +1398,7 @@ def ObjCKindOf : TypeAttr { } def NoEscape : Attr { - let Spellings = [GNU<"noescape">, CXX11<"clang", "noescape">]; + let Spellings = [Clang<"noescape">]; let Subjects = SubjectList<[ParmVar]>; let Documentation = [NoEscapeDocs]; } @@ -1434,7 +1431,7 @@ def NoInstrumentFunction : InheritableAttr { } def NotTailCalled : InheritableAttr { - let Spellings = [GNU<"not_tail_called">, CXX11<"clang", "not_tail_called">]; + let Spellings = [Clang<"not_tail_called">]; let Subjects = SubjectList<[Function]>; let Documentation = [NotTailCalledDocs]; } @@ -1596,7 +1593,7 @@ def ObjCBoxable : Attr { } def OptimizeNone : InheritableAttr { - let Spellings = [GNU<"optnone">, CXX11<"clang", "optnone">]; + let Spellings = [Clang<"optnone">]; let Subjects = SubjectList<[Function, ObjCMethod]>; let Documentation = [OptnoneDocs]; } @@ -1674,8 +1671,7 @@ def ReqdWorkGroupSize : InheritableAttr { } def RequireConstantInit : InheritableAttr { - let Spellings = [GNU<"require_constant_initialization">, - CXX11<"clang", "require_constant_initialization">]; + let Spellings = [Clang<"require_constant_initialization">]; let Subjects = SubjectList<[GlobalVar], ErrorDiag, "ExpectedStaticOrTLSVar">; let Documentation = [RequireConstantInitDocs]; @@ -1984,7 +1980,7 @@ def Visibility : InheritableAttr { def TypeVisibility : InheritableAttr { let Clone = 0; - let Spellings = [GNU<"type_visibility">, CXX11<"clang", "type_visibility">]; + let Spellings = [Clang<"type_visibility">]; let Args = [EnumArgument<"Visibility", "VisibilityType", ["default", "hidden", "internal", "protected"], ["Default", "Hidden", "Hidden", "Protected"]>]; @@ -2063,7 +2059,7 @@ def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr } def NoSanitize : InheritableAttr { - let Spellings = [GNU<"no_sanitize">, CXX11<"clang", "no_sanitize">]; + let Spellings = [Clang<"no_sanitize">]; let Args = [VariadicStringArgument<"Sanitizers">]; let Subjects = SubjectList<[Function, ObjCMethod, GlobalVar], ErrorDiag, "ExpectedFunctionMethodOrGlobalVar">; @@ -2125,15 +2121,12 @@ def ScopedLockable : InheritableAttr { } def Capability : InheritableAttr { - let Spellings = [GNU<"capability">, CXX11<"clang", "capability">, - GNU<"shared_capability">, - CXX11<"clang", "shared_capability">]; + let Spellings = [Clang<"capability">, Clang<"shared_capability">]; let Subjects = SubjectList<[Record, TypedefName], ErrorDiag, "ExpectedStructOrUnionOrTypedef">; let Args = [StringArgument<"Name">]; let Accessors = [Accessor<"isShared", - [GNU<"shared_capability">, - CXX11<"clang","shared_capability">]>]; + [Clang<"shared_capability">]>]; let Documentation = [Undocumented]; let AdditionalMembers = [{ bool isMutex() const { return getName().equals_lower("mutex"); } @@ -2142,10 +2135,8 @@ def Capability : InheritableAttr { } def AssertCapability : InheritableAttr { - let Spellings = [GNU<"assert_capability">, - CXX11<"clang", "assert_capability">, - GNU<"assert_shared_capability">, - CXX11<"clang", "assert_shared_capability">]; + let Spellings = [Clang<"assert_capability">, + Clang<"assert_shared_capability">]; let Subjects = SubjectList<[Function]>; let LateParsed = 1; let TemplateDependent = 1; @@ -2153,16 +2144,13 @@ def AssertCapability : InheritableAttr { let DuplicatesAllowedWhileMerging = 1; let Args = [VariadicExprArgument<"Args">]; let Accessors = [Accessor<"isShared", - [GNU<"assert_shared_capability">, - CXX11<"clang", "assert_shared_capability">]>]; + [Clang<"assert_shared_capability">]>]; let Documentation = [AssertCapabilityDocs]; } def AcquireCapability : InheritableAttr { - let Spellings = [GNU<"acquire_capability">, - CXX11<"clang", "acquire_capability">, - GNU<"acquire_shared_capability">, - CXX11<"clang", "acquire_shared_capability">, + let Spellings = [Clang<"acquire_capability">, + Clang<"acquire_shared_capability">, GNU<"exclusive_lock_function">, GNU<"shared_lock_function">]; let Subjects = SubjectList<[Function]>; @@ -2172,17 +2160,14 @@ def AcquireCapability : InheritableAttr { let DuplicatesAllowedWhileMerging = 1; let Args = [VariadicExprArgument<"Args">]; let Accessors = [Accessor<"isShared", - [GNU<"acquire_shared_capability">, - CXX11<"clang", "acquire_shared_capability">, + [Clang<"acquire_shared_capability">, GNU<"shared_lock_function">]>]; let Documentation = [AcquireCapabilityDocs]; } def TryAcquireCapability : InheritableAttr { - let Spellings = [GNU<"try_acquire_capability">, - CXX11<"clang", "try_acquire_capability">, - GNU<"try_acquire_shared_capability">, - CXX11<"clang", "try_acquire_shared_capability">]; + let Spellings = [Clang<"try_acquire_capability">, + Clang<"try_acquire_shared_capability">]; let Subjects = SubjectList<[Function], ErrorDiag>; let LateParsed = 1; @@ -2191,18 +2176,14 @@ def TryAcquireCapability : InheritableAttr { let DuplicatesAllowedWhileMerging = 1; let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">]; let Accessors = [Accessor<"isShared", - [GNU<"try_acquire_shared_capability">, - CXX11<"clang", "try_acquire_shared_capability">]>]; + [Clang<"try_acquire_shared_capability">]>]; let Documentation = [TryAcquireCapabilityDocs]; } def ReleaseCapability : InheritableAttr { - let Spellings = [GNU<"release_capability">, - CXX11<"clang", "release_capability">, - GNU<"release_shared_capability">, - CXX11<"clang", "release_shared_capability">, - GNU<"release_generic_capability">, - CXX11<"clang", "release_generic_capability">, + let Spellings = [Clang<"release_capability">, + Clang<"release_shared_capability">, + Clang<"release_generic_capability">, GNU<"unlock_function">]; let Subjects = SubjectList<[Function]>; let LateParsed = 1; @@ -2211,21 +2192,17 @@ def ReleaseCapability : InheritableAttr { let DuplicatesAllowedWhileMerging = 1; let Args = [VariadicExprArgument<"Args">]; let Accessors = [Accessor<"isShared", - [GNU<"release_shared_capability">, - CXX11<"clang", "release_shared_capability">]>, + [Clang<"release_shared_capability">]>, Accessor<"isGeneric", - [GNU<"release_generic_capability">, - CXX11<"clang", "release_generic_capability">, + [Clang<"release_generic_capability">, GNU<"unlock_function">]>]; let Documentation = [ReleaseCapabilityDocs]; } def RequiresCapability : InheritableAttr { - let Spellings = [GNU<"requires_capability">, - CXX11<"clang", "requires_capability">, + let Spellings = [Clang<"requires_capability">, GNU<"exclusive_locks_required">, - GNU<"requires_shared_capability">, - CXX11<"clang", "requires_shared_capability">, + Clang<"requires_shared_capability">, GNU<"shared_locks_required">]; let Args = [VariadicExprArgument<"Args">]; let LateParsed = 1; @@ -2233,9 +2210,8 @@ def RequiresCapability : InheritableAttr { let ParseArgumentsAsUnevaluated = 1; let DuplicatesAllowedWhileMerging = 1; let Subjects = SubjectList<[Function]>; - let Accessors = [Accessor<"isShared", [GNU<"requires_shared_capability">, - GNU<"shared_locks_required">, - CXX11<"clang","requires_shared_capability">]>]; + let Accessors = [Accessor<"isShared", [Clang<"requires_shared_capability">, + GNU<"shared_locks_required">]>]; let Documentation = [Undocumented]; } @@ -2792,7 +2768,7 @@ def OMPDeclareTargetDecl : Attr { } def InternalLinkage : InheritableAttr { - let Spellings = [GNU<"internal_linkage">, CXX11<"clang", "internal_linkage">]; + let Spellings = [Clang<"internal_linkage">]; let Subjects = SubjectList<[Var, Function, CXXRecord]>; let Documentation = [InternalLinkageDocs]; } diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index effabcc6cb..9284fe4081 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -56,8 +56,8 @@ public: V(Spelling.getValueAsString("Variety")), N(Spelling.getValueAsString("Name")) { - assert(V != "GCC" && "Given a GCC spelling, which means this hasn't been" - "flattened!"); + assert(V != "GCC" && V != "Clang" && + "Given a GCC spelling, which means this hasn't been flattened!"); if (V == "CXX11" || V == "C2x" || V == "Pragma") NS = Spelling.getValueAsString("Namespace"); bool Unset; @@ -78,11 +78,15 @@ GetFlattenedSpellings(const Record &Attr) { std::vector Ret; for (const auto &Spelling : Spellings) { - if (Spelling->getValueAsString("Variety") == "GCC") { + StringRef Variety = Spelling->getValueAsString("Variety"); + StringRef Name = Spelling->getValueAsString("Name"); + if (Variety == "GCC") { // Gin up two new spelling objects to add into the list. - Ret.emplace_back("GNU", Spelling->getValueAsString("Name"), "", true); - Ret.emplace_back("CXX11", Spelling->getValueAsString("Name"), "gnu", - true); + Ret.emplace_back("GNU", Name, "", true); + Ret.emplace_back("CXX11", Name, "gnu", true); + } else if (Variety == "Clang") { + Ret.emplace_back("GNU", Name, "", false); + Ret.emplace_back("CXX11", Name, "clang", false); } else Ret.push_back(FlattenedSpelling(*Spelling)); } -- GitLab From 8084ad7fc6453b51a6422b6c73e41644910d7bd3 Mon Sep 17 00:00:00 2001 From: Eric Liu Date: Thu, 26 Oct 2017 13:09:50 +0000 Subject: [PATCH 0085/1682] Try to fix warnings and windows test failures caused by r316653 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316661 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Tooling/StandaloneExecution.cpp | 2 +- unittests/Tooling/ExecutionTest.cpp | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/Tooling/StandaloneExecution.cpp b/lib/Tooling/StandaloneExecution.cpp index aade40b62a..e52e4a611f 100644 --- a/lib/Tooling/StandaloneExecution.cpp +++ b/lib/Tooling/StandaloneExecution.cpp @@ -62,7 +62,7 @@ llvm::Error StandaloneToolExecutor::execute( auto &Action = Actions.front(); Tool.appendArgumentsAdjuster(Action.second); Tool.appendArgumentsAdjuster(ArgsAdjuster); - if (int Ret = Tool.run(Action.first.get())) + if (Tool.run(Action.first.get())) return make_string_error("Failed to run action."); return llvm::Error::success(); diff --git a/unittests/Tooling/ExecutionTest.cpp b/unittests/Tooling/ExecutionTest.cpp index da482b88f5..44e37b4009 100644 --- a/unittests/Tooling/ExecutionTest.cpp +++ b/unittests/Tooling/ExecutionTest.cpp @@ -183,10 +183,10 @@ TEST(CreateToolExecutorTest, CreateTestToolExecutor) { } TEST(StandaloneToolTest, SynctaxOnlyActionOnSimpleCode) { - FixedCompilationDatabase Compilations("/", std::vector()); + FixedCompilationDatabase Compilations(".", std::vector()); StandaloneToolExecutor Executor(Compilations, - std::vector(1, "/a.cc")); - Executor.mapVirtualFile("/a.cc", "int x = 0;"); + std::vector(1, "a.cc")); + Executor.mapVirtualFile("a.cc", "int x = 0;"); auto Err = Executor.execute(newFrontendActionFactory(), getClangSyntaxOnlyAdjuster()); @@ -194,10 +194,10 @@ TEST(StandaloneToolTest, SynctaxOnlyActionOnSimpleCode) { } TEST(StandaloneToolTest, SimpleAction) { - FixedCompilationDatabase Compilations("/", std::vector()); + FixedCompilationDatabase Compilations(".", std::vector()); StandaloneToolExecutor Executor(Compilations, - std::vector(1, "/a.cc")); - Executor.mapVirtualFile("/a.cc", "int x = 0;"); + std::vector(1, "a.cc")); + Executor.mapVirtualFile("a.cc", "int x = 0;"); auto Err = Executor.execute(std::unique_ptr( new ReportResultActionFactory(Executor.getExecutionContext()))); @@ -207,10 +207,10 @@ TEST(StandaloneToolTest, SimpleAction) { } TEST(StandaloneToolTest, SimpleActionWithResult) { - FixedCompilationDatabase Compilations("/", std::vector()); + FixedCompilationDatabase Compilations(".", std::vector()); StandaloneToolExecutor Executor(Compilations, - std::vector(1, "/a.cc")); - Executor.mapVirtualFile("/a.cc", "int x = 0; void f() {}"); + std::vector(1, "a.cc")); + Executor.mapVirtualFile("a.cc", "int x = 0; void f() {}"); auto Err = Executor.execute(std::unique_ptr( new ReportResultActionFactory(Executor.getExecutionContext()))); -- GitLab From 5f17d5ca46b48156b96f81e7c32d381a0ca65b41 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Thu, 26 Oct 2017 13:18:14 +0000 Subject: [PATCH 0086/1682] [Sema] -Wzero-as-null-pointer-constant: don't warn for system macros other than NULL. Summary: The warning was initially introduced in D32914 by @thakis, and the concerns were raised there, and later in rL302247 and PR33771. I do believe that it makes sense to relax the diagnostic e.g. in this case, when the expression originates from the system header, which can not be modified. This prevents adoption for the diagnostic for codebases which use pthreads (`PTHREAD_MUTEX_INITIALIZER`), gtest, etc. As @malcolm.parsons suggests, it *may* make sense to also not warn for the template types, but it is not obvious to me how to do that in here. Though, it still makes sense to complain about `NULL` macro. While there, add more tests. Reviewers: dblaikie, thakis, rsmith, rjmccall, aaron.ballman Reviewed By: thakis Subscribers: Rakete1111, hans, cfe-commits, thakis, malcolm.parsons Tags: #clang Differential Revision: https://reviews.llvm.org/D38954 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316662 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/ReleaseNotes.rst | 3 ++ lib/Sema/Sema.cpp | 16 ++++++- test/SemaCXX/Inputs/warn-zero-nullptr.h | 3 ++ test/SemaCXX/warn-zero-nullptr.cpp | 64 +++++++++++++++++++++++-- 4 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 test/SemaCXX/Inputs/warn-zero-nullptr.h diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst index 997c6d3fcd..30afc52ad2 100644 --- a/docs/ReleaseNotes.rst +++ b/docs/ReleaseNotes.rst @@ -91,6 +91,9 @@ Improvements to Clang's diagnostics offset is nonzero. It also now warns about arithmetic on a null pointer treated as a cast from integer to pointer (GNU extension). +- ``-Wzero-as-null-pointer-constant`` was adjusted not to warn on null pointer + constants that originate from system macros, except ``NULL`` macro. + Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index a9d6cb4c58..58bca42677 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -436,12 +436,24 @@ void Sema::diagnoseNullableToNonnullConversion(QualType DstType, } void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) { + if (Diags.isIgnored(diag::warn_zero_as_null_pointer_constant, + E->getLocStart())) + return; + // nullptr only exists from C++11 on, so don't warn on its absence earlier. + if (!getLangOpts().CPlusPlus11) + return; + if (Kind != CK_NullToPointer && Kind != CK_NullToMemberPointer) return; if (E->IgnoreParenImpCasts()->getType()->isNullPtrType()) return; - // nullptr only exists from C++11 on, so don't warn on its absence earlier. - if (!getLangOpts().CPlusPlus11) + + // If it is a macro from system header, and if the macro name is not "NULL", + // do not warn. + SourceLocation MaybeMacroLoc = E->getLocStart(); + if (Diags.getSuppressSystemWarnings() && + SourceMgr.isInSystemMacro(MaybeMacroLoc) && + !findMacroSpelling(MaybeMacroLoc, "NULL")) return; Diag(E->getLocStart(), diag::warn_zero_as_null_pointer_constant) diff --git a/test/SemaCXX/Inputs/warn-zero-nullptr.h b/test/SemaCXX/Inputs/warn-zero-nullptr.h new file mode 100644 index 0000000000..9b86c4b7b0 --- /dev/null +++ b/test/SemaCXX/Inputs/warn-zero-nullptr.h @@ -0,0 +1,3 @@ +#define NULL (0) +#define SYSTEM_MACRO (0) +#define OTHER_SYSTEM_MACRO (NULL) diff --git a/test/SemaCXX/warn-zero-nullptr.cpp b/test/SemaCXX/warn-zero-nullptr.cpp index 72280405d7..45f05fa570 100644 --- a/test/SemaCXX/warn-zero-nullptr.cpp +++ b/test/SemaCXX/warn-zero-nullptr.cpp @@ -1,4 +1,10 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -Wzero-as-null-pointer-constant -std=c++11 +// RUN: %clang_cc1 -fsyntax-only -verify %s -isystem %S/Inputs -Wzero-as-null-pointer-constant -std=c++11 +// RUN: %clang_cc1 -fsyntax-only -verify %s -isystem %S/Inputs -DSYSTEM_WARNINGS -Wzero-as-null-pointer-constant -Wsystem-headers -std=c++11 + +#include + +#define MACRO (0) +#define MCRO(x) (x) struct S {}; @@ -15,8 +21,12 @@ void* p2 = __null; // expected-warning{{zero as null pointer constant}} void (*fp2)() = __null; // expected-warning{{zero as null pointer constant}} int (S::*mp2) = __null; // expected-warning{{zero as null pointer constant}} -void f0(void* v = 0); // expected-warning{{zero as null pointer constant}} -void f1(void* v); +void f0(void* v = MACRO); // expected-warning{{zero as null pointer constant}} +void f1(void* v = NULL); // expected-warning{{zero as null pointer constant}} +void f2(void* v = MCRO(0)); // expected-warning{{zero as null pointer constant}} +void f3(void* v = MCRO(NULL)); // expected-warning{{zero as null pointer constant}} +void f4(void* v = 0); // expected-warning{{zero as null pointer constant}} +void f5(void* v); void g() { f1(0); // expected-warning{{zero as null pointer constant}} @@ -32,3 +42,51 @@ struct A { operator int*() { return nullptr; } }; void func() { if (nullptr == A()) {} } void func2() { if ((nullptr) == A()) {} } } + +template void TmplFunc0(T var) {} +void Func0Test() { + TmplFunc0(0); + TmplFunc0(0); // expected-warning {{zero as null pointer constant}} + TmplFunc0(0); // expected-warning {{zero as null pointer constant}} +} + +// FIXME: this one probably should not warn. +template void TmplFunc1(int a, T default_value = 0) {} // expected-warning{{zero as null pointer constant}} expected-warning{{zero as null pointer constant}} +void FuncTest() { + TmplFunc1(0); + TmplFunc1(0); // expected-note {{in instantiation of default function argument expression for 'TmplFunc1' required here}} + TmplFunc1(0); // expected-note {{in instantiation of default function argument expression for 'TmplFunc1' required here}} +} + +template +class TemplateClass0 { + public: + explicit TemplateClass0(T var) {} +}; +void TemplateClass0Test() { + TemplateClass0 a(0); + TemplateClass0 b(0); // expected-warning {{zero as null pointer constant}} + TemplateClass0 c(0); // expected-warning {{zero as null pointer constant}} +} + +template +class TemplateClass1 { + public: +// FIXME: this one should *NOT* warn. + explicit TemplateClass1(int a, T default_value = 0) {} // expected-warning{{zero as null pointer constant}} expected-warning{{zero as null pointer constant}} +}; +void IgnoreSubstTemplateType1() { + TemplateClass1 a(1); + TemplateClass1 b(1); // expected-note {{in instantiation of default function argument expression for 'TemplateClass1' required here}} + TemplateClass1 c(1); // expected-note {{in instantiation of default function argument expression for 'TemplateClass1' required here}} +} + +#ifndef SYSTEM_WARNINGS +// Do not warn on *any* other macros from system headers, even if they +// expand to/their expansion contains NULL. +void* sys_init = SYSTEM_MACRO; +void* sys_init2 = OTHER_SYSTEM_MACRO; +#else +void* sys_init = SYSTEM_MACRO; // expected-warning {{zero as null pointer constant}} +void* sys_init2 = OTHER_SYSTEM_MACRO; // expected-warning {{zero as null pointer constant}} +#endif -- GitLab From c9d23a99f00d5e84f1e05d2903ef7538a4d4c33a Mon Sep 17 00:00:00 2001 From: Dave Lee Date: Thu, 26 Oct 2017 15:53:37 +0000 Subject: [PATCH 0087/1682] Add objcCategoryImplDecl matcher Summary: Add `objcCategoryImplDecl` which matches ObjC category definitions (`@implementation`). This matcher complements `objcCategoryDecl` (`@interface`) which was added in D30854. Reviewers: aaron.ballman, malcolm.parsons, alexshap Reviewed By: aaron.ballman Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D39293 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316670 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LibASTMatchersReference.html | 9 +++++++++ include/clang/ASTMatchers/ASTMatchers.h | 11 +++++++++++ lib/ASTMatchers/Dynamic/Registry.cpp | 1 + unittests/ASTMatchers/ASTMatchersNodeTest.cpp | 8 +++++++- 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html index b8d4ed557b..63ae085b0d 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -346,6 +346,15 @@ Example matches Foo (Additions) +Matcher<Decl>objcCategoryImplDeclMatcher<ObjCCategoryImplDecl>... +
Matches Objective-C category definitions.
+
+Example matches Foo (Additions)
+  @implementation Foo (Additions)
+  @end
+
+ + Matcher<Decl>objcImplementationDeclMatcher<ObjCImplementationDecl>...
Matches Objective-C implementation declarations.
 
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 2b03bb362b..766e95cdde 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -1178,6 +1178,17 @@ const internal::VariadicDynCastAllOfMatcher<
   Decl,
   ObjCCategoryDecl> objcCategoryDecl;
 
+/// \brief Matches Objective-C category definitions.
+///
+/// Example matches Foo (Additions)
+/// \code
+///   @implementation Foo (Additions)
+///   @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+  Decl,
+  ObjCCategoryImplDecl> objcCategoryImplDecl;
+
 /// \brief Matches Objective-C method declarations.
 ///
 /// Example matches both declaration and definition of -[Foo method]
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
index 83f2c0e33a..f68c3cc6fc 100644
--- a/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -375,6 +375,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(numSelectorArgs);
   REGISTER_MATCHER(ofClass);
   REGISTER_MATCHER(objcCategoryDecl);
+  REGISTER_MATCHER(objcCategoryImplDecl);
   REGISTER_MATCHER(objcImplementationDecl);
   REGISTER_MATCHER(objcInterfaceDecl);
   REGISTER_MATCHER(objcIvarDecl);
diff --git a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index beb6ed880a..a24d8d338e 100644
--- a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1590,7 +1590,7 @@ TEST(ObjCMessageExprMatcher, SimpleExprs) {
     )));
 }
 
-TEST(ObjCDeclMacher, CoreDecls) {
+TEST(ObjCDeclMatcher, CoreDecls) {
   std::string ObjCString =
     "@protocol Proto "
     "- (void)protoDidThing; "
@@ -1605,6 +1605,9 @@ TEST(ObjCDeclMacher, CoreDecls) {
     "{ id _ivar; } "
     "- (void)anything {} "
     "@end "
+    "@implementation Thing (ABC) "
+    "- (void)abc_doThing {} "
+    "@end "
     ;
 
   EXPECT_TRUE(matchesObjC(
@@ -1616,6 +1619,9 @@ TEST(ObjCDeclMacher, CoreDecls) {
   EXPECT_TRUE(matchesObjC(
     ObjCString,
     objcCategoryDecl(hasName("ABC"))));
+  EXPECT_TRUE(matchesObjC(
+    ObjCString,
+    objcCategoryImplDecl(hasName("ABC"))));
   EXPECT_TRUE(matchesObjC(
     ObjCString,
     objcMethodDecl(hasName("protoDidThing"))));
-- 
GitLab


From 2cb4a7c648adc733bfc6749a5a8a07efc6025d57 Mon Sep 17 00:00:00 2001
From: Reid Kleckner 
Date: Thu, 26 Oct 2017 17:07:48 +0000
Subject: [PATCH 0088/1682] Move MS inline asm parser methods out of line to
 reduce indentation, NFC

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316674 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Parse/ParseStmtAsm.cpp | 216 ++++++++++++++++++++-----------------
 1 file changed, 118 insertions(+), 98 deletions(-)

diff --git a/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp
index 3bd7fcc5e3..d81029e279 100644
--- a/lib/Parse/ParseStmtAsm.cpp
+++ b/lib/Parse/ParseStmtAsm.cpp
@@ -56,53 +56,11 @@ public:
 
   void LookupInlineAsmIdentifier(StringRef &LineBuf,
                                  llvm::InlineAsmIdentifierInfo &Info,
-                                 bool IsUnevaluatedContext) override {
-    // Collect the desired tokens.
-    SmallVector LineToks;
-    const Token *FirstOrigToken = nullptr;
-    findTokensForString(LineBuf, LineToks, FirstOrigToken);
-
-    unsigned NumConsumedToks;
-    ExprResult Result = TheParser.ParseMSAsmIdentifier(
-        LineToks, NumConsumedToks, IsUnevaluatedContext);
-
-    // If we consumed the entire line, tell MC that.
-    // Also do this if we consumed nothing as a way of reporting failure.
-    if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {
-      // By not modifying LineBuf, we're implicitly consuming it all.
-
-      // Otherwise, consume up to the original tokens.
-    } else {
-      assert(FirstOrigToken && "not using original tokens?");
-
-      // Since we're using original tokens, apply that offset.
-      assert(FirstOrigToken[NumConsumedToks].getLocation() ==
-             LineToks[NumConsumedToks].getLocation());
-      unsigned FirstIndex = FirstOrigToken - AsmToks.begin();
-      unsigned LastIndex = FirstIndex + NumConsumedToks - 1;
-
-      // The total length we've consumed is the relative offset
-      // of the last token we consumed plus its length.
-      unsigned TotalOffset =
-          (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() -
-           AsmTokOffsets[FirstIndex]);
-      LineBuf = LineBuf.substr(0, TotalOffset);
-    }
-
-    // Initialize Info with the lookup result.
-    if (!Result.isUsable())
-      return;
-    TheParser.getActions().FillInlineAsmIdentifierInfo(Result.get(), Info);
-  }
+                                 bool IsUnevaluatedContext) override;
 
   StringRef LookupInlineAsmLabel(StringRef Identifier, llvm::SourceMgr &LSM,
                                  llvm::SMLoc Location,
-                                 bool Create) override {
-    SourceLocation Loc = translateLocation(LSM, Location);
-    LabelDecl *Label =
-      TheParser.getActions().GetOrCreateMSAsmLabel(Identifier, Loc, Create);
-    return Label->getMSAsmLabel();
-  }
+                                 bool Create) override;
 
   bool LookupInlineAsmField(StringRef Base, StringRef Member,
                             unsigned &Offset) override {
@@ -117,65 +75,127 @@ public:
 private:
   /// Collect the appropriate tokens for the given string.
   void findTokensForString(StringRef Str, SmallVectorImpl &TempToks,
-                           const Token *&FirstOrigToken) const {
-    // For now, assert that the string we're working with is a substring
-    // of what we gave to MC.  This lets us use the original tokens.
-    assert(!std::less()(Str.begin(), AsmString.begin()) &&
-           !std::less()(AsmString.end(), Str.end()));
-
-    // Try to find a token whose offset matches the first token.
-    unsigned FirstCharOffset = Str.begin() - AsmString.begin();
-    const unsigned *FirstTokOffset = std::lower_bound(
-        AsmTokOffsets.begin(), AsmTokOffsets.end(), FirstCharOffset);
-
-    // For now, assert that the start of the string exactly
-    // corresponds to the start of a token.
-    assert(*FirstTokOffset == FirstCharOffset);
-
-    // Use all the original tokens for this line.  (We assume the
-    // end of the line corresponds cleanly to a token break.)
-    unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();
-    FirstOrigToken = &AsmToks[FirstTokIndex];
-    unsigned LastCharOffset = Str.end() - AsmString.begin();
-    for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) {
-      if (AsmTokOffsets[i] >= LastCharOffset)
-        break;
-      TempToks.push_back(AsmToks[i]);
-    }
+                           const Token *&FirstOrigToken) const;
+
+  SourceLocation translateLocation(const llvm::SourceMgr &LSM,
+                                   llvm::SMLoc SMLoc);
+
+  void handleDiagnostic(const llvm::SMDiagnostic &D);
+};
+}
+
+void ClangAsmParserCallback::LookupInlineAsmIdentifier(
+    StringRef &LineBuf, llvm::InlineAsmIdentifierInfo &Info,
+    bool IsUnevaluatedContext) {
+  // Collect the desired tokens.
+  SmallVector LineToks;
+  const Token *FirstOrigToken = nullptr;
+  findTokensForString(LineBuf, LineToks, FirstOrigToken);
+
+  unsigned NumConsumedToks;
+  ExprResult Result = TheParser.ParseMSAsmIdentifier(LineToks, NumConsumedToks,
+                                                     IsUnevaluatedContext);
+
+  // If we consumed the entire line, tell MC that.
+  // Also do this if we consumed nothing as a way of reporting failure.
+  if (NumConsumedToks == 0 || NumConsumedToks == LineToks.size()) {
+    // By not modifying LineBuf, we're implicitly consuming it all.
+
+    // Otherwise, consume up to the original tokens.
+  } else {
+    assert(FirstOrigToken && "not using original tokens?");
+
+    // Since we're using original tokens, apply that offset.
+    assert(FirstOrigToken[NumConsumedToks].getLocation() ==
+           LineToks[NumConsumedToks].getLocation());
+    unsigned FirstIndex = FirstOrigToken - AsmToks.begin();
+    unsigned LastIndex = FirstIndex + NumConsumedToks - 1;
+
+    // The total length we've consumed is the relative offset
+    // of the last token we consumed plus its length.
+    unsigned TotalOffset =
+        (AsmTokOffsets[LastIndex] + AsmToks[LastIndex].getLength() -
+         AsmTokOffsets[FirstIndex]);
+    LineBuf = LineBuf.substr(0, TotalOffset);
   }
 
-  SourceLocation translateLocation(const llvm::SourceMgr &LSM, llvm::SMLoc SMLoc) {
-    // Compute an offset into the inline asm buffer.
-    // FIXME: This isn't right if .macro is involved (but hopefully, no
-    // real-world code does that).
-    const llvm::MemoryBuffer *LBuf =
-        LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc));
-    unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart();
-
-    // Figure out which token that offset points into.
-    const unsigned *TokOffsetPtr =
-        std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset);
-    unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();
-    unsigned TokOffset = *TokOffsetPtr;
-
-    // If we come up with an answer which seems sane, use it; otherwise,
-    // just point at the __asm keyword.
-    // FIXME: Assert the answer is sane once we handle .macro correctly.
-    SourceLocation Loc = AsmLoc;
-    if (TokIndex < AsmToks.size()) {
-      const Token &Tok = AsmToks[TokIndex];
-      Loc = Tok.getLocation();
-      Loc = Loc.getLocWithOffset(Offset - TokOffset);
-    }
-    return Loc;
+  // Initialize Info with the lookup result.
+  if (!Result.isUsable())
+    return;
+  TheParser.getActions().FillInlineAsmIdentifierInfo(Result.get(), Info);
+}
+
+StringRef ClangAsmParserCallback::LookupInlineAsmLabel(StringRef Identifier,
+                                                       llvm::SourceMgr &LSM,
+                                                       llvm::SMLoc Location,
+                                                       bool Create) {
+  SourceLocation Loc = translateLocation(LSM, Location);
+  LabelDecl *Label =
+      TheParser.getActions().GetOrCreateMSAsmLabel(Identifier, Loc, Create);
+  return Label->getMSAsmLabel();
+}
+
+void ClangAsmParserCallback::findTokensForString(
+    StringRef Str, SmallVectorImpl &TempToks,
+    const Token *&FirstOrigToken) const {
+  // For now, assert that the string we're working with is a substring
+  // of what we gave to MC.  This lets us use the original tokens.
+  assert(!std::less()(Str.begin(), AsmString.begin()) &&
+         !std::less()(AsmString.end(), Str.end()));
+
+  // Try to find a token whose offset matches the first token.
+  unsigned FirstCharOffset = Str.begin() - AsmString.begin();
+  const unsigned *FirstTokOffset = std::lower_bound(
+      AsmTokOffsets.begin(), AsmTokOffsets.end(), FirstCharOffset);
+
+  // For now, assert that the start of the string exactly
+  // corresponds to the start of a token.
+  assert(*FirstTokOffset == FirstCharOffset);
+
+  // Use all the original tokens for this line.  (We assume the
+  // end of the line corresponds cleanly to a token break.)
+  unsigned FirstTokIndex = FirstTokOffset - AsmTokOffsets.begin();
+  FirstOrigToken = &AsmToks[FirstTokIndex];
+  unsigned LastCharOffset = Str.end() - AsmString.begin();
+  for (unsigned i = FirstTokIndex, e = AsmTokOffsets.size(); i != e; ++i) {
+    if (AsmTokOffsets[i] >= LastCharOffset)
+      break;
+    TempToks.push_back(AsmToks[i]);
   }
+}
 
-  void handleDiagnostic(const llvm::SMDiagnostic &D) {
-    const llvm::SourceMgr &LSM = *D.getSourceMgr();
-    SourceLocation Loc = translateLocation(LSM, D.getLoc());
-    TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
+SourceLocation
+ClangAsmParserCallback::translateLocation(const llvm::SourceMgr &LSM,
+                                          llvm::SMLoc SMLoc) {
+  // Compute an offset into the inline asm buffer.
+  // FIXME: This isn't right if .macro is involved (but hopefully, no
+  // real-world code does that).
+  const llvm::MemoryBuffer *LBuf =
+      LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(SMLoc));
+  unsigned Offset = SMLoc.getPointer() - LBuf->getBufferStart();
+
+  // Figure out which token that offset points into.
+  const unsigned *TokOffsetPtr =
+      std::lower_bound(AsmTokOffsets.begin(), AsmTokOffsets.end(), Offset);
+  unsigned TokIndex = TokOffsetPtr - AsmTokOffsets.begin();
+  unsigned TokOffset = *TokOffsetPtr;
+
+  // If we come up with an answer which seems sane, use it; otherwise,
+  // just point at the __asm keyword.
+  // FIXME: Assert the answer is sane once we handle .macro correctly.
+  SourceLocation Loc = AsmLoc;
+  if (TokIndex < AsmToks.size()) {
+    const Token &Tok = AsmToks[TokIndex];
+    Loc = Tok.getLocation();
+    Loc = Loc.getLocWithOffset(Offset - TokOffset);
   }
-};
+  return Loc;
+}
+
+void ClangAsmParserCallback::handleDiagnostic(const llvm::SMDiagnostic &D) {
+  const llvm::SourceMgr &LSM = *D.getSourceMgr();
+  SourceLocation Loc = translateLocation(LSM, D.getLoc());
+  TheParser.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage();
 }
 
 /// Parse an identifier in an MS-style inline assembly block.
-- 
GitLab


From 24608dda4d4170b6813211360e6f4253cb81d79f Mon Sep 17 00:00:00 2001
From: Craig Topper 
Date: Thu, 26 Oct 2017 17:54:22 +0000
Subject: [PATCH 0089/1682] [X86] Add a target attribute test for no-sse4.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316681 91177308-0d34-0410-b5e6-96231b3b80d8
---
 test/CodeGen/attr-target-x86.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/test/CodeGen/attr-target-x86.c b/test/CodeGen/attr-target-x86.c
index f2777679ae..a1cb4518dc 100644
--- a/test/CodeGen/attr-target-x86.c
+++ b/test/CodeGen/attr-target-x86.c
@@ -10,6 +10,7 @@ int __attribute__((target("fpmath=387"))) koala(int a) { return 4; }
 int __attribute__((target("no-sse2"))) echidna(int a) { return 4; }
 
 int __attribute__((target("sse4"))) panda(int a) { return 4; }
+int __attribute__((target("no-sse4"))) narwhal(int a) { return 4; }
 
 int bar(int a) { return baz(a) + foo(a); }
 
@@ -29,15 +30,17 @@ int __attribute__((target("arch=lakemont"))) lake(int a) { return 4; }
 // CHECK: koala{{.*}} #0
 // CHECK: echidna{{.*}} #2
 // CHECK: panda{{.*}} #3
+// CHECK: narwhal{{.*}} #4
 // CHECK: bar{{.*}} #0
 // CHECK: qux{{.*}} #1
-// CHECK: qax{{.*}} #4
-// CHECK: qq{{.*}} #5
-// CHECK: lake{{.*}} #6
+// CHECK: qax{{.*}} #5
+// CHECK: qq{{.*}} #6
+// CHECK: lake{{.*}} #7
 // CHECK: #0 = {{.*}}"target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87"
 // CHECK: #1 = {{.*}}"target-cpu"="ivybridge" "target-features"="+aes,+avx,+cx16,+f16c,+fsgsbase,+fxsr,+mmx,+pclmul,+popcnt,+rdrnd,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"
 // CHECK: #2 = {{.*}}"target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+x87,-aes,-avx,-avx2,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512ifma,-avx512pf,-avx512vbmi,-avx512vl,-avx512vpopcntdq,-f16c,-fma,-fma4,-pclmul,-sha,-sse2,-sse3,-sse4.1,-sse4.2,-sse4a,-ssse3,-xop,-xsave,-xsaveopt"
 // CHECK: #3 = {{.*}}"target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"
-// CHECK: #4 = {{.*}}"target-cpu"="ivybridge" "target-features"="+avx,+cx16,+f16c,+fsgsbase,+fxsr,+mmx,+pclmul,+popcnt,+rdrnd,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt,-aes"
-// CHECK: #5 = {{.*}}"target-cpu"="x86-64" "target-features"="+fxsr,+sse,+sse2,+x87,-3dnow,-3dnowa,-mmx"
-// CHECK: #6 = {{.*}}"target-cpu"="lakemont" "target-features"="+mmx,+sse,+sse2"
+// CHECK: #4 = {{.*}}"target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87,-avx,-avx2,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512ifma,-avx512pf,-avx512vbmi,-avx512vl,-avx512vpopcntdq,-f16c,-fma,-fma4,-sse4.1,-sse4.2,-xop,-xsave,-xsaveopt"
+// CHECK: #5 = {{.*}}"target-cpu"="ivybridge" "target-features"="+avx,+cx16,+f16c,+fsgsbase,+fxsr,+mmx,+pclmul,+popcnt,+rdrnd,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt,-aes"
+// CHECK: #6 = {{.*}}"target-cpu"="x86-64" "target-features"="+fxsr,+sse,+sse2,+x87,-3dnow,-3dnowa,-mmx"
+// CHECK: #7 = {{.*}}"target-cpu"="lakemont" "target-features"="+mmx,+sse,+sse2"
-- 
GitLab


From b62a18f137edb8c75a27ab36802a18744147c55e Mon Sep 17 00:00:00 2001
From: Adrian Prantl 
Date: Thu, 26 Oct 2017 18:16:05 +0000
Subject: [PATCH 0090/1682] Simplify codegen and debug info generation for
 block context parameters.

The exisiting code goes out of its way to put block parameters into an
alloca only at -O0, and then describes the funciton argument with a
dbg.declare, which is undocumented in the LLVM-CFE contract and does
not actually behave as intended after LLVM r642022.

This patch just generates the alloca unconditionally, the mem2reg pass
will eliminate it at -O1 and up anyway and points the dbg.declare to
the alloca as intended (which mem2reg will then correctly rewrite into
a dbg.value).

rdar://problem/35043980

Differential Revision: https://reviews.llvm.org/D39305

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316684 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/CodeGen/CGBlocks.cpp                      | 16 ++---
 lib/CodeGen/CGDebugInfo.cpp                   | 16 ++---
 lib/CodeGen/CGDebugInfo.h                     |  4 +-
 test/CodeGen/debug-info-block-vars.c          | 20 ++++++
 .../debug-info-block-captured-self.m          | 72 -------------------
 5 files changed, 34 insertions(+), 94 deletions(-)
 create mode 100644 test/CodeGen/debug-info-block-vars.c
 delete mode 100644 test/CodeGenObjC/debug-info-block-captured-self.m

diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 2915dabe54..e7743fa0c6 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -1294,19 +1294,19 @@ void CodeGenFunction::setBlockContextParameter(const ImplicitParamDecl *D,
   assert(BlockInfo && "not emitting prologue of block invocation function?!");
 
   llvm::Value *localAddr = nullptr;
-  if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
-    // Allocate a stack slot to let the debug info survive the RA.
-    Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr");
-    Builder.CreateStore(arg, alloc);
-    localAddr = Builder.CreateLoad(alloc);
-  }
+  // Allocate a stack slot like for any local variable to guarantee optimal
+  // debug info at -O0. The mem2reg pass will eliminate it when optimizing.
+  Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr");
+  Builder.CreateStore(arg, alloc);
+  localAddr = Builder.CreateLoad(alloc);
 
   if (CGDebugInfo *DI = getDebugInfo()) {
     if (CGM.getCodeGenOpts().getDebugInfo() >=
         codegenoptions::LimitedDebugInfo) {
       DI->setLocation(D->getLocation());
-      DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, arg, argNum,
-                                               localAddr, Builder);
+      DI->EmitDeclareOfBlockLiteralArgVariable(
+          *BlockInfo, D->getName(), argNum,
+          cast(alloc.getPointer()), Builder);
     }
   }
 
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index a73e4a98b3..3e4acd208f 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -3694,9 +3694,9 @@ bool operator<(const BlockLayoutChunk &l, const BlockLayoutChunk &r) {
 }
 
 void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
-                                                       llvm::Value *Arg,
+                                                       StringRef Name,
                                                        unsigned ArgNo,
-                                                       llvm::Value *LocalAddr,
+                                                       llvm::AllocaInst *Alloca,
                                                        CGBuilderTy &Builder) {
   assert(DebugKind >= codegenoptions::LimitedDebugInfo);
   ASTContext &C = CGM.getContext();
@@ -3828,19 +3828,11 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
 
   // Create the descriptor for the parameter.
   auto *debugVar = DBuilder.createParameterVariable(
-      scope, Arg->getName(), ArgNo, tunit, line, type,
+      scope, Name, ArgNo, tunit, line, type,
       CGM.getLangOpts().Optimize, flags);
 
-  if (LocalAddr) {
-    // Insert an llvm.dbg.value into the current block.
-    DBuilder.insertDbgValueIntrinsic(
-        LocalAddr, debugVar, DBuilder.createExpression(),
-        llvm::DebugLoc::get(line, column, scope, CurInlinedAt),
-        Builder.GetInsertBlock());
-  }
-
   // Insert an llvm.dbg.declare into the current block.
-  DBuilder.insertDeclare(Arg, debugVar, DBuilder.createExpression(),
+  DBuilder.insertDeclare(Alloca, debugVar, DBuilder.createExpression(),
                          llvm::DebugLoc::get(line, column, scope, CurInlinedAt),
                          Builder.GetInsertBlock());
 }
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 36de231f05..4f7b7f2a0d 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -398,8 +398,8 @@ public:
   /// Emit call to \c llvm.dbg.declare for the block-literal argument
   /// to a block invocation function.
   void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
-                                            llvm::Value *Arg, unsigned ArgNo,
-                                            llvm::Value *LocalAddr,
+                                            StringRef Name, unsigned ArgNo,
+                                            llvm::AllocaInst *LocalAddr,
                                             CGBuilderTy &Builder);
 
   /// Emit information about a global variable.
diff --git a/test/CodeGen/debug-info-block-vars.c b/test/CodeGen/debug-info-block-vars.c
new file mode 100644
index 0000000000..e0bb61e5e8
--- /dev/null
+++ b/test/CodeGen/debug-info-block-vars.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -x c -fblocks -debug-info-kind=standalone -emit-llvm -O0 \
+// RUN:   -triple x86_64-apple-darwin -o - %s | FileCheck %s
+// RUN: %clang_cc1 -x c -fblocks -debug-info-kind=standalone -emit-llvm -O1 \
+// RUN:   -triple x86_64-apple-darwin -o - %s \
+// RUN:   | FileCheck --check-prefix=CHECK-OPT %s
+
+// CHECK: define internal void @__f_block_invoke(i8* %.block_descriptor)
+// CHECK: %.block_descriptor.addr = alloca i8*, align 8
+// CHECK: %block.addr = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor* }>*, align 8
+// CHECK: store i8* %.block_descriptor, i8** %.block_descriptor.addr, align 8
+// CHECK: call void @llvm.dbg.declare(metadata i8** %.block_descriptor.addr,
+// CHECK-SAME:                        metadata !DIExpression())
+// CHECK-OPT-NOT: alloca
+// CHECK-OPT: call void @llvm.dbg.value(metadata i8* %.block_descriptor,
+// CHECK-OPT-SAME:                      metadata !DIExpression())
+void f() {
+  a(^{
+    b();
+  });
+}
diff --git a/test/CodeGenObjC/debug-info-block-captured-self.m b/test/CodeGenObjC/debug-info-block-captured-self.m
deleted file mode 100644
index 302a011342..0000000000
--- a/test/CodeGenObjC/debug-info-block-captured-self.m
+++ /dev/null
@@ -1,72 +0,0 @@
-// RUN: %clang_cc1 -fblocks -debug-info-kind=limited -emit-llvm -triple x86_64-apple-darwin -o - %s | FileCheck %s
-//
-// Test that debug location is generated for a captured "self" inside
-// a block.
-//
-// This test is split into two parts, this one for the frontend, and
-// then llvm/test/DebugInfo/debug-info-block-captured-self.ll to
-// ensure that DW_AT_location is generated for the captured self.
-@class T;
-@interface S
-@end
-@interface Mode
--(int) count;
-@end
-@interface Context
-@end
-@interface ViewController
-@property (nonatomic, readwrite, strong) Context *context;
-@end
-typedef enum {
-    Unknown = 0,
-} State;
-@interface Main : ViewController
-{
-    T * t1;
-    T * t2;
-}
-@property(readwrite, nonatomic) State state;
-@end
-@implementation Main
-- (id) initWithContext:(Context *) context
-{
-    t1 = [self.context withBlock:^(id obj){
-        id *mode1;
-	t2 = [mode1 withBlock:^(id object){
-	    Mode *mode2 = object;
-	    if ([mode2 count] != 0) {
-	      self.state = 0;
-	    }
-	  }];
-      }];
-}
-@end
-// The important part of this test is that there is a dbg.value
-// intrinsic associated with the implicit .block_descriptor argument
-// of the block. We also test that this value gets alloca'd, so the
-// register llocator won't accidentally kill it.
-
-// outer block:
-// CHECK: define internal void {{.*}}_block_invoke{{.*}}
-
-// inner block:
-// CHECK: define internal void {{.*}}_block_invoke{{.*}}
-// CHECK:        %[[MEM1:.*]] = alloca i8*, align 8
-// CHECK-NEXT:   %[[MEM2:.*]] = alloca i8*, align 8
-// CHECK-NEXT:   [[DBGADDR:%.*]] = alloca [[BLOCK_T:<{.*}>]]*, align 8
-// CHECK:        store i8* [[BLOCK_DESC:%.*]], i8** %[[MEM1]], align 8
-// CHECK:        %[[TMP0:.*]] = load i8*, i8** %[[MEM1]]
-// CHECK:        call void @llvm.dbg.value(metadata i8* %[[TMP0]], metadata ![[BDMD:[0-9]+]], metadata !{{.*}})
-// CHECK:        call void @llvm.dbg.declare(metadata i8* [[BLOCK_DESC]], metadata ![[BDMD:[0-9]+]], metadata !{{.*}})
-// CHECK:        store [[BLOCK_T]]* {{%.*}}, [[BLOCK_T]]** [[DBGADDR]], align 8
-// CHECK:        call void @llvm.dbg.declare(metadata [[BLOCK_T]]** [[DBGADDR]], metadata ![[SELF:.*]], metadata !{{.*}})
-// make sure we are still in the same function
-// CHECK: define {{.*}}__copy_helper_block_
-// Metadata
-// CHECK: ![[MAIN:.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Main"
-// CHECK-SAME:                            line: 23,
-// CHECK: ![[PMAIN:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[MAIN]],
-// CHECK: ![[BDMD]] = !DILocalVariable(name: ".block_descriptor", arg:
-// CHECK: ![[SELF]] = !DILocalVariable(name: "self"
-// CHECK-NOT:                          arg:
-// CHECK-SAME:                         line: 40,
-- 
GitLab


From 639ed1da2f19d52e75fda5011c548223095d0b68 Mon Sep 17 00:00:00 2001
From: Adrian Prantl 
Date: Thu, 26 Oct 2017 18:32:16 +0000
Subject: [PATCH 0091/1682] Revert "Simplify codegen and debug info generation
 for block context parameters."

This reverts commit r316684 while investigating buildbot breakage.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316686 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/CodeGen/CGBlocks.cpp                      | 16 ++---
 lib/CodeGen/CGDebugInfo.cpp                   | 16 +++--
 lib/CodeGen/CGDebugInfo.h                     |  4 +-
 test/CodeGen/debug-info-block-vars.c          | 20 ------
 .../debug-info-block-captured-self.m          | 72 +++++++++++++++++++
 5 files changed, 94 insertions(+), 34 deletions(-)
 delete mode 100644 test/CodeGen/debug-info-block-vars.c
 create mode 100644 test/CodeGenObjC/debug-info-block-captured-self.m

diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index e7743fa0c6..2915dabe54 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -1294,19 +1294,19 @@ void CodeGenFunction::setBlockContextParameter(const ImplicitParamDecl *D,
   assert(BlockInfo && "not emitting prologue of block invocation function?!");
 
   llvm::Value *localAddr = nullptr;
-  // Allocate a stack slot like for any local variable to guarantee optimal
-  // debug info at -O0. The mem2reg pass will eliminate it when optimizing.
-  Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr");
-  Builder.CreateStore(arg, alloc);
-  localAddr = Builder.CreateLoad(alloc);
+  if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
+    // Allocate a stack slot to let the debug info survive the RA.
+    Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr");
+    Builder.CreateStore(arg, alloc);
+    localAddr = Builder.CreateLoad(alloc);
+  }
 
   if (CGDebugInfo *DI = getDebugInfo()) {
     if (CGM.getCodeGenOpts().getDebugInfo() >=
         codegenoptions::LimitedDebugInfo) {
       DI->setLocation(D->getLocation());
-      DI->EmitDeclareOfBlockLiteralArgVariable(
-          *BlockInfo, D->getName(), argNum,
-          cast(alloc.getPointer()), Builder);
+      DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, arg, argNum,
+                                               localAddr, Builder);
     }
   }
 
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 3e4acd208f..a73e4a98b3 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -3694,9 +3694,9 @@ bool operator<(const BlockLayoutChunk &l, const BlockLayoutChunk &r) {
 }
 
 void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
-                                                       StringRef Name,
+                                                       llvm::Value *Arg,
                                                        unsigned ArgNo,
-                                                       llvm::AllocaInst *Alloca,
+                                                       llvm::Value *LocalAddr,
                                                        CGBuilderTy &Builder) {
   assert(DebugKind >= codegenoptions::LimitedDebugInfo);
   ASTContext &C = CGM.getContext();
@@ -3828,11 +3828,19 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
 
   // Create the descriptor for the parameter.
   auto *debugVar = DBuilder.createParameterVariable(
-      scope, Name, ArgNo, tunit, line, type,
+      scope, Arg->getName(), ArgNo, tunit, line, type,
       CGM.getLangOpts().Optimize, flags);
 
+  if (LocalAddr) {
+    // Insert an llvm.dbg.value into the current block.
+    DBuilder.insertDbgValueIntrinsic(
+        LocalAddr, debugVar, DBuilder.createExpression(),
+        llvm::DebugLoc::get(line, column, scope, CurInlinedAt),
+        Builder.GetInsertBlock());
+  }
+
   // Insert an llvm.dbg.declare into the current block.
-  DBuilder.insertDeclare(Alloca, debugVar, DBuilder.createExpression(),
+  DBuilder.insertDeclare(Arg, debugVar, DBuilder.createExpression(),
                          llvm::DebugLoc::get(line, column, scope, CurInlinedAt),
                          Builder.GetInsertBlock());
 }
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 4f7b7f2a0d..36de231f05 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -398,8 +398,8 @@ public:
   /// Emit call to \c llvm.dbg.declare for the block-literal argument
   /// to a block invocation function.
   void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
-                                            StringRef Name, unsigned ArgNo,
-                                            llvm::AllocaInst *LocalAddr,
+                                            llvm::Value *Arg, unsigned ArgNo,
+                                            llvm::Value *LocalAddr,
                                             CGBuilderTy &Builder);
 
   /// Emit information about a global variable.
diff --git a/test/CodeGen/debug-info-block-vars.c b/test/CodeGen/debug-info-block-vars.c
deleted file mode 100644
index e0bb61e5e8..0000000000
--- a/test/CodeGen/debug-info-block-vars.c
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clang_cc1 -x c -fblocks -debug-info-kind=standalone -emit-llvm -O0 \
-// RUN:   -triple x86_64-apple-darwin -o - %s | FileCheck %s
-// RUN: %clang_cc1 -x c -fblocks -debug-info-kind=standalone -emit-llvm -O1 \
-// RUN:   -triple x86_64-apple-darwin -o - %s \
-// RUN:   | FileCheck --check-prefix=CHECK-OPT %s
-
-// CHECK: define internal void @__f_block_invoke(i8* %.block_descriptor)
-// CHECK: %.block_descriptor.addr = alloca i8*, align 8
-// CHECK: %block.addr = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor* }>*, align 8
-// CHECK: store i8* %.block_descriptor, i8** %.block_descriptor.addr, align 8
-// CHECK: call void @llvm.dbg.declare(metadata i8** %.block_descriptor.addr,
-// CHECK-SAME:                        metadata !DIExpression())
-// CHECK-OPT-NOT: alloca
-// CHECK-OPT: call void @llvm.dbg.value(metadata i8* %.block_descriptor,
-// CHECK-OPT-SAME:                      metadata !DIExpression())
-void f() {
-  a(^{
-    b();
-  });
-}
diff --git a/test/CodeGenObjC/debug-info-block-captured-self.m b/test/CodeGenObjC/debug-info-block-captured-self.m
new file mode 100644
index 0000000000..302a011342
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-block-captured-self.m
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -fblocks -debug-info-kind=limited -emit-llvm -triple x86_64-apple-darwin -o - %s | FileCheck %s
+//
+// Test that debug location is generated for a captured "self" inside
+// a block.
+//
+// This test is split into two parts, this one for the frontend, and
+// then llvm/test/DebugInfo/debug-info-block-captured-self.ll to
+// ensure that DW_AT_location is generated for the captured self.
+@class T;
+@interface S
+@end
+@interface Mode
+-(int) count;
+@end
+@interface Context
+@end
+@interface ViewController
+@property (nonatomic, readwrite, strong) Context *context;
+@end
+typedef enum {
+    Unknown = 0,
+} State;
+@interface Main : ViewController
+{
+    T * t1;
+    T * t2;
+}
+@property(readwrite, nonatomic) State state;
+@end
+@implementation Main
+- (id) initWithContext:(Context *) context
+{
+    t1 = [self.context withBlock:^(id obj){
+        id *mode1;
+	t2 = [mode1 withBlock:^(id object){
+	    Mode *mode2 = object;
+	    if ([mode2 count] != 0) {
+	      self.state = 0;
+	    }
+	  }];
+      }];
+}
+@end
+// The important part of this test is that there is a dbg.value
+// intrinsic associated with the implicit .block_descriptor argument
+// of the block. We also test that this value gets alloca'd, so the
+// register llocator won't accidentally kill it.
+
+// outer block:
+// CHECK: define internal void {{.*}}_block_invoke{{.*}}
+
+// inner block:
+// CHECK: define internal void {{.*}}_block_invoke{{.*}}
+// CHECK:        %[[MEM1:.*]] = alloca i8*, align 8
+// CHECK-NEXT:   %[[MEM2:.*]] = alloca i8*, align 8
+// CHECK-NEXT:   [[DBGADDR:%.*]] = alloca [[BLOCK_T:<{.*}>]]*, align 8
+// CHECK:        store i8* [[BLOCK_DESC:%.*]], i8** %[[MEM1]], align 8
+// CHECK:        %[[TMP0:.*]] = load i8*, i8** %[[MEM1]]
+// CHECK:        call void @llvm.dbg.value(metadata i8* %[[TMP0]], metadata ![[BDMD:[0-9]+]], metadata !{{.*}})
+// CHECK:        call void @llvm.dbg.declare(metadata i8* [[BLOCK_DESC]], metadata ![[BDMD:[0-9]+]], metadata !{{.*}})
+// CHECK:        store [[BLOCK_T]]* {{%.*}}, [[BLOCK_T]]** [[DBGADDR]], align 8
+// CHECK:        call void @llvm.dbg.declare(metadata [[BLOCK_T]]** [[DBGADDR]], metadata ![[SELF:.*]], metadata !{{.*}})
+// make sure we are still in the same function
+// CHECK: define {{.*}}__copy_helper_block_
+// Metadata
+// CHECK: ![[MAIN:.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Main"
+// CHECK-SAME:                            line: 23,
+// CHECK: ![[PMAIN:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[MAIN]],
+// CHECK: ![[BDMD]] = !DILocalVariable(name: ".block_descriptor", arg:
+// CHECK: ![[SELF]] = !DILocalVariable(name: "self"
+// CHECK-NOT:                          arg:
+// CHECK-SAME:                         line: 40,
-- 
GitLab


From bce8668f19401f4fc021a74f3fe323574476ed28 Mon Sep 17 00:00:00 2001
From: George Karpenkov 
Date: Thu, 26 Oct 2017 19:00:22 +0000
Subject: [PATCH 0092/1682] [Analyzer] [Tests] Write analyzers crashes to
 stdout, and not to a separate file

With this change it would be sufficient to look at CI console to see the
failure.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316687 91177308-0d34-0410-b5e6-96231b3b80d8
---
 utils/analyzer/SATestBuild.py | 32 ++++++++++++--------------------
 1 file changed, 12 insertions(+), 20 deletions(-)

diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py
index 74a5f6ebda..6f4ef2824b 100755
--- a/utils/analyzer/SATestBuild.py
+++ b/utils/analyzer/SATestBuild.py
@@ -450,29 +450,21 @@ def checkBuild(SBOutputDir):
             len(Plists)
         return
 
-    # Create summary file to display when the build fails.
-    SummaryPath = os.path.join(
-        SBOutputDir, LogFolderName, FailuresSummaryFileName)
-    if (Verbose > 0):
-        print "  Creating the failures summary file %s" % (SummaryPath,)
-
-    with open(SummaryPath, "w+") as SummaryLog:
-        SummaryLog.write("Total of %d failures discovered.\n" % (TotalFailed,))
-        if TotalFailed > NumOfFailuresInSummary:
-            SummaryLog.write("See the first %d below.\n" % (
-                NumOfFailuresInSummary,))
+    print "Error: analysis failed."
+    print "Total of %d failures discovered." % TotalFailed
+    if TotalFailed > NumOfFailuresInSummary:
+        print "See the first %d below.\n" % NumOfFailuresInSummary
         # TODO: Add a line "See the results folder for more."
 
-        Idx = 0
-        for FailLogPathI in Failures:
-            if Idx >= NumOfFailuresInSummary:
-                break
-            Idx += 1
-            SummaryLog.write("\n-- Error #%d -----------\n" % (Idx,))
-            with open(FailLogPathI, "r") as FailLogI:
-                shutil.copyfileobj(FailLogI, SummaryLog)
+    Idx = 0
+    for FailLogPathI in Failures:
+        if Idx >= NumOfFailuresInSummary:
+            break
+        Idx += 1
+        print "\n-- Error #%d -----------\n" % Idx
+        with open(FailLogPathI, "r") as FailLogI:
+            shutil.copyfileobj(FailLogI, sys.stdout)
 
-    print "Error: analysis failed. See ", SummaryPath
     sys.exit(1)
 
 
-- 
GitLab


From 6a6960cec6506142369c1d1e0359703afe5a1117 Mon Sep 17 00:00:00 2001
From: Adrian Prantl 
Date: Thu, 26 Oct 2017 20:08:52 +0000
Subject: [PATCH 0093/1682] Simplify codegen and debug info generation for
 block context parameters.

The exisiting code goes out of its way to put block parameters into an
alloca only at -O0, and then describes the funciton argument with a
dbg.declare, which is undocumented in the LLVM-CFE contract and does
not actually behave as intended after LLVM r642022.

This patch just generates the alloca unconditionally, the mem2reg pass
will eliminate it at -O1 and up anyway and points the dbg.declare to
the alloca as intended (which mem2reg will then correctly rewrite into
a dbg.value).

This reapplies r316684 with some dead code removed.

rdar://problem/35043980

Differential Revision: https://reviews.llvm.org/D39305

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316689 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/CodeGen/CGBlocks.cpp                      | 17 ++---
 lib/CodeGen/CGDebugInfo.cpp                   | 16 ++---
 lib/CodeGen/CGDebugInfo.h                     |  4 +-
 test/CodeGen/debug-info-block-vars.c          | 20 ++++++
 .../debug-info-block-captured-self.m          | 72 -------------------
 5 files changed, 33 insertions(+), 96 deletions(-)
 create mode 100644 test/CodeGen/debug-info-block-vars.c
 delete mode 100644 test/CodeGenObjC/debug-info-block-captured-self.m

diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 2915dabe54..0bd9d7c506 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -1293,20 +1293,17 @@ void CodeGenFunction::setBlockContextParameter(const ImplicitParamDecl *D,
                                                llvm::Value *arg) {
   assert(BlockInfo && "not emitting prologue of block invocation function?!");
 
-  llvm::Value *localAddr = nullptr;
-  if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
-    // Allocate a stack slot to let the debug info survive the RA.
-    Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr");
-    Builder.CreateStore(arg, alloc);
-    localAddr = Builder.CreateLoad(alloc);
-  }
-
+  // Allocate a stack slot like for any local variable to guarantee optimal
+  // debug info at -O0. The mem2reg pass will eliminate it when optimizing.
+  Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr");
+  Builder.CreateStore(arg, alloc);
   if (CGDebugInfo *DI = getDebugInfo()) {
     if (CGM.getCodeGenOpts().getDebugInfo() >=
         codegenoptions::LimitedDebugInfo) {
       DI->setLocation(D->getLocation());
-      DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, arg, argNum,
-                                               localAddr, Builder);
+      DI->EmitDeclareOfBlockLiteralArgVariable(
+          *BlockInfo, D->getName(), argNum,
+          cast(alloc.getPointer()), Builder);
     }
   }
 
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index a73e4a98b3..3e4acd208f 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -3694,9 +3694,9 @@ bool operator<(const BlockLayoutChunk &l, const BlockLayoutChunk &r) {
 }
 
 void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
-                                                       llvm::Value *Arg,
+                                                       StringRef Name,
                                                        unsigned ArgNo,
-                                                       llvm::Value *LocalAddr,
+                                                       llvm::AllocaInst *Alloca,
                                                        CGBuilderTy &Builder) {
   assert(DebugKind >= codegenoptions::LimitedDebugInfo);
   ASTContext &C = CGM.getContext();
@@ -3828,19 +3828,11 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
 
   // Create the descriptor for the parameter.
   auto *debugVar = DBuilder.createParameterVariable(
-      scope, Arg->getName(), ArgNo, tunit, line, type,
+      scope, Name, ArgNo, tunit, line, type,
       CGM.getLangOpts().Optimize, flags);
 
-  if (LocalAddr) {
-    // Insert an llvm.dbg.value into the current block.
-    DBuilder.insertDbgValueIntrinsic(
-        LocalAddr, debugVar, DBuilder.createExpression(),
-        llvm::DebugLoc::get(line, column, scope, CurInlinedAt),
-        Builder.GetInsertBlock());
-  }
-
   // Insert an llvm.dbg.declare into the current block.
-  DBuilder.insertDeclare(Arg, debugVar, DBuilder.createExpression(),
+  DBuilder.insertDeclare(Alloca, debugVar, DBuilder.createExpression(),
                          llvm::DebugLoc::get(line, column, scope, CurInlinedAt),
                          Builder.GetInsertBlock());
 }
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 36de231f05..4f7b7f2a0d 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -398,8 +398,8 @@ public:
   /// Emit call to \c llvm.dbg.declare for the block-literal argument
   /// to a block invocation function.
   void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
-                                            llvm::Value *Arg, unsigned ArgNo,
-                                            llvm::Value *LocalAddr,
+                                            StringRef Name, unsigned ArgNo,
+                                            llvm::AllocaInst *LocalAddr,
                                             CGBuilderTy &Builder);
 
   /// Emit information about a global variable.
diff --git a/test/CodeGen/debug-info-block-vars.c b/test/CodeGen/debug-info-block-vars.c
new file mode 100644
index 0000000000..e0bb61e5e8
--- /dev/null
+++ b/test/CodeGen/debug-info-block-vars.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -x c -fblocks -debug-info-kind=standalone -emit-llvm -O0 \
+// RUN:   -triple x86_64-apple-darwin -o - %s | FileCheck %s
+// RUN: %clang_cc1 -x c -fblocks -debug-info-kind=standalone -emit-llvm -O1 \
+// RUN:   -triple x86_64-apple-darwin -o - %s \
+// RUN:   | FileCheck --check-prefix=CHECK-OPT %s
+
+// CHECK: define internal void @__f_block_invoke(i8* %.block_descriptor)
+// CHECK: %.block_descriptor.addr = alloca i8*, align 8
+// CHECK: %block.addr = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor* }>*, align 8
+// CHECK: store i8* %.block_descriptor, i8** %.block_descriptor.addr, align 8
+// CHECK: call void @llvm.dbg.declare(metadata i8** %.block_descriptor.addr,
+// CHECK-SAME:                        metadata !DIExpression())
+// CHECK-OPT-NOT: alloca
+// CHECK-OPT: call void @llvm.dbg.value(metadata i8* %.block_descriptor,
+// CHECK-OPT-SAME:                      metadata !DIExpression())
+void f() {
+  a(^{
+    b();
+  });
+}
diff --git a/test/CodeGenObjC/debug-info-block-captured-self.m b/test/CodeGenObjC/debug-info-block-captured-self.m
deleted file mode 100644
index 302a011342..0000000000
--- a/test/CodeGenObjC/debug-info-block-captured-self.m
+++ /dev/null
@@ -1,72 +0,0 @@
-// RUN: %clang_cc1 -fblocks -debug-info-kind=limited -emit-llvm -triple x86_64-apple-darwin -o - %s | FileCheck %s
-//
-// Test that debug location is generated for a captured "self" inside
-// a block.
-//
-// This test is split into two parts, this one for the frontend, and
-// then llvm/test/DebugInfo/debug-info-block-captured-self.ll to
-// ensure that DW_AT_location is generated for the captured self.
-@class T;
-@interface S
-@end
-@interface Mode
--(int) count;
-@end
-@interface Context
-@end
-@interface ViewController
-@property (nonatomic, readwrite, strong) Context *context;
-@end
-typedef enum {
-    Unknown = 0,
-} State;
-@interface Main : ViewController
-{
-    T * t1;
-    T * t2;
-}
-@property(readwrite, nonatomic) State state;
-@end
-@implementation Main
-- (id) initWithContext:(Context *) context
-{
-    t1 = [self.context withBlock:^(id obj){
-        id *mode1;
-	t2 = [mode1 withBlock:^(id object){
-	    Mode *mode2 = object;
-	    if ([mode2 count] != 0) {
-	      self.state = 0;
-	    }
-	  }];
-      }];
-}
-@end
-// The important part of this test is that there is a dbg.value
-// intrinsic associated with the implicit .block_descriptor argument
-// of the block. We also test that this value gets alloca'd, so the
-// register llocator won't accidentally kill it.
-
-// outer block:
-// CHECK: define internal void {{.*}}_block_invoke{{.*}}
-
-// inner block:
-// CHECK: define internal void {{.*}}_block_invoke{{.*}}
-// CHECK:        %[[MEM1:.*]] = alloca i8*, align 8
-// CHECK-NEXT:   %[[MEM2:.*]] = alloca i8*, align 8
-// CHECK-NEXT:   [[DBGADDR:%.*]] = alloca [[BLOCK_T:<{.*}>]]*, align 8
-// CHECK:        store i8* [[BLOCK_DESC:%.*]], i8** %[[MEM1]], align 8
-// CHECK:        %[[TMP0:.*]] = load i8*, i8** %[[MEM1]]
-// CHECK:        call void @llvm.dbg.value(metadata i8* %[[TMP0]], metadata ![[BDMD:[0-9]+]], metadata !{{.*}})
-// CHECK:        call void @llvm.dbg.declare(metadata i8* [[BLOCK_DESC]], metadata ![[BDMD:[0-9]+]], metadata !{{.*}})
-// CHECK:        store [[BLOCK_T]]* {{%.*}}, [[BLOCK_T]]** [[DBGADDR]], align 8
-// CHECK:        call void @llvm.dbg.declare(metadata [[BLOCK_T]]** [[DBGADDR]], metadata ![[SELF:.*]], metadata !{{.*}})
-// make sure we are still in the same function
-// CHECK: define {{.*}}__copy_helper_block_
-// Metadata
-// CHECK: ![[MAIN:.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Main"
-// CHECK-SAME:                            line: 23,
-// CHECK: ![[PMAIN:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[MAIN]],
-// CHECK: ![[BDMD]] = !DILocalVariable(name: ".block_descriptor", arg:
-// CHECK: ![[SELF]] = !DILocalVariable(name: "self"
-// CHECK-NOT:                          arg:
-// CHECK-SAME:                         line: 40,
-- 
GitLab


From 38a85bd42aec616f085aef2591cf0da895ab9082 Mon Sep 17 00:00:00 2001
From: Adrian Prantl 
Date: Thu, 26 Oct 2017 20:16:03 +0000
Subject: [PATCH 0094/1682] Fix C++ testcase I forgot to add to r316689.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316695 91177308-0d34-0410-b5e6-96231b3b80d8
---
 test/CodeGenCXX/blocks.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/test/CodeGenCXX/blocks.cpp b/test/CodeGenCXX/blocks.cpp
index 5b7c7e6e46..37219d3f7a 100644
--- a/test/CodeGenCXX/blocks.cpp
+++ b/test/CodeGenCXX/blocks.cpp
@@ -122,7 +122,6 @@ namespace test4 {
   // CHECK-LABEL: define internal void @___ZN5test44testEv_block_invoke
   // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1
   // CHECK-NEXT: store i8* [[BLOCKDESC:%.*]], i8** {{.*}}, align 8
-  // CHECK-NEXT: load i8*, i8**
   // CHECK-NEXT: bitcast i8* [[BLOCKDESC]] to <{ i8*, i32, i32, i8*, %struct.__block_descriptor* }>*
   // CHECK:      call void @_ZN5test41AC1Ev([[A]]* [[TMP]])
   // CHECK-NEXT: call void @_ZN5test43fooENS_1AE([[A]]* [[TMP]])
-- 
GitLab


From 28250cddcac412897f421b4b7069b663a102fd54 Mon Sep 17 00:00:00 2001
From: Richard Smith 
Date: Thu, 26 Oct 2017 21:06:52 +0000
Subject: [PATCH 0095/1682] [www] Regenerate diagnostics reference.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316701 91177308-0d34-0410-b5e6-96231b3b80d8
---
 docs/DiagnosticsReference.rst | 796 ++++++++++++++++++++++++++++------
 1 file changed, 668 insertions(+), 128 deletions(-)

diff --git a/docs/DiagnosticsReference.rst b/docs/DiagnosticsReference.rst
index d8c486fc3b..e2b0bd7dd5 100644
--- a/docs/DiagnosticsReference.rst
+++ b/docs/DiagnosticsReference.rst
@@ -244,6 +244,21 @@ This diagnostic is an error by default, but the flag ``-Wno-address-of-temporary
 ------------------
 This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
 
+-Waligned-allocation-unavailable
+--------------------------------
+This diagnostic is an error by default, but the flag ``-Wno-aligned-allocation-unavailable`` can be used to disable the error.
+
+**Diagnostic text:**
+
++--------------------------------------------------+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:error:`error:` |nbsp| :diagtext:`aligned` |nbsp| |+------------------------+| |nbsp| :diagtext:`function of type '`:placeholder:`B`:diagtext:`' is only available on` |nbsp| :placeholder:`C` |nbsp| :placeholder:`D` |nbsp| :diagtext:`or newer`|
+|                                                  ||:diagtext:`allocation`  ||                                                                                                                                                                    |
+|                                                  |+------------------------+|                                                                                                                                                                    |
+|                                                  ||:diagtext:`deallocation`||                                                                                                                                                                    |
+|                                                  |+------------------------+|                                                                                                                                                                    |
++--------------------------------------------------+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
 -Wall
 -----
 Some of the diagnostics controlled by this flag are enabled by default.
@@ -745,6 +760,11 @@ This diagnostic is enabled by default.
 +--------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
 
+-Wbinary-literal
+----------------
+Controls `-Wc++14-binary-literal`_, `-Wc++98-c++11-compat-binary-literal`_, `-Wgnu-binary-literal`_.
+
+
 -Wbind-to-temporary-copy
 ------------------------
 Also controls `-Wc++98-compat-bind-to-temporary-copy`_.
@@ -972,7 +992,7 @@ Synonym for `-Wc++11-narrowing`_.
 --------------
 Some of the diagnostics controlled by this flag are enabled by default.
 
-Also controls `-Wc++11-compat-deprecated-writable-strings`_, `-Wc++11-compat-reserved-user-defined-literal`_, `-Wc++11-narrowing`_, `-Wc++98-c++11-c++14-compat`_, `-Wc++98-c++11-compat`_.
+Also controls `-Wc++11-compat-deprecated-writable-strings`_, `-Wc++11-compat-reserved-user-defined-literal`_, `-Wc++11-narrowing`_, `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_, `-Wc++98-c++11-compat`_.
 
 **Diagnostic text:**
 
@@ -1038,7 +1058,9 @@ This diagnostic is enabled by default.
 
 -Wc++11-compat-pedantic
 -----------------------
-Controls `-Wc++98-c++11-c++14-compat-pedantic`_, `-Wc++98-c++11-compat-pedantic`_.
+Some of the diagnostics controlled by this flag are enabled by default.
+
+Controls `-Wc++11-compat`_, `-Wc++98-c++11-c++14-c++17-compat-pedantic`_, `-Wc++98-c++11-c++14-compat-pedantic`_, `-Wc++98-c++11-compat-pedantic`_.
 
 
 -Wc++11-compat-reserved-user-defined-literal
@@ -1288,12 +1310,12 @@ Some of the diagnostics controlled by this flag are enabled by default.
 
 -Wc++14-compat
 --------------
-Synonym for `-Wc++98-c++11-c++14-compat`_.
+Controls `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_.
 
 
 -Wc++14-compat-pedantic
 -----------------------
-Synonym for `-Wc++98-c++11-c++14-compat-pedantic`_.
+Controls `-Wc++14-compat`_, `-Wc++98-c++11-c++14-c++17-compat-pedantic`_, `-Wc++98-c++11-c++14-compat-pedantic`_.
 
 
 -Wc++14-extensions
@@ -1349,16 +1371,16 @@ Also controls `-Wc++14-binary-literal`_.
 +-------------------------------------------------------------------------------+
 
 
--Wc++1y-extensions
-------------------
-Synonym for `-Wc++14-extensions`_.
+-Wc++17-compat
+--------------
+Some of the diagnostics controlled by this flag are enabled by default.
 
+Controls `-Wc++17-compat-mangling`_, `-Wc++98-c++11-c++14-c++17-compat`_, `-Wdeprecated-increment-bool`_, `-Wdeprecated-register`_.
 
--Wc++1z-compat
---------------
-This diagnostic is enabled by default.
 
-Also controls `-Wdeprecated-increment-bool`_, `-Wdeprecated-register`_.
+-Wc++17-compat-mangling
+-----------------------
+This diagnostic is enabled by default.
 
 **Diagnostic text:**
 
@@ -1367,42 +1389,49 @@ Also controls `-Wdeprecated-increment-bool`_, `-Wdeprecated-register`_.
 +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
 
--Wc++1z-extensions
+-Wc++17-compat-pedantic
+-----------------------
+Some of the diagnostics controlled by this flag are enabled by default.
+
+Controls `-Wc++17-compat`_, `-Wc++98-c++11-c++14-c++17-compat-pedantic`_.
+
+
+-Wc++17-extensions
 ------------------
 Some of the diagnostics controlled by this flag are enabled by default.
 
 **Diagnostic text:**
 
 +------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`constexpr if is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`constexpr if is a C++17 extension`|
 +------------------------------------------------------------------------+
 
 +---------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`'constexpr' on lambda expressions is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`'constexpr' on lambda expressions is a C++17 extension`|
 +---------------------------------------------------------------------------------------------+
 
 +---------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`use of the` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`use of the` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute is a C++17 extension`|
 +---------------------------------------------------------------------------------------------------------------------------+
 
 +---------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`decomposition declarations are a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`decomposition declarations are a C++17 extension`|
 +---------------------------------------------------------------------------------------+
 
 +--------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`pack fold expression is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`pack fold expression is a C++17 extension`|
 +--------------------------------------------------------------------------------+
 
 +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`'begin' and 'end' returning different types (`:placeholder:`A` |nbsp| :diagtext:`and` |nbsp| :placeholder:`B`:diagtext:`) is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`'begin' and 'end' returning different types (`:placeholder:`A` |nbsp| :diagtext:`and` |nbsp| :placeholder:`B`:diagtext:`) is a C++17 extension`|
 +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
 +----------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`hexadecimal floating literals are a C++1z feature`|
+|:warning:`warning:` |nbsp| :diagtext:`hexadecimal floating literals are a C++17 feature`|
 +----------------------------------------------------------------------------------------+
 
 +----------------------------------------+--------------------+-------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`'`|+------------------+|:diagtext:`' initialization statements are a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`'`|+------------------+|:diagtext:`' initialization statements are a C++17 extension`|
 |                                        ||:diagtext:`if`    ||                                                             |
 |                                        |+------------------+|                                                             |
 |                                        ||:diagtext:`switch`||                                                             |
@@ -1410,68 +1439,145 @@ Some of the diagnostics controlled by this flag are enabled by default.
 +----------------------------------------+--------------------+-------------------------------------------------------------+
 
 +-----------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`inline variables are a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`inline variables are a C++17 extension`|
 +-----------------------------------------------------------------------------+
 
 +---------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`use of multiple declarators in a single using declaration is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`use of multiple declarators in a single using declaration is a C++17 extension`|
 +---------------------------------------------------------------------------------------------------------------------+
 
 +-------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`nested namespace definition is a C++1z extension; define each namespace separately`|
+|:warning:`warning:` |nbsp| :diagtext:`nested namespace definition is a C++17 extension; define each namespace separately`|
 +-------------------------------------------------------------------------------------------------------------------------+
 
++------------------------------------------------------------+---------------------------+-----------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`attributes on` |nbsp| |+-------------------------+| |nbsp| :diagtext:`declaration are a C++17 extension`|
+|                                                            ||:diagtext:`a namespace`  ||                                                     |
+|                                                            |+-------------------------+|                                                     |
+|                                                            ||:diagtext:`an enumerator`||                                                     |
+|                                                            |+-------------------------+|                                                     |
++------------------------------------------------------------+---------------------------+-----------------------------------------------------+
+
 +---------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`capture of '\*this' by copy is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`capture of '\*this' by copy is a C++17 extension`|
 +---------------------------------------------------------------------------------------+
 
 +------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`static\_assert with no message is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`static\_assert with no message is a C++17 extension`|
 +------------------------------------------------------------------------------------------+
 
 +--------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`template template parameter using 'typename' is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`template template parameter using 'typename' is a C++17 extension`|
 +--------------------------------------------------------------------------------------------------------+
 
 +--------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`default scope specifier for attributes is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`default scope specifier for attributes is a C++17 extension`|
 +--------------------------------------------------------------------------------------------------+
 
 +-----------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`pack expansion of using declaration is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`pack expansion of using declaration is a C++17 extension`|
 +-----------------------------------------------------------------------------------------------+
 
 
+-Wc++1y-extensions
+------------------
+Synonym for `-Wc++14-extensions`_.
+
+
+-Wc++1z-compat
+--------------
+Synonym for `-Wc++17-compat`_.
+
+
+-Wc++1z-compat-mangling
+-----------------------
+Synonym for `-Wc++17-compat-mangling`_.
+
+
+-Wc++1z-extensions
+------------------
+Synonym for `-Wc++17-extensions`_.
+
+
+-Wc++2a-compat
+--------------
+**Diagnostic text:**
+
++-------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' is a keyword in C++2a`|
++-------------------------------------------------------------------------------------------+
+
+
+-Wc++2a-compat-pedantic
+-----------------------
+Synonym for `-Wc++2a-compat`_.
+
+
+-Wc++2a-extensions
+------------------
+Some of the diagnostics controlled by this flag are enabled by default.
+
+**Diagnostic text:**
+
++----------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`default member initializer for bit-field is a C++2a extension`|
++----------------------------------------------------------------------------------------------------+
+
++--------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`explicit capture of 'this' with a capture default of '=' is a C++2a extension`|
++--------------------------------------------------------------------------------------------------------------------+
+
++--------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`invoking a pointer to a 'const &' member function on an rvalue is a C++2a extension`|
++--------------------------------------------------------------------------------------------------------------------------+
+
+
+-Wc++98-c++11-c++14-c++17-compat
+--------------------------------
+**Diagnostic text:**
+
++-------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`default member initializer for bit-field is incompatible with C++ standards before C++2a`|
++-------------------------------------------------------------------------------------------------------------------------------+
+
++-----------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`explicit capture of 'this' with a capture default of '=' is incompatible with C++ standards before C++2a`|
++-----------------------------------------------------------------------------------------------------------------------------------------------+
+
+
+-Wc++98-c++11-c++14-c++17-compat-pedantic
+-----------------------------------------
+Also controls `-Wc++98-c++11-c++14-c++17-compat`_.
+
+**Diagnostic text:**
+
++-----------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`invoking a pointer to a 'const &' member function on an rvalue is incompatible with C++ standards before C++2a`|
++-----------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
 -Wc++98-c++11-c++14-compat
 --------------------------
 **Diagnostic text:**
 
-+------------------------------------------------------------+---------------------------+--------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`attributes on` |nbsp| |+-------------------------+| |nbsp| :diagtext:`declaration are incompatible with C++ standards before C++1z`|
-|                                                            ||:diagtext:`a namespace`  ||                                                                                |
-|                                                            |+-------------------------+|                                                                                |
-|                                                            ||:diagtext:`an enumerator`||                                                                                |
-|                                                            |+-------------------------+|                                                                                |
-+------------------------------------------------------------+---------------------------+--------------------------------------------------------------------------------+
-
 +---------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`constexpr if is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`constexpr if is incompatible with C++ standards before C++17`|
 +---------------------------------------------------------------------------------------------------+
 
 +----------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`constexpr on lambda expressions is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`constexpr on lambda expressions is incompatible with C++ standards before C++17`|
 +----------------------------------------------------------------------------------------------------------------------+
 
 +------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`decomposition declarations are incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`decomposition declarations are incompatible with C++ standards before C++17`|
 +------------------------------------------------------------------------------------------------------------------+
 
 +-----------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`pack fold expression is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`pack fold expression is incompatible with C++ standards before C++17`|
 +-----------------------------------------------------------------------------------------------------------+
 
 +---------------------------+--------------------+----------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| |+------------------+| |nbsp| :diagtext:`initialization statements are incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| |+------------------+| |nbsp| :diagtext:`initialization statements are incompatible with C++ standards before C++17`|
 |                           ||:diagtext:`if`    ||                                                                                              |
 |                           |+------------------+|                                                                                              |
 |                           ||:diagtext:`switch`||                                                                                              |
@@ -1479,47 +1585,47 @@ Some of the diagnostics controlled by this flag are enabled by default.
 +---------------------------+--------------------+----------------------------------------------------------------------------------------------+
 
 +--------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`inline variables are incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`inline variables are incompatible with C++ standards before C++17`|
 +--------------------------------------------------------------------------------------------------------+
 
 +------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`nested namespace definition is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`nested namespace definition is incompatible with C++ standards before C++17`|
 +------------------------------------------------------------------------------------------------------------------+
 
 +-------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`by value capture of '\*this' is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`by value capture of '\*this' is incompatible with C++ standards before C++17`|
 +-------------------------------------------------------------------------------------------------------------------+
 
 +---------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`static\_assert with no message is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`static\_assert with no message is incompatible with C++ standards before C++17`|
 +---------------------------------------------------------------------------------------------------------------------+
 
 +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`non-type template parameters declared with` |nbsp| :placeholder:`A` |nbsp| :diagtext:`are incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`non-type template parameters declared with` |nbsp| :placeholder:`A` |nbsp| :diagtext:`are incompatible with C++ standards before C++17`|
 +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
 +-----------------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`template template parameter using 'typename' is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`template template parameter using 'typename' is incompatible with C++ standards before C++17`|
 +-----------------------------------------------------------------------------------------------------------------------------------+
 
 +--------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`unicode literals are incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`unicode literals are incompatible with C++ standards before C++17`|
 +--------------------------------------------------------------------------------------------------------+
 
 +-----------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`default scope specifier for attributes is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`default scope specifier for attributes is incompatible with C++ standards before C++17`|
 +-----------------------------------------------------------------------------------------------------------------------------+
 
 +------------------------------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`use of multiple declarators in a single using declaration is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`use of multiple declarators in a single using declaration is incompatible with C++ standards before C++17`|
 +------------------------------------------------------------------------------------------------------------------------------------------------+
 
 +-----------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`pack expansion using declaration is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`pack expansion using declaration is incompatible with C++ standards before C++17`|
 +-----------------------------------------------------------------------------------------------------------------------+
 
 +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`'begin' and 'end' returning different types (`:placeholder:`A` |nbsp| :diagtext:`and` |nbsp| :placeholder:`B`:diagtext:`) is incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`'begin' and 'end' returning different types (`:placeholder:`A` |nbsp| :diagtext:`and` |nbsp| :placeholder:`B`:diagtext:`) is incompatible with C++ standards before C++17`|
 +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
 
@@ -1529,8 +1635,16 @@ Also controls `-Wc++98-c++11-c++14-compat`_.
 
 **Diagnostic text:**
 
++------------------------------------------------------------+---------------------------+--------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`attributes on` |nbsp| |+-------------------------+| |nbsp| :diagtext:`declaration are incompatible with C++ standards before C++17`|
+|                                                            ||:diagtext:`a namespace`  ||                                                                                |
+|                                                            |+-------------------------+|                                                                                |
+|                                                            ||:diagtext:`an enumerator`||                                                                                |
+|                                                            |+-------------------------+|                                                                                |
++------------------------------------------------------------+---------------------------+--------------------------------------------------------------------------------+
+
 +---------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`hexadecimal floating literals are incompatible with C++ standards before C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`hexadecimal floating literals are incompatible with C++ standards before C++17`|
 +---------------------------------------------------------------------------------------------------------------------+
 
 
@@ -1587,10 +1701,8 @@ Also controls `-Wc++98-c++11-c++14-compat`_.
 +----------------------------------------------------------------------------------------------------------+
 
 
--Wc++98-c++11-compat-pedantic
------------------------------
-Also controls `-Wc++98-c++11-compat`_.
-
+-Wc++98-c++11-compat-binary-literal
+-----------------------------------
 **Diagnostic text:**
 
 +---------------------------------------------------------------------------------------------------------------+
@@ -1598,9 +1710,14 @@ Also controls `-Wc++98-c++11-compat`_.
 +---------------------------------------------------------------------------------------------------------------+
 
 
+-Wc++98-c++11-compat-pedantic
+-----------------------------
+Controls `-Wc++98-c++11-compat`_, `-Wc++98-c++11-compat-binary-literal`_.
+
+
 -Wc++98-compat
 --------------
-Also controls `-Wc++98-c++11-c++14-compat`_, `-Wc++98-c++11-compat`_, `-Wc++98-compat-local-type-template-args`_, `-Wc++98-compat-unnamed-type-template-args`_.
+Also controls `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_, `-Wc++98-c++11-compat`_, `-Wc++98-compat-local-type-template-args`_, `-Wc++98-compat-unnamed-type-template-args`_.
 
 **Diagnostic text:**
 
@@ -1941,7 +2058,7 @@ Also controls `-Wc++98-c++11-c++14-compat`_, `-Wc++98-c++11-compat`_, `-Wc++98-c
 
 -Wc++98-compat-pedantic
 -----------------------
-Also controls `-Wc++98-c++11-c++14-compat-pedantic`_, `-Wc++98-c++11-compat-pedantic`_, `-Wc++98-compat`_, `-Wc++98-compat-bind-to-temporary-copy`_.
+Also controls `-Wc++98-c++11-c++14-c++17-compat-pedantic`_, `-Wc++98-c++11-c++14-compat-pedantic`_, `-Wc++98-c++11-compat-pedantic`_, `-Wc++98-compat`_, `-Wc++98-compat-bind-to-temporary-copy`_.
 
 **Diagnostic text:**
 
@@ -2435,6 +2552,11 @@ Synonym for `-Wnull-conversion`_.
 
 -Wcoroutine
 -----------
+Synonym for `-Wcoroutine-missing-unhandled-exception`_.
+
+
+-Wcoroutine-missing-unhandled-exception
+---------------------------------------
 This diagnostic is enabled by default.
 
 **Diagnostic text:**
@@ -2453,6 +2575,11 @@ This diagnostic is enabled by default.
 +--------------------------------------------------------------------------------------------------+
 
 
+-Wcpp
+-----
+Synonym for `-W#warnings`_.
+
+
 -Wcstring-format-directive
 --------------------------
 **Diagnostic text:**
@@ -2716,6 +2843,10 @@ This diagnostic is enabled by default.
 
 **Diagnostic text:**
 
++--------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`specifying 'uuid' as an ATL attribute is deprecated; use \_\_declspec instead`|
++--------------------------------------------------------------------------------------------------------------------+
+
 +-----------------------------------------------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`use of C-style parameters in Objective-C method declarations is deprecated`|
 +-----------------------------------------------------------------------------------------------------------------+
@@ -2751,7 +2882,7 @@ This diagnostic is enabled by default.
 **Diagnostic text:**
 
 +----------------------------------------------------------------------+----------------------+
-|:warning:`warning:` |nbsp| :diagtext:`Implementing deprecated` |nbsp| |+--------------------+|
+|:warning:`warning:` |nbsp| :diagtext:`implementing deprecated` |nbsp| |+--------------------+|
 |                                                                      ||:diagtext:`method`  ||
 |                                                                      |+--------------------+|
 |                                                                      ||:diagtext:`class`   ||
@@ -2760,6 +2891,10 @@ This diagnostic is enabled by default.
 |                                                                      |+--------------------+|
 +----------------------------------------------------------------------+----------------------+
 
++----------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`implementing unavailable method`|
++----------------------------------------------------------------------+
+
 
 -Wdeprecated-increment-bool
 ---------------------------
@@ -2768,7 +2903,7 @@ This diagnostic is enabled by default.
 **Diagnostic text:**
 
 +---------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`incrementing expression of type bool is deprecated and incompatible with C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`incrementing expression of type bool is deprecated and incompatible with C++17`|
 +---------------------------------------------------------------------------------------------------------------------+
 
 
@@ -2818,7 +2953,7 @@ This diagnostic is enabled by default.
 **Diagnostic text:**
 
 +-------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`'register' storage class specifier is deprecated and incompatible with C++1z`|
+|:warning:`warning:` |nbsp| :diagtext:`'register' storage class specifier is deprecated and incompatible with C++17`|
 +-------------------------------------------------------------------------------------------------------------------+
 
 
@@ -3227,7 +3362,7 @@ Also controls `-Wdeprecated-dynamic-exception-spec`_.
 **Diagnostic text:**
 
 +--------------------------------------------------------------------------------------------+
-|:error:`error:` |nbsp| :diagtext:`ISO C++1z does not allow dynamic exception specifications`|
+|:error:`error:` |nbsp| :diagtext:`ISO C++17 does not allow dynamic exception specifications`|
 +--------------------------------------------------------------------------------------------+
 
 
@@ -3279,7 +3414,7 @@ This diagnostic is enabled by default.
 **Diagnostic text:**
 
 +-------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`ISO C++1z does not allow a decomposition group to be empty`|
+|:warning:`warning:` |nbsp| :diagtext:`ISO C++17 does not allow a decomposition group to be empty`|
 +-------------------------------------------------------------------------------------------------+
 
 
@@ -3312,6 +3447,8 @@ Synonym for `-Wextra-tokens`_.
 --------------
 This diagnostic is enabled by default.
 
+Also controls `-Wenum-compare-switch`_.
+
 **Diagnostic text:**
 
 +------------------------------------------------------------------------------------------------+
@@ -3319,6 +3456,17 @@ This diagnostic is enabled by default.
 +------------------------------------------------------------------------------------------------+
 
 
+-Wenum-compare-switch
+---------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++--------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`comparison of two values with different enumeration types in switch statement`|
++--------------------------------------------------------------------------------------------------------------------+
+
+
 -Wenum-conversion
 -----------------
 This diagnostic is enabled by default.
@@ -3363,6 +3511,10 @@ This diagnostic is enabled by default.
 |:warning:`warning:` |nbsp| :diagtext:`exception of type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`will be caught by earlier handler`|
 +-------------------------------------------------------------------------------------------------------------------------------------+
 
++-----------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`has a non-throwing exception specification but can still throw`|
++-----------------------------------------------------------------------------------------------------------------------------+
+
 
 -Wexit-time-destructors
 -----------------------
@@ -3451,7 +3603,7 @@ This diagnostic is enabled by default.
 -------
 Some of the diagnostics controlled by this flag are enabled by default.
 
-Also controls `-Wignored-qualifiers`_, `-Winitializer-overrides`_, `-Wmissing-field-initializers`_, `-Wmissing-method-return-type`_, `-Wsemicolon-before-method-body`_, `-Wsign-compare`_, `-Wunused-parameter`_.
+Also controls `-Wignored-qualifiers`_, `-Winitializer-overrides`_, `-Wmissing-field-initializers`_, `-Wmissing-method-return-type`_, `-Wnull-pointer-arithmetic`_, `-Wsemicolon-before-method-body`_, `-Wsign-compare`_, `-Wunused-parameter`_.
 
 **Diagnostic text:**
 
@@ -4317,6 +4469,10 @@ This diagnostic is enabled by default.
 |:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute ignored`|
 +--------------------------------------------------------------------------------+
 
++--------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute ignored for field of type` |nbsp| :placeholder:`B`|
++--------------------------------------------------------------------------------------------------------------------------+
+
 +---------------------------------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute ignored on inline function`|
 +---------------------------------------------------------------------------------------------------+
@@ -4453,6 +4609,8 @@ This diagnostic is enabled by default.
 |                                                                                                |+----------------------------------------------------------------------------------------------------------------+|
 |                                                                                                ||:diagtext:`methods and properties`                                                                              ||
 |                                                                                                |+----------------------------------------------------------------------------------------------------------------+|
+|                                                                                                ||:diagtext:`functions, methods, and properties`                                                                  ||
+|                                                                                                |+----------------------------------------------------------------------------------------------------------------+|
 |                                                                                                ||:diagtext:`struct or union`                                                                                     ||
 |                                                                                                |+----------------------------------------------------------------------------------------------------------------+|
 |                                                                                                ||:diagtext:`struct, union or class`                                                                              ||
@@ -4645,9 +4803,13 @@ This diagnostic is enabled by default.
 |:warning:`warning:` |nbsp| :diagtext:`\_\_declspec attribute` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is not supported`|
 +-------------------------------------------------------------------------------------------------------------------------+
 
-+-------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`Ignoring unsupported '`:placeholder:`A`:diagtext:`' in the target attribute string`|
-+-------------------------------------------------------------------------------------------------------------------------+
++-------------------------------------------------------+-------------------------+----------------------------------+---------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ignoring` |nbsp| |+-----------------------+|+--------------------------------+| |nbsp| :diagtext:`'`:placeholder:`C`:diagtext:`' in the target attribute string`|
+|                                                       ||:diagtext:`unsupported`|||                                ||                                                                                 |
+|                                                       |+-----------------------+|+--------------------------------+|                                                                                 |
+|                                                       ||:diagtext:`duplicate`  ||| |nbsp| :diagtext:`architecture`||                                                                                 |
+|                                                       |+-----------------------+|+--------------------------------+|                                                                                 |
++-------------------------------------------------------+-------------------------+----------------------------------+---------------------------------------------------------------------------------+
 
 
 -Wignored-optimization-argument
@@ -4970,9 +5132,13 @@ Some of the diagnostics controlled by this flag are enabled by default.
 
 **Diagnostic text:**
 
-+------------------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`implicit declaration of function` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is invalid in C99`|
-+------------------------------------------------------------------------------------------------------------------------------------+
++----------------------------------------------------------------------------------------------------------------------------------------+--------------------+
+|:warning:`warning:` |nbsp| :diagtext:`implicit declaration of function` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is invalid in` |nbsp| |+------------------+|
+|                                                                                                                                        ||:diagtext:`C99`   ||
+|                                                                                                                                        |+------------------+|
+|                                                                                                                                        ||:diagtext:`OpenCL`||
+|                                                                                                                                        |+------------------+|
++----------------------------------------------------------------------------------------------------------------------------------------+--------------------+
 
 +---------------------------------------------------------------------------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`implicitly declaring library function '`:placeholder:`A`:diagtext:`' with type` |nbsp| :placeholder:`B`|
@@ -5250,6 +5416,10 @@ This diagnostic is enabled by default.
 |:warning:`warning:` |nbsp| :diagtext:`missing submodule '`:placeholder:`A`:diagtext:`'`|
 +---------------------------------------------------------------------------------------+
 
++--------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`umbrella directory '`:placeholder:`A`:diagtext:`' not found`|
++--------------------------------------------------------------------------------------------------+
+
 +-------------------------------------------------------------------------------------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`umbrella header for module '`:placeholder:`A`:diagtext:`' does not include header '`:placeholder:`B`:diagtext:`'`|
 +-------------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -5299,7 +5469,7 @@ Also controls `-Wdeprecated-increment-bool`_.
 **Diagnostic text:**
 
 +------------------------------------------------------------------------------------------------+
-|:error:`error:` |nbsp| :diagtext:`ISO C++1z does not allow incrementing expression of type bool`|
+|:error:`error:` |nbsp| :diagtext:`ISO C++17 does not allow incrementing expression of type bool`|
 +------------------------------------------------------------------------------------------------+
 
 
@@ -5472,6 +5642,10 @@ Also controls `-Wignored-optimization-argument`_.
 
 **Diagnostic text:**
 
++-----------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`the object size sanitizer has no effect at -O0, but is explicitly enabled:` |nbsp| :placeholder:`A`|
++-----------------------------------------------------------------------------------------------------------------------------------------+
+
 +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`optimization level '`:placeholder:`A`:diagtext:`' is not supported; using '`:placeholder:`B`:placeholder:`C`:diagtext:`' instead`|
 +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -5522,6 +5696,17 @@ This diagnostic is enabled by default.
 +--------------------------------------------------------------------------------------------------------------+
 
 
+-Winvalid-ios-deployment-target
+-------------------------------
+This diagnostic is an error by default, but the flag ``-Wno-invalid-ios-deployment-target`` can be used to disable the error.
+
+**Diagnostic text:**
+
++------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:error:`error:` |nbsp| :diagtext:`invalid iOS deployment version '`:placeholder:`A`:diagtext:`', iOS 10 is the maximum deployment target for 32-bit targets`|
++------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
 -Winvalid-noreturn
 ------------------
 This diagnostic is enabled by default.
@@ -6013,6 +6198,8 @@ This diagnostic is enabled by default.
 
 -Wmicrosoft-enum-forward-reference
 ----------------------------------
+This diagnostic is enabled by default.
+
 **Diagnostic text:**
 
 +---------------------------------------------------------------------------------------------------+
@@ -6022,8 +6209,6 @@ This diagnostic is enabled by default.
 
 -Wmicrosoft-enum-value
 ----------------------
-This diagnostic is enabled by default.
-
 **Diagnostic text:**
 
 +---------------------------------------------------------------------------------------------------------------------------+
@@ -6433,6 +6618,17 @@ This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
 +--------------------------------------------------------------------------------------------+
 
 
+-Wmissing-noescape
+------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++----------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`parameter of overriding method should be annotated with \_\_attribute\_\_((noescape))`|
++----------------------------------------------------------------------------------------------------------------------------+
+
+
 -Wmissing-noreturn
 ------------------
 **Diagnostic text:**
@@ -6596,7 +6792,7 @@ This diagnostic is an error by default, but the flag ``-Wno-modules-import-neste
 ------
 Some of the diagnostics controlled by this flag are enabled by default.
 
-Controls `-Wcast-of-sel-type`_, `-Wchar-subscripts`_, `-Wcomment`_, `-Wdelete-non-virtual-dtor`_, `-Wextern-c-compat`_, `-Wfor-loop-analysis`_, `-Wformat`_, `-Wimplicit`_, `-Winfinite-recursion`_, `-Wmismatched-tags`_, `-Wmissing-braces`_, `-Wmove`_, `-Wmultichar`_, `-Wobjc-designated-initializers`_, `-Wobjc-missing-super-calls`_, `-Woverloaded-virtual`_, `-Wprivate-extern`_, `-Wreorder`_, `-Wreturn-type`_, `-Wself-assign`_, `-Wself-move`_, `-Wsizeof-array-argument`_, `-Wsizeof-array-decay`_, `-Wstring-plus-int`_, `-Wtrigraphs`_, `-Wuninitialized`_, `-Wunknown-pragmas`_, `-Wunused`_, `-Wuser-defined-warnings`_, `-Wvolatile-register-var`_.
+Controls `-Wcast-of-sel-type`_, `-Wchar-subscripts`_, `-Wcomment`_, `-Wdelete-non-virtual-dtor`_, `-Wextern-c-compat`_, `-Wfor-loop-analysis`_, `-Wformat`_, `-Wimplicit`_, `-Winfinite-recursion`_, `-Wmismatched-tags`_, `-Wmissing-braces`_, `-Wmove`_, `-Wmultichar`_, `-Wobjc-designated-initializers`_, `-Wobjc-flexible-array`_, `-Wobjc-missing-super-calls`_, `-Woverloaded-virtual`_, `-Wprivate-extern`_, `-Wreorder`_, `-Wreturn-type`_, `-Wself-assign`_, `-Wself-move`_, `-Wsizeof-array-argument`_, `-Wsizeof-array-decay`_, `-Wstring-plus-int`_, `-Wtrigraphs`_, `-Wuninitialized`_, `-Wunknown-pragmas`_, `-Wunused`_, `-Wuser-defined-warnings`_, `-Wvolatile-register-var`_.
 
 
 -Wmove
@@ -6692,6 +6888,11 @@ This diagnostic is enabled by default.
 +----------------------------------------------------------------+
 
 
+-Wnoexcept-type
+---------------
+Synonym for `-Wc++17-compat-mangling`_.
+
+
 -Wnon-gcc
 ---------
 Some of the diagnostics controlled by this flag are enabled by default.
@@ -6832,6 +7033,32 @@ This diagnostic is enabled by default.
 +---------------------------------------------------------------------------------------------------------------------+
 
 
+-Wnsconsumed-mismatch
+---------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++---------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`overriding method has mismatched ns\_consumed attribute on its parameter`|
++---------------------------------------------------------------------------------------------------------------+
+
+
+-Wnsreturns-mismatch
+--------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++-------------------------------------------------------------------------------------+---------------------------+------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`overriding method has mismatched ns\_returns\_`|+-------------------------+| |nbsp| :diagtext:`attributes`|
+|                                                                                     ||:diagtext:`not\_retained`||                              |
+|                                                                                     |+-------------------------+|                              |
+|                                                                                     ||:diagtext:`retained`     ||                              |
+|                                                                                     |+-------------------------+|                              |
++-------------------------------------------------------------------------------------+---------------------------+------------------------------+
+
+
 -Wnull-arithmetic
 -----------------
 This diagnostic is enabled by default.
@@ -6904,6 +7131,23 @@ This diagnostic is enabled by default.
 +---------------------------------------------------------------------------------------------------------+
 
 
+-Wnull-pointer-arithmetic
+-------------------------
+**Diagnostic text:**
+
++--------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`arithmetic on a null pointer treated as a cast from integer to pointer is a GNU extension`|
++--------------------------------------------------------------------------------------------------------------------------------+
+
++-------------------------------------------------------------------------------------------------------------+----------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`performing pointer arithmetic on a null pointer has undefined behavior`|+--------------------------------------------+|
+|                                                                                                             ||                                            ||
+|                                                                                                             |+--------------------------------------------+|
+|                                                                                                             || |nbsp| :diagtext:`if the offset is nonzero`||
+|                                                                                                             |+--------------------------------------------+|
++-------------------------------------------------------------------------------------------------------------+----------------------------------------------+
+
+
 -Wnullability
 -------------
 This diagnostic is enabled by default.
@@ -7077,6 +7321,21 @@ This diagnostic is enabled by default.
 +----------------------------------------------------------------------------------------------------------+
 
 
+-Wobjc-flexible-array
+---------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`field` |nbsp| :placeholder:`A` |nbsp| :diagtext:`can overwrite instance variable` |nbsp| :placeholder:`B` |nbsp| :diagtext:`with variable sized type` |nbsp| :placeholder:`C` |nbsp| :diagtext:`in superclass` |nbsp| :placeholder:`D`|
++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`field` |nbsp| :placeholder:`A` |nbsp| :diagtext:`with variable sized type` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is not visible to subclasses and can conflict with their instance variables`|
++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
 -Wobjc-forward-class-redefinition
 ---------------------------------
 This diagnostic is enabled by default.
@@ -7152,6 +7411,15 @@ This diagnostic is enabled by default.
 +-------------------------------------------------------------------------------------------+
 
 
+-Wobjc-messaging-id
+-------------------
+**Diagnostic text:**
+
++---------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`messaging unqualified id`|
++---------------------------------------------------------------+
+
+
 -Wobjc-method-access
 --------------------
 This diagnostic is enabled by default.
@@ -7515,10 +7783,26 @@ This diagnostic is enabled by default.
 
 **Diagnostic text:**
 
++------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`option '-ffine-grained-bitfield-accesses' cannot be enabled together with a sanitizer; flag ignored`|
++------------------------------------------------------------------------------------------------------------------------------------------+
+
 +----------------------------------------------------------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`option '`:placeholder:`A`:diagtext:`' was ignored by the PS4 toolchain, using '-fPIC'`|
 +----------------------------------------------------------------------------------------------------------------------------+
 
++-------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ignoring '-mabicalls' option as it cannot be used with non position-independent code and the N64 ABI`|
++-------------------------------------------------------------------------------------------------------------------------------------------+
+
++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------+----------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ignoring '-mlong-calls' option as it is not currently supported with` |nbsp| |+-----------------------------------------+|:diagtext:`-mabicalls`|
+|                                                                                                                   ||                                         ||                      |
+|                                                                                                                   |+-----------------------------------------+|                      |
+|                                                                                                                   ||:diagtext:`the implicit usage of` |nbsp| ||                      |
+|                                                                                                                   |+-----------------------------------------+|                      |
++-------------------------------------------------------------------------------------------------------------------+-------------------------------------------+----------------------+
+
 
 -Wout-of-line-declaration
 -------------------------
@@ -7531,6 +7815,21 @@ This diagnostic is an error by default, but the flag ``-Wno-out-of-line-declarat
 +-------------------------------------------------------------------------------------------+
 
 
+-Wout-of-scope-function
+-----------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++-------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`use of out-of-scope declaration of` |nbsp| :placeholder:`A`|+-------------------------------------------------------------------------------------+|
+|                                                                                                 ||                                                                                     ||
+|                                                                                                 |+-------------------------------------------------------------------------------------+|
+|                                                                                                 || |nbsp| :diagtext:`whose type is not compatible with that of an implicit declaration`||
+|                                                                                                 |+-------------------------------------------------------------------------------------+|
++-------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------+
+
+
 -Wover-aligned
 --------------
 **Diagnostic text:**
@@ -7776,7 +8075,7 @@ This diagnostic is enabled by default.
 
 -Wpedantic
 ----------
-Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-literal`_, `-Wc11-extensions`_, `-Wcomplex-component-init`_, `-Wdeclaration-after-statement`_, `-Wdollar-in-identifier-extension`_, `-Wembedded-directive`_, `-Wempty-translation-unit`_, `-Wextended-offsetof`_, `-Wflexible-array-extensions`_, `-Wformat-pedantic`_, `-Wfour-char-constants`_, `-Wgnu-anonymous-struct`_, `-Wgnu-auto-type`_, `-Wgnu-binary-literal`_, `-Wgnu-case-range`_, `-Wgnu-complex-integer`_, `-Wgnu-compound-literal-initializer`_, `-Wgnu-conditional-omitted-operand`_, `-Wgnu-empty-initializer`_, `-Wgnu-empty-struct`_, `-Wgnu-flexible-array-initializer`_, `-Wgnu-flexible-array-union-member`_, `-Wgnu-folding-constant`_, `-Wgnu-imaginary-constant`_, `-Wgnu-include-next`_, `-Wgnu-label-as-value`_, `-Wgnu-redeclared-enum`_, `-Wgnu-statement-expression`_, `-Wgnu-union-cast`_, `-Wgnu-zero-line-directive`_, `-Wgnu-zero-variadic-macro-arguments`_, `-Wimport-preprocessor-directive-pedantic`_, `-Wkeyword-macro`_, `-Wlanguage-extension-token`_, `-Wlong-long`_, `-Wmicrosoft-charize`_, `-Wmicrosoft-comment-paste`_, `-Wmicrosoft-cpp-macro`_, `-Wmicrosoft-end-of-file`_, `-Wmicrosoft-enum-forward-reference`_, `-Wmicrosoft-fixed-enum`_, `-Wmicrosoft-flexible-array`_, `-Wmicrosoft-redeclare-static`_, `-Wnested-anon-types`_, `-Wnullability-extension`_, `-Woverlength-strings`_, `-Wretained-language-linkage`_, `-Wvariadic-macros`_, `-Wvla-extension`_, `-Wzero-length-array`_.
+Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-literal`_, `-Wc11-extensions`_, `-Wcomplex-component-init`_, `-Wdeclaration-after-statement`_, `-Wdollar-in-identifier-extension`_, `-Wembedded-directive`_, `-Wempty-translation-unit`_, `-Wextended-offsetof`_, `-Wflexible-array-extensions`_, `-Wformat-pedantic`_, `-Wfour-char-constants`_, `-Wgnu-anonymous-struct`_, `-Wgnu-auto-type`_, `-Wgnu-binary-literal`_, `-Wgnu-case-range`_, `-Wgnu-complex-integer`_, `-Wgnu-compound-literal-initializer`_, `-Wgnu-conditional-omitted-operand`_, `-Wgnu-empty-initializer`_, `-Wgnu-empty-struct`_, `-Wgnu-flexible-array-initializer`_, `-Wgnu-flexible-array-union-member`_, `-Wgnu-folding-constant`_, `-Wgnu-imaginary-constant`_, `-Wgnu-include-next`_, `-Wgnu-label-as-value`_, `-Wgnu-redeclared-enum`_, `-Wgnu-statement-expression`_, `-Wgnu-union-cast`_, `-Wgnu-zero-line-directive`_, `-Wgnu-zero-variadic-macro-arguments`_, `-Wimport-preprocessor-directive-pedantic`_, `-Wkeyword-macro`_, `-Wlanguage-extension-token`_, `-Wlong-long`_, `-Wmicrosoft-charize`_, `-Wmicrosoft-comment-paste`_, `-Wmicrosoft-cpp-macro`_, `-Wmicrosoft-end-of-file`_, `-Wmicrosoft-enum-value`_, `-Wmicrosoft-fixed-enum`_, `-Wmicrosoft-flexible-array`_, `-Wmicrosoft-redeclare-static`_, `-Wnested-anon-types`_, `-Wnullability-extension`_, `-Woverlength-strings`_, `-Wretained-language-linkage`_, `-Wundefined-internal-type`_, `-Wvla-extension`_, `-Wzero-length-array`_.
 
 **Diagnostic text:**
 
@@ -7842,6 +8141,10 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter
 |:warning:`warning:` |nbsp| :diagtext:`parameter` |nbsp| :placeholder:`A` |nbsp| :diagtext:`was not declared, defaulting to type 'int'`|
 +--------------------------------------------------------------------------------------------------------------------------------------+
 
++--------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`invoking a pointer to a 'const &' member function on an rvalue is a C++2a extension`|
++--------------------------------------------------------------------------------------------------------------------------+
+
 +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`qualifier in explicit instantiation of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`requires a template-id (a typedef is not permitted)`|
 +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -7995,7 +8298,7 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter
 +---------------------------------------------------------------------------------------------------------------------------+
 
 +---------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`use of the` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute is a C++1z extension`|
+|:warning:`warning:` |nbsp| :diagtext:`use of the` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute is a C++17 extension`|
 +---------------------------------------------------------------------------------------------------------------------------+
 
 +-----------------------------------------------------------------------------+--------------------+---------------------------------------------+
@@ -8080,6 +8383,14 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter
 |:warning:`warning:` |nbsp| :diagtext:`exception specification of '...' is a Microsoft extension`|
 +------------------------------------------------------------------------------------------------+
 
++------------------------------------------------------------+---------------------------+-----------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`attributes on` |nbsp| |+-------------------------+| |nbsp| :diagtext:`declaration are a C++17 extension`|
+|                                                            ||:diagtext:`a namespace`  ||                                                     |
+|                                                            |+-------------------------+|                                                     |
+|                                                            ||:diagtext:`an enumerator`||                                                     |
+|                                                            |+-------------------------+|                                                     |
++------------------------------------------------------------+---------------------------+-----------------------------------------------------+
+
 +-----------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`extern templates are a C++11 extension`|
 +-----------------------------------------------------------------------------+
@@ -8105,7 +8416,7 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter
 +---------------------------------------------------------------------------------------+
 
 +----------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`hexadecimal floating literals are a C++1z feature`|
+|:warning:`warning:` |nbsp| :diagtext:`hexadecimal floating literals are a C++17 feature`|
 +----------------------------------------------------------------------------------------+
 
 +---------------------------------------------------------------------+
@@ -8124,6 +8435,14 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter
 |:warning:`warning:` |nbsp| :diagtext:`\_\_VA\_ARGS\_\_ can only appear in the expansion of a C99 variadic macro`|
 +----------------------------------------------------------------------------------------------------------------+
 
++------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`variadic macros are a C99 feature`|
++------------------------------------------------------------------------+
+
++--------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`named variadic macros are a GNU extension`|
++--------------------------------------------------------------------------------+
+
 +------------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`empty macro arguments are a C99 feature`|
 +------------------------------------------------------------------------------+
@@ -8288,6 +8607,17 @@ This diagnostic is enabled by default.
 +----------------------------------------------------------------------------------------------------------------------------------+
 
 
+-Wpragma-clang-attribute
+------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++-------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`unused attribute` |nbsp| :placeholder:`A` |nbsp| :diagtext:`in '#pragma clang attribute push' region`|
++-------------------------------------------------------------------------------------------------------------------------------------------+
+
+
 -Wpragma-once-outside-header
 ----------------------------
 This diagnostic is enabled by default.
@@ -8299,6 +8629,32 @@ This diagnostic is enabled by default.
 +----------------------------------------------------------------+
 
 
+-Wpragma-pack
+-------------
+Some of the diagnostics controlled by this flag are enabled by default.
+
+Also controls `-Wpragma-pack-suspicious-include`_.
+
+**Diagnostic text:**
+
++---------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`the current #pragma pack aligment value is modified in the included file`|
++---------------------------------------------------------------------------------------------------------------+
+
++---------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`unterminated '#pragma pack (push, ...)' at end of file`|
++---------------------------------------------------------------------------------------------+
+
+
+-Wpragma-pack-suspicious-include
+--------------------------------
+**Diagnostic text:**
+
++-------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`non-default #pragma pack value changes the alignment of struct or union members in the included file`|
++-------------------------------------------------------------------------------------------------------------------------------------------+
+
+
 -Wpragma-system-header-outside-header
 -------------------------------------
 This diagnostic is enabled by default.
@@ -8314,7 +8670,7 @@ This diagnostic is enabled by default.
 ---------
 Some of the diagnostics controlled by this flag are enabled by default.
 
-Also controls `-Wignored-pragmas`_, `-Wunknown-pragmas`_.
+Also controls `-Wignored-pragmas`_, `-Wpragma-clang-attribute`_, `-Wpragma-pack`_, `-Wunknown-pragmas`_.
 
 **Diagnostic text:**
 
@@ -8370,6 +8726,23 @@ This diagnostic is enabled by default.
 |:warning:`warning:` |nbsp| :diagtext:`top-level module '`:placeholder:`A`:diagtext:`' in private module map, expected a submodule of '`:placeholder:`B`:diagtext:`'`|
 +--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
++----------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`module '`:placeholder:`A`:diagtext:`' already re-exported as '`:placeholder:`B`:diagtext:`'`|
++----------------------------------------------------------------------------------------------------------------------------------+
+
+
+-Wprofile-instr-missing
+-----------------------
+**Diagnostic text:**
+
++-----------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+---------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`profile data may be incomplete: of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`function`|+-------------+|:diagtext:`,` |nbsp| :placeholder:`B` |nbsp| |+-----------------+| |nbsp| :diagtext:`no data`|
+|                                                                                                                             ||             ||                                             ||:diagtext:`:has` ||                           |
+|                                                                                                                             |+-------------+|                                             |+-----------------+|                           |
+|                                                                                                                             ||:diagtext:`s`||                                             ||:diagtext:`:have`||                           |
+|                                                                                                                             |+-------------+|                                             |+-----------------+|                           |
++-----------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+---------------------------+
+
 
 -Wprofile-instr-out-of-date
 ---------------------------
@@ -8377,13 +8750,13 @@ This diagnostic is enabled by default.
 
 **Diagnostic text:**
 
-+------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+---------------------------------------------------------------+-------------------+--------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`profile data may be out of date: of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`function`|+-------------+|:diagtext:`,` |nbsp| :placeholder:`B` |nbsp| |+-----------------+| |nbsp| :diagtext:`no data and` |nbsp| :placeholder:`C` |nbsp| |+-----------------+| |nbsp| :diagtext:`mismatched data that will be ignored`|
-|                                                                                                                              ||             ||                                             ||:diagtext:`:has` ||                                                               ||:diagtext:`:has` ||                                                        |
-|                                                                                                                              |+-------------+|                                             |+-----------------+|                                                               |+-----------------+|                                                        |
-|                                                                                                                              ||:diagtext:`s`||                                             ||:diagtext:`:have`||                                                               ||:diagtext:`:have`||                                                        |
-|                                                                                                                              |+-------------+|                                             |+-----------------+|                                                               |+-----------------+|                                                        |
-+------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+---------------------------------------------------------------+-------------------+--------------------------------------------------------+
++------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+--------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`profile data may be out of date: of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`function`|+-------------+|:diagtext:`,` |nbsp| :placeholder:`B` |nbsp| |+-----------------+| |nbsp| :diagtext:`mismatched data that will be ignored`|
+|                                                                                                                              ||             ||                                             ||:diagtext:`:has` ||                                                        |
+|                                                                                                                              |+-------------+|                                             |+-----------------+|                                                        |
+|                                                                                                                              ||:diagtext:`s`||                                             ||:diagtext:`:have`||                                                        |
+|                                                                                                                              |+-------------+|                                             |+-----------------+|                                                        |
++------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+--------------------------------------------------------+
 
 
 -Wprofile-instr-unprofiled
@@ -8448,9 +8821,29 @@ This diagnostic is enabled by default.
 
 **Diagnostic text:**
 
-+-----------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`property of type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`was selected for synthesis`|
-+-----------------------------------------------------------------------------------------------------------------------------+
++-------------------------------------------------------+----------------------------------------------------------------+----------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`property` |nbsp| |+--------------------------------------------------------------+| |nbsp| :diagtext:`was selected for synthesis`|
+|                                                       ||+-------------------------------------------+                 ||                                              |
+|                                                       |||:diagtext:`of type` |nbsp| :placeholder:`B`|                 ||                                              |
+|                                                       ||+-------------------------------------------+                 ||                                              |
+|                                                       |+--------------------------------------------------------------+|                                              |
+|                                                       ||+---------------------------------------------------------+   ||                                              |
+|                                                       |||:diagtext:`with attribute '`:placeholder:`B`:diagtext:`'`|   ||                                              |
+|                                                       ||+---------------------------------------------------------+   ||                                              |
+|                                                       |+--------------------------------------------------------------+|                                              |
+|                                                       ||+------------------------------------------------------------+||                                              |
+|                                                       |||:diagtext:`without attribute '`:placeholder:`B`:diagtext:`'`|||                                              |
+|                                                       ||+------------------------------------------------------------+||                                              |
+|                                                       |+--------------------------------------------------------------+|                                              |
+|                                                       ||+-----------------------------------------------+             ||                                              |
+|                                                       |||:diagtext:`with getter` |nbsp| :placeholder:`B`|             ||                                              |
+|                                                       ||+-----------------------------------------------+             ||                                              |
+|                                                       |+--------------------------------------------------------------+|                                              |
+|                                                       ||+-----------------------------------------------+             ||                                              |
+|                                                       |||:diagtext:`with setter` |nbsp| :placeholder:`B`|             ||                                              |
+|                                                       ||+-----------------------------------------------+             ||                                              |
+|                                                       |+--------------------------------------------------------------+|                                              |
++-------------------------------------------------------+----------------------------------------------------------------+----------------------------------------------+
 
 
 -Wqualified-void-return-type
@@ -8542,6 +8935,15 @@ This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
 +-------------------------------------------------------------------------+
 
 
+-Wredundant-parens
+------------------
+**Diagnostic text:**
+
++-----------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`redundant parentheses surrounding declarator`|
++-----------------------------------------------------------------------------------+
+
+
 -Wregister
 ----------
 This diagnostic is enabled by default.
@@ -8551,7 +8953,7 @@ Also controls `-Wdeprecated-register`_.
 **Diagnostic text:**
 
 +----------------------------------------------------------------------------------------------+
-|:error:`error:` |nbsp| :diagtext:`ISO C++1z does not allow 'register' storage class specifier`|
+|:error:`error:` |nbsp| :diagtext:`ISO C++17 does not allow 'register' storage class specifier`|
 +----------------------------------------------------------------------------------------------+
 
 
@@ -8695,9 +9097,9 @@ Also controls `-Wreturn-type-c-linkage`_.
 |                                                   |+--------------------+|                                                                 |
 +---------------------------------------------------+----------------------+-----------------------------------------------------------------+
 
-+--------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`control reaches end of non-void coroutine`|
-+--------------------------------------------------------------------------------+
++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`control reaches end of coroutine; which is undefined behavior because the promise type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`does not declare 'return\_void()'`|
++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
 +-------------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`control reaches end of non-void function`|
@@ -8707,9 +9109,9 @@ Also controls `-Wreturn-type-c-linkage`_.
 |:warning:`warning:` |nbsp| :diagtext:`control reaches end of non-void lambda`|
 +-----------------------------------------------------------------------------+
 
-+----------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`control may reach end of non-void coroutine`|
-+----------------------------------------------------------------------------------+
++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`control may reach end of coroutine; which is undefined behavior because the promise type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`does not declare 'return\_void()'`|
++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
 +---------------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`control may reach end of non-void function`|
@@ -8789,6 +9191,10 @@ This diagnostic is enabled by default.
 
 **Diagnostic text:**
 
++--------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`section attribute is specified on redeclared variable`|
++--------------------------------------------------------------------------------------------+
+
 +----------------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`section does not match previous declaration`|
 +----------------------------------------------------------------------------------+
@@ -9370,6 +9776,8 @@ This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
 |:warning:`warning:` |nbsp| :diagtext:`this` |nbsp| |+------------------------------------------------------------+| |nbsp| :diagtext:`a prototype`|
 |                                                   ||:diagtext:`function declaration is not`                     ||                               |
 |                                                   |+------------------------------------------------------------+|                               |
+|                                                   ||:diagtext:`block declaration is not`                        ||                               |
+|                                                   |+------------------------------------------------------------+|                               |
 |                                                   ||:diagtext:`old-style function definition is not preceded by`||                               |
 |                                                   |+------------------------------------------------------------+|                               |
 +---------------------------------------------------+--------------------------------------------------------------+-------------------------------+
@@ -9383,6 +9791,8 @@ This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
 |:warning:`warning:` |nbsp| :diagtext:`this` |nbsp| |+------------------------------------------------------------+| |nbsp| :diagtext:`a prototype`|
 |                                                   ||:diagtext:`function declaration is not`                     ||                               |
 |                                                   |+------------------------------------------------------------+|                               |
+|                                                   ||:diagtext:`block declaration is not`                        ||                               |
+|                                                   |+------------------------------------------------------------+|                               |
 |                                                   ||:diagtext:`old-style function definition is not preceded by`||                               |
 |                                                   |+------------------------------------------------------------+|                               |
 +---------------------------------------------------+--------------------------------------------------------------+-------------------------------+
@@ -9576,7 +9986,7 @@ This diagnostic flag exists for GCC compatibility, and has no effect in Clang.
 ----------------------
 Some of the diagnostics controlled by this flag are enabled by default.
 
-Also controls `-Wtautological-constant-out-of-range-compare`_, `-Wtautological-overlap-compare`_, `-Wtautological-pointer-compare`_, `-Wtautological-undefined-compare`_.
+Also controls `-Wtautological-constant-compare`_, `-Wtautological-overlap-compare`_, `-Wtautological-pointer-compare`_, `-Wtautological-undefined-compare`_.
 
 **Diagnostic text:**
 
@@ -9598,21 +10008,22 @@ Also controls `-Wtautological-constant-out-of-range-compare`_, `-Wtautological-o
 |                                                                                     |+-----------------+|
 +-------------------------------------------------------------------------------------+-------------------+
 
-+-------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`comparison of unsigned`|+------------------------+| |nbsp| :diagtext:`expression` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is always` |nbsp| :placeholder:`B`|
-|                                                             ||                        ||                                                                                                           |
-|                                                             |+------------------------+|                                                                                                           |
-|                                                             || |nbsp| :diagtext:`enum`||                                                                                                           |
-|                                                             |+------------------------+|                                                                                                           |
-+-------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------------------------------------------+
 
-+--------------------------------------------------------------------------------------------------------+--------------------------+----------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`comparison of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`unsigned`|+------------------------+| |nbsp| :diagtext:`expression is always` |nbsp| :placeholder:`B`|
-|                                                                                                        ||                        ||                                                                |
-|                                                                                                        |+------------------------+|                                                                |
-|                                                                                                        || |nbsp| :diagtext:`enum`||                                                                |
-|                                                                                                        |+------------------------+|                                                                |
-+--------------------------------------------------------------------------------------------------------+--------------------------+----------------------------------------------------------------+
+-Wtautological-constant-compare
+-------------------------------
+This diagnostic is enabled by default.
+
+Also controls `-Wtautological-constant-out-of-range-compare`_, `-Wtautological-unsigned-enum-zero-compare`_, `-Wtautological-unsigned-zero-compare`_.
+
+**Diagnostic text:**
+
++---------------------------------------------------------+------------------+--------------------------------+------------------+-------------------------------------+-------------------+
+|:warning:`warning:` |nbsp| :diagtext:`comparison` |nbsp| |+----------------+| |nbsp| :placeholder:`C` |nbsp| |+----------------+| |nbsp| :diagtext:`is always` |nbsp| |+-----------------+|
+|                                                         ||:placeholder:`D`||                                ||:placeholder:`B`||                                     ||:diagtext:`false`||
+|                                                         |+----------------+|                                |+----------------+|                                     |+-----------------+|
+|                                                         ||:placeholder:`B`||                                ||:placeholder:`D`||                                     ||:diagtext:`true` ||
+|                                                         |+----------------+|                                |+----------------+|                                     |+-----------------+|
++---------------------------------------------------------+------------------+--------------------------------+------------------+-------------------------------------+-------------------+
 
 
 -Wtautological-constant-out-of-range-compare
@@ -9695,6 +10106,36 @@ This diagnostic is enabled by default.
 +------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------+
 
 
+-Wtautological-unsigned-enum-zero-compare
+-----------------------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++------------------------------------------------------------+--------------------------------------+--------------------------------+--------------------------------------+-------------------------------------+-------------------+
+|:warning:`warning:` |nbsp| :diagtext:`comparison of` |nbsp| |+------------------------------------+| |nbsp| :placeholder:`C` |nbsp| |+------------------------------------+| |nbsp| :diagtext:`is always` |nbsp| |+-----------------+|
+|                                                            ||:placeholder:`D`                    ||                                ||:diagtext:`unsigned enum expression`||                                     ||:diagtext:`false`||
+|                                                            |+------------------------------------+|                                |+------------------------------------+|                                     |+-----------------+|
+|                                                            ||:diagtext:`unsigned enum expression`||                                ||:placeholder:`D`                    ||                                     ||:diagtext:`true` ||
+|                                                            |+------------------------------------+|                                |+------------------------------------+|                                     |+-----------------+|
++------------------------------------------------------------+--------------------------------------+--------------------------------+--------------------------------------+-------------------------------------+-------------------+
+
+
+-Wtautological-unsigned-zero-compare
+------------------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++------------------------------------------------------------+---------------------------------+--------------------------------+---------------------------------+-------------------------------------+-------------------+
+|:warning:`warning:` |nbsp| :diagtext:`comparison of` |nbsp| |+-------------------------------+| |nbsp| :placeholder:`C` |nbsp| |+-------------------------------+| |nbsp| :diagtext:`is always` |nbsp| |+-----------------+|
+|                                                            ||:placeholder:`D`               ||                                ||:diagtext:`unsigned expression`||                                     ||:diagtext:`false`||
+|                                                            |+-------------------------------+|                                |+-------------------------------+|                                     |+-----------------+|
+|                                                            ||:diagtext:`unsigned expression`||                                ||:placeholder:`D`               ||                                     ||:diagtext:`true` ||
+|                                                            |+-------------------------------+|                                |+-------------------------------+|                                     |+-----------------+|
++------------------------------------------------------------+---------------------------------+--------------------------------+---------------------------------+-------------------------------------+-------------------+
+
+
 -Wtentative-definition-incomplete-type
 --------------------------------------
 This diagnostic is enabled by default.
@@ -10110,6 +10551,19 @@ This diagnostic is enabled by default.
 +---------------------------+----------------------+-----------------------------------------------------------------------------------+
 
 
+-Wundefined-internal-type
+-------------------------
+**Diagnostic text:**
+
++---------------------------------------------------------------------------------------------------------+----------------------+----------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ISO C++ requires a definition in this translation unit for` |nbsp| |+--------------------+| |nbsp| :placeholder:`B` |nbsp| :diagtext:`because its type does not have linkage`|
+|                                                                                                         ||:diagtext:`function`||                                                                                  |
+|                                                                                                         |+--------------------+|                                                                                  |
+|                                                                                                         ||:diagtext:`variable`||                                                                                  |
+|                                                                                                         |+--------------------+|                                                                                  |
++---------------------------------------------------------------------------------------------------------+----------------------+----------------------------------------------------------------------------------+
+
+
 -Wundefined-reinterpret-cast
 ----------------------------
 **Diagnostic text:**
@@ -10149,19 +10603,22 @@ Also controls `-Wpotentially-evaluated-expression`_.
 
 -Wunguarded-availability
 ------------------------
+Some of the diagnostics controlled by this flag are enabled by default.
+
+Also controls `-Wunguarded-availability-new`_.
+
 **Diagnostic text:**
 
-+----------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is only available conditionally`|
-+----------------------------------------------------------------------------------------------+
++---------------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is only available on` |nbsp| :placeholder:`B` |nbsp| :placeholder:`C` |nbsp| :diagtext:`or newer`|
++---------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
-+------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`may be partial because the receiver type is unknown`|
-+------------------------------------------------------------------------------------------------------------------+
 
-+--------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is partial:` |nbsp| :placeholder:`B`|
-+--------------------------------------------------------------------------------------------------+
+-Wunguarded-availability-new
+----------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
 
 +---------------------------------------------------------------------------------------------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is only available on` |nbsp| :placeholder:`B` |nbsp| :placeholder:`C` |nbsp| :diagtext:`or newer`|
@@ -10314,10 +10771,6 @@ Some of the diagnostics controlled by this flag are enabled by default.
 |:warning:`warning:` |nbsp| :diagtext:`unexpected token in pragma diagnostic`|
 +----------------------------------------------------------------------------+
 
-+----------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`unknown warning group '`:placeholder:`A`:diagtext:`', ignored`|
-+----------------------------------------------------------------------------------------------------+
-
 +-------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`unknown pragma ignored`|
 +-------------------------------------------------------------+
@@ -10376,6 +10829,10 @@ This diagnostic is enabled by default.
 
 **Diagnostic text:**
 
++----------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`unknown warning group '`:placeholder:`A`:diagtext:`', ignored`|
++----------------------------------------------------------------------------------------------------+
+
 +------------------------------------------------------+---------------------+---------------------------------------------------------+--------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`unknown` |nbsp| |+-------------------+| |nbsp| :diagtext:`option '`:placeholder:`B`:diagtext:`'`|+------------------------------------------------------------+|
 |                                                      ||:diagtext:`warning`||                                                         ||                                                            ||
@@ -10488,6 +10945,36 @@ This diagnostic is enabled by default.
 +-----------------------------------------------------------------------------------------------------+
 
 
+-Wunsupported-abs
+-----------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++-----------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ignoring '-mabs=2008' option because the '`:placeholder:`A`:diagtext:`' architecture does not support it`|
++-----------------------------------------------------------------------------------------------------------------------------------------------+
+
++-------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ignoring '-mabs=legacy' option because the '`:placeholder:`A`:diagtext:`' architecture does not support it`|
++-------------------------------------------------------------------------------------------------------------------------------------------------+
+
+
+-Wunsupported-availability-guard
+--------------------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++---------------------------+------------------------------------+--------------------------------------------------------------+------------------------------------+---------------------+
+|:warning:`warning:` |nbsp| |+----------------------------------+| |nbsp| :diagtext:`does not guard availability here; use if (`|+----------------------------------+|:diagtext:`) instead`|
+|                           ||:diagtext:`@available`            ||                                                              ||:diagtext:`@available`            ||                     |
+|                           |+----------------------------------+|                                                              |+----------------------------------+|                     |
+|                           ||:diagtext:`\_\_builtin\_available`||                                                              ||:diagtext:`\_\_builtin\_available`||                     |
+|                           |+----------------------------------+|                                                              |+----------------------------------+|                     |
++---------------------------+------------------------------------+--------------------------------------------------------------+------------------------------------+---------------------+
+
+
 -Wunsupported-cb
 ----------------
 This diagnostic is enabled by default.
@@ -10527,6 +11014,21 @@ This diagnostic is enabled by default.
 +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
 
+-Wunsupported-gpopt
+-------------------
+This diagnostic is enabled by default.
+
+**Diagnostic text:**
+
++--------------------------------------------------------------------------------------------------+-------------------------------------------+----------------------+
+|:warning:`warning:` |nbsp| :diagtext:`ignoring '-mgpopt' option as it cannot be used with` |nbsp| |+-----------------------------------------+|:diagtext:`-mabicalls`|
+|                                                                                                  ||                                         ||                      |
+|                                                                                                  |+-----------------------------------------+|                      |
+|                                                                                                  ||:diagtext:`the implicit usage of` |nbsp| ||                      |
+|                                                                                                  |+-----------------------------------------+|                      |
++--------------------------------------------------------------------------------------------------+-------------------------------------------+----------------------+
+
+
 -Wunsupported-nan
 -----------------
 This diagnostic is enabled by default.
@@ -10585,14 +11087,14 @@ This diagnostic is enabled by default.
 
 **Diagnostic text:**
 
++-------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`argument '`:placeholder:`A`:diagtext:`' requires profile-guided optimization information`|
++-------------------------------------------------------------------------------------------------------------------------------+
+
 +---------------------------------------------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`joined argument expects additional value: '`:placeholder:`A`:diagtext:`'`|
 +---------------------------------------------------------------------------------------------------------------+
 
-+-----------------------------------------------------------------------------------------------------------------------------+
-|:warning:`warning:` |nbsp| :diagtext:`argument '-fdiagnostics-show-hotness' requires profile-guided optimization information`|
-+-----------------------------------------------------------------------------------------------------------------------------+
-
 +----------------------------------------------------------------------------------------------------+----------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :placeholder:`A`:diagtext:`: '`:placeholder:`B`:diagtext:`' input unused`|+--------------------------------------------------------------------+|
 |                                                                                                    ||+------------------------------------------------------------------+||
@@ -10621,6 +11123,10 @@ This diagnostic is enabled by default.
 |:warning:`warning:` |nbsp| :diagtext:`argument unused during compilation: '`:placeholder:`A`:diagtext:`'`|
 +---------------------------------------------------------------------------------------------------------+
 
++----------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`the flag '`:placeholder:`A`:diagtext:`' has been deprecated and will be ignored`|
++----------------------------------------------------------------------------------------------------------------------+
+
 
 -Wunused-comparison
 -------------------
@@ -10781,6 +11287,21 @@ This diagnostic is enabled by default.
 +-------------------------------------------------------------------------------------------------------------------------------------------+
 
 
+-Wunused-template
+-----------------
+Also controls `-Wunneeded-internal-declaration`_.
+
+**Diagnostic text:**
+
++-----------------------------------------------------+----------------------+----------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`unused` |nbsp| |+--------------------+| |nbsp| :diagtext:`template` |nbsp| :placeholder:`B`|
+|                                                     ||:diagtext:`function`||                                                    |
+|                                                     |+--------------------+|                                                    |
+|                                                     ||:diagtext:`variable`||                                                    |
+|                                                     |+--------------------+|                                                    |
++-----------------------------------------------------+----------------------+----------------------------------------------------+
+
+
 -Wunused-value
 --------------
 This diagnostic is enabled by default.
@@ -10888,12 +11409,18 @@ This diagnostic is enabled by default.
 
 -Wvariadic-macros
 -----------------
+Some of the diagnostics controlled by this flag are enabled by default.
+
 **Diagnostic text:**
 
 +--------------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`named variadic macros are a GNU extension`|
 +--------------------------------------------------------------------------------+
 
++-----------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`\_\_VA\_OPT\_\_ can only appear in the expansion of a variadic macro`|
++-----------------------------------------------------------------------------------------------------------+
+
 +------------------------------------------------------------------------+
 |:warning:`warning:` |nbsp| :diagtext:`variadic macros are a C99 feature`|
 +------------------------------------------------------------------------+
@@ -10952,6 +11479,10 @@ This diagnostic is enabled by default.
 |:warning:`warning:` |nbsp| :diagtext:`parentheses were disambiguated as a function declaration`|
 +-----------------------------------------------------------------------------------------------+
 
++-----------------------------------------------------------------------------------------------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`parentheses were disambiguated as redundant parentheses around declaration of variable named` |nbsp| :placeholder:`A`|
++-----------------------------------------------------------------------------------------------------------------------------------------------------------+
+
 
 -Wvisibility
 ------------
@@ -11037,6 +11568,15 @@ Also controls `-Wdeprecated-writable-strings`_.
 Synonym for `-Wwritable-strings`_.
 
 
+-Wzero-as-null-pointer-constant
+-------------------------------
+**Diagnostic text:**
+
++--------------------------------------------------------------------+
+|:warning:`warning:` |nbsp| :diagtext:`zero as null pointer constant`|
++--------------------------------------------------------------------+
+
+
 -Wzero-length-array
 -------------------
 **Diagnostic text:**
-- 
GitLab


From 290485ca2ff922bb3da08c784323e7e25acbcfde Mon Sep 17 00:00:00 2001
From: Vedant Kumar 
Date: Thu, 26 Oct 2017 21:27:24 +0000
Subject: [PATCH 0096/1682] [CGBlocks] Improve line info in backtraces
 containing *_helper_block

Instead of only setting a non-zero debug location on the return
instruction in *_helper_block functions, set a proper location on all
instructions within these functions. Pick the start location of the
block literal expr for maximum clarity.

The debugger does not step into *_helper_block functions during normal
single-stepping because we mark their parameters as artificial. This is
what we want (the functions are implicitly generated and uninteresting
to most users). The stepping behavior is unchanged by this patch.

rdar://32907581

Differential Revision: https://reviews.llvm.org/D39310

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316704 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/CodeGen/CGBlocks.cpp             |  8 ++------
 test/CodeGenObjC/debug-info-blocks.m | 21 +++++++++++++--------
 2 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 0bd9d7c506..8b79893405 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -1644,10 +1644,8 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
 
   CGM.SetInternalFunctionAttributes(nullptr, Fn, FI);
 
-  auto NL = ApplyDebugLocation::CreateEmpty(*this);
   StartFunction(FD, C.VoidTy, Fn, FI, args);
-  // Create a scope with an artificial location for the body of this function.
-  auto AL = ApplyDebugLocation::CreateArtificial(*this);
+  ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getLocStart()};
   llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
 
   Address src = GetAddrOfLocalVar(&SrcDecl);
@@ -1816,10 +1814,8 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
 
   CGM.SetInternalFunctionAttributes(nullptr, Fn, FI);
 
-  // Create a scope with an artificial location for the body of this function.
-  auto NL = ApplyDebugLocation::CreateEmpty(*this);
   StartFunction(FD, C.VoidTy, Fn, FI, args);
-  auto AL = ApplyDebugLocation::CreateArtificial(*this);
+  ApplyDebugLocation NL{*this, blockInfo.getBlockExpr()->getLocStart()};
 
   llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo();
 
diff --git a/test/CodeGenObjC/debug-info-blocks.m b/test/CodeGenObjC/debug-info-blocks.m
index 0bf566395a..848e389f70 100644
--- a/test/CodeGenObjC/debug-info-blocks.m
+++ b/test/CodeGenObjC/debug-info-blocks.m
@@ -10,23 +10,20 @@
 // CHECK-NEXT: call void @llvm.dbg.declare(metadata <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** %[[ALLOCA]], metadata ![[SELF:[0-9]+]], metadata !{{.*}})
 // CHECK-NEXT: call void @llvm.dbg.declare(metadata %1** %d, metadata ![[D:[0-9]+]], metadata !{{.*}})
 
-// rdar://problem/14386148
-// Test that we don't emit bogus line numbers for the helper functions.
-// Test that we do emit scope info for the helper functions.
+// Test that we do emit scope info for the helper functions, and that the
+// parameters to these functions are marked as artificial (so the debugger
+// doesn't accidentally step into the function).
 // CHECK: define {{.*}} @__copy_helper_block_{{.*}}(i8*, i8*)
 // CHECK-NOT: ret
 // CHECK: call {{.*}}, !dbg ![[DBG_LINE:[0-9]+]]
 // CHECK-NOT: ret
 // CHECK: load {{.*}}, !dbg ![[COPY_LINE:[0-9]+]]
+// CHECK: ret void, !dbg ![[COPY_LINE]]
 // CHECK: define {{.*}} @__destroy_helper_block_{{.*}}(i8*)
 // CHECK-NOT: ret
 // CHECK: load {{.*}}, !dbg ![[DESTROY_LINE:[0-9]+]]
+// CHECK: ret void, !dbg ![[DESTROY_LINE]]
 
-// CHECK-DAG: [[DBG_LINE]] = !DILocation(line: 0, scope: ![[COPY_SP:[0-9]+]])
-// CHECK-DAG: [[COPY_LINE]] = !DILocation(line: 0, scope: ![[COPY_SP:[0-9]+]])
-// CHECK-DAG: [[COPY_SP]] = distinct !DISubprogram(name: "__copy_helper_block_"
-// CHECK-DAG: [[DESTROY_LINE]] = !DILocation(line: 0, scope: ![[DESTROY_SP:[0-9]+]])
-// CHECK-DAG: [[DESTROY_SP]] = distinct !DISubprogram(name: "__destroy_helper_block_"
 typedef unsigned int NSUInteger;
 
 @protocol NSObject
@@ -60,6 +57,14 @@ static void run(void (^block)(void))
 - (id)init
 {
     if ((self = [super init])) {
+      // CHECK-DAG: [[DBG_LINE]] = !DILocation(line: 0, scope: ![[COPY_SP:[0-9]+]])
+      // CHECK-DAG: [[COPY_LINE]] = !DILocation(line: [[@LINE+7]], scope: ![[COPY_SP:[0-9]+]])
+      // CHECK-DAG: [[COPY_SP]] = distinct !DISubprogram(name: "__copy_helper_block_"
+      // CHECK-DAG: [[DESTROY_LINE]] = !DILocation(line: [[@LINE+5]], scope: ![[DESTROY_SP:[0-9]+]])
+      // CHECK-DAG: [[DESTROY_SP]] = distinct !DISubprogram(name: "__destroy_helper_block_"
+      // CHECK-DAG: !DILocalVariable(arg: 1, scope: ![[COPY_SP]], {{.*}}, flags: DIFlagArtificial)
+      // CHECK-DAG: !DILocalVariable(arg: 2, scope: ![[COPY_SP]], {{.*}}, flags: DIFlagArtificial)
+      // CHECK-DAG: !DILocalVariable(arg: 1, scope: ![[DESTROY_SP]], {{.*}}, flags: DIFlagArtificial)
       run(^{
           // CHECK-DAG: ![[SELF]] = !DILocalVariable(name: "self", scope:{{.*}}, line: [[@LINE+4]],
           // CHECK-DAG: ![[D]] = !DILocalVariable(name: "d", scope:{{.*}}, line: [[@LINE+1]],
-- 
GitLab


From feb6dd4fa212508a0eeaca24247791a9e4dc907d Mon Sep 17 00:00:00 2001
From: Craig Topper 
Date: Thu, 26 Oct 2017 21:28:33 +0000
Subject: [PATCH 0097/1682] [X86][Driver] Move all of the X86 feature flags to
 one spot in the Options.td file and pair them up with their negations.

It looks like at one time Options.td was in alphabetical order, but that looks to have long been broken. The result is that it all the no- x86 options got separated from their other friends for no good reason.

This patch puts them all together in one place with the no- paired with its none negated version.

I've kept all the SSE and AVX/AVX512 bits together since they represent a somewhat linear progression of features. The rest I just put in alphabetical order after.

Differential Revision: https://reviews.llvm.org/D39341

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316705 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Driver/Options.td | 246 ++++++++++++++++----------------
 1 file changed, 125 insertions(+), 121 deletions(-)

diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 819dbff288..eef0eca713 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -1693,8 +1693,6 @@ def m16 : Flag<["-"], "m16">, Group, Flags<[DriverOption, CoreOption]>;
 def m32 : Flag<["-"], "m32">, Group, Flags<[DriverOption, CoreOption]>;
 def mqdsp6_compat : Flag<["-"], "mqdsp6-compat">, Group, Flags<[DriverOption,CC1Option]>,
   HelpText<"Enable hexagon-qdsp6 backward compatibility">;
-def m3dnowa : Flag<["-"], "m3dnowa">, Group;
-def m3dnow : Flag<["-"], "m3dnow">, Group;
 def m64 : Flag<["-"], "m64">, Group, Flags<[DriverOption, CoreOption]>;
 def mx32 : Flag<["-"], "mx32">, Group, Flags<[DriverOption, CoreOption]>;
 def mabi_EQ : Joined<["-"], "mabi=">, Group;
@@ -1781,13 +1779,9 @@ def mthread_model : Separate<["-"], "mthread-model">, Group, Flags<[CC1
 def meabi : Separate<["-"], "meabi">, Group, Flags<[CC1Option]>,
   HelpText<"Set EABI type, e.g. 4, 5 or gnu (default depends on triple)">, Values<"default,4,5,gnu">;
 
-def mmmx : Flag<["-"], "mmmx">, Group;
-def mno_3dnowa : Flag<["-"], "mno-3dnowa">, Group;
-def mno_3dnow : Flag<["-"], "mno-3dnow">, Group;
 def mno_constant_cfstrings : Flag<["-"], "mno-constant-cfstrings">, Group;
 def mno_global_merge : Flag<["-"], "mno-global-merge">, Group, Flags<[CC1Option]>,
   HelpText<"Disable merging of globals">;
-def mno_mmx : Flag<["-"], "mno-mmx">, Group;
 def mno_pascal_strings : Flag<["-"], "mno-pascal-strings">,
   Alias;
 def mno_red_zone : Flag<["-"], "mno-red-zone">, Group;
@@ -1795,65 +1789,6 @@ def mno_relax_all : Flag<["-"], "mno-relax-all">, Group;
 def mno_rtd: Flag<["-"], "mno-rtd">, Group;
 def mno_soft_float : Flag<["-"], "mno-soft-float">, Group;
 def mno_stackrealign : Flag<["-"], "mno-stackrealign">, Group;
-def mno_x87 : Flag<["-"], "mno-x87">, Group;
-def mno_80387 : Flag<["-"], "mno-80387">, Alias;
-def mno_sse2 : Flag<["-"], "mno-sse2">, Group;
-def mno_sse3 : Flag<["-"], "mno-sse3">, Group;
-def mno_sse4a : Flag<["-"], "mno-sse4a">, Group;
-def mno_sse4_1 : Flag<["-"], "mno-sse4.1">, Group;
-def mno_sse4_2 : Flag<["-"], "mno-sse4.2">, Group;
-// -mno-sse4 turns off sse4.1 which has the effect of turning off everything
-// later than 4.1. -msse4 turns on 4.2 which has the effect of turning on
-// everything earlier than 4.2.
-def mno_sse4 : Flag<["-"], "mno-sse4">, Alias;
-def mno_sse : Flag<["-"], "mno-sse">, Group;
-def mno_ssse3 : Flag<["-"], "mno-ssse3">, Group;
-def mno_aes : Flag<["-"], "mno-aes">, Group;
-def mno_avx : Flag<["-"], "mno-avx">, Group;
-def mno_avx2 : Flag<["-"], "mno-avx2">, Group;
-def mno_avx512f : Flag<["-"], "mno-avx512f">, Group;
-def mno_avx512cd : Flag<["-"], "mno-avx512cd">, Group;
-def mno_avx512vpopcntdq : Flag<["-"], "mno-avx512vpopcntdq">, Group;
-def mno_avx512er : Flag<["-"], "mno-avx512er">, Group;
-def mno_avx512pf : Flag<["-"], "mno-avx512pf">, Group;
-def mno_avx512dq : Flag<["-"], "mno-avx512dq">, Group;
-def mno_avx512bw : Flag<["-"], "mno-avx512bw">, Group;
-def mno_avx512vl : Flag<["-"], "mno-avx512vl">, Group;
-def mno_avx512vbmi : Flag<["-"], "mno-avx512vbmi">, Group;
-def mno_avx512ifma : Flag<["-"], "mno-avx512ifma">, Group;
-def mno_pclmul : Flag<["-"], "mno-pclmul">, Group;
-def mno_lzcnt : Flag<["-"], "mno-lzcnt">, Group;
-def mno_rdrnd : Flag<["-"], "mno-rdrnd">, Group;
-def mno_fsgsbase : Flag<["-"], "mno-fsgsbase">, Group;
-def mno_bmi : Flag<["-"], "mno-bmi">, Group;
-def mno_bmi2 : Flag<["-"], "mno-bmi2">, Group;
-def mno_popcnt : Flag<["-"], "mno-popcnt">, Group;
-def mno_tbm : Flag<["-"], "mno-tbm">, Group;
-def mno_lwp : Flag<["-"], "mno-lwp">, Group;
-def mno_fma4 : Flag<["-"], "mno-fma4">, Group;
-def mno_fma : Flag<["-"], "mno-fma">, Group;
-def mno_xop : Flag<["-"], "mno-xop">, Group;
-def mno_f16c : Flag<["-"], "mno-f16c">, Group;
-def mno_rtm : Flag<["-"], "mno-rtm">, Group;
-def mno_prfchw : Flag<["-"], "mno-prfchw">, Group;
-def mno_rdseed : Flag<["-"], "mno-rdseed">, Group;
-def mno_adx : Flag<["-"], "mno-adx">, Group;
-def mno_sha : Flag<["-"], "mno-sha">, Group;
-def mno_cx16 : Flag<["-"], "mno-cx16">, Group;
-def mno_fxsr : Flag<["-"], "mno-fxsr">, Group;
-def mno_xsave : Flag<["-"], "mno-xsave">, Group;
-def mno_xsaveopt : Flag<["-"], "mno-xsaveopt">, Group;
-def mno_xsavec : Flag<["-"], "mno-xsavec">, Group;
-def mno_xsaves : Flag<["-"], "mno-xsaves">, Group;
-def mno_mwaitx : Flag<["-"], "mno-mwaitx">, Group;
-def mno_clzero : Flag<["-"], "mno-clzero">, Group;
-def mno_pku : Flag<["-"], "mno-pku">, Group;
-def mno_clflushopt : Flag<["-"], "mno-clflushopt">, Group;
-def mno_clwb : Flag<["-"], "mno-clwb">, Group;
-def mno_movbe : Flag<["-"], "mno-movbe">, Group;
-def mno_mpx : Flag<["-"], "mno-mpx">, Group;
-def mno_sgx : Flag<["-"], "mno-sgx">, Group;
-def mno_prefetchwt1 : Flag<["-"], "mno-prefetchwt1">, Group;
 
 def munaligned_access : Flag<["-"], "munaligned-access">, Group,
   HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64 only)">;
@@ -1999,62 +1934,6 @@ def mpie_copy_relocations : Flag<["-"], "mpie-copy-relocations">, Group
 def mno_pie_copy_relocations : Flag<["-"], "mno-pie-copy-relocations">, Group;
 def mfentry : Flag<["-"], "mfentry">, HelpText<"Insert calls to fentry at function entry (x86 only)">,
   Flags<[CC1Option]>, Group;
-def mx87 : Flag<["-"], "mx87">, Group;
-def m80387 : Flag<["-"], "m80387">, Alias;
-def msse2 : Flag<["-"], "msse2">, Group;
-def msse3 : Flag<["-"], "msse3">, Group;
-def msse4a : Flag<["-"], "msse4a">, Group;
-def msse4_1 : Flag<["-"], "msse4.1">, Group;
-def msse4_2 : Flag<["-"], "msse4.2">, Group;
-def msse4 : Flag<["-"], "msse4">, Alias;
-def msse : Flag<["-"], "msse">, Group;
-def mssse3 : Flag<["-"], "mssse3">, Group;
-def maes : Flag<["-"], "maes">, Group;
-def mavx : Flag<["-"], "mavx">, Group;
-def mavx2 : Flag<["-"], "mavx2">, Group;
-def mavx512f : Flag<["-"], "mavx512f">, Group;
-def mavx512cd : Flag<["-"], "mavx512cd">, Group;
-def mavx512vpopcntdq : Flag<["-"], "mavx512vpopcntdq">, Group;
-def mavx512er : Flag<["-"], "mavx512er">, Group;
-def mavx512pf : Flag<["-"], "mavx512pf">, Group;
-def mavx512dq : Flag<["-"], "mavx512dq">, Group;
-def mavx512bw : Flag<["-"], "mavx512bw">, Group;
-def mavx512vl : Flag<["-"], "mavx512vl">, Group;
-def mavx512vbmi : Flag<["-"], "mavx512vbmi">, Group;
-def mavx512ifma : Flag<["-"], "mavx512ifma">, Group;
-def mpclmul : Flag<["-"], "mpclmul">, Group;
-def mlzcnt : Flag<["-"], "mlzcnt">, Group;
-def mrdrnd : Flag<["-"], "mrdrnd">, Group;
-def mfsgsbase : Flag<["-"], "mfsgsbase">, Group;
-def mbmi : Flag<["-"], "mbmi">, Group;
-def mbmi2 : Flag<["-"], "mbmi2">, Group;
-def mpopcnt : Flag<["-"], "mpopcnt">, Group;
-def mtbm : Flag<["-"], "mtbm">, Group;
-def mlwp : Flag<["-"], "mlwp">, Group;
-def mfma4 : Flag<["-"], "mfma4">, Group;
-def mfma : Flag<["-"], "mfma">, Group;
-def mxop : Flag<["-"], "mxop">, Group;
-def mf16c : Flag<["-"], "mf16c">, Group;
-def mrtm : Flag<["-"], "mrtm">, Group;
-def mprfchw : Flag<["-"], "mprfchw">, Group;
-def mrdseed : Flag<["-"], "mrdseed">, Group;
-def mpku : Flag<["-"], "mpku">, Group;
-def madx : Flag<["-"], "madx">, Group;
-def msha : Flag<["-"], "msha">, Group;
-def mcx16 : Flag<["-"], "mcx16">, Group;
-def mfxsr : Flag<["-"], "mfxsr">, Group;
-def mxsave : Flag<["-"], "mxsave">, Group;
-def mxsaveopt : Flag<["-"], "mxsaveopt">, Group;
-def mxsavec : Flag<["-"], "mxsavec">, Group;
-def mxsaves : Flag<["-"], "mxsaves">, Group;
-def mmwaitx : Flag<["-"], "mmwaitx">, Group;
-def mclzero : Flag<["-"], "mclzero">, Group;
-def mclflushopt : Flag<["-"], "mclflushopt">, Group;
-def mclwb : Flag<["-"], "mclwb">, Group;
-def mmovbe : Flag<["-"], "mmovbe">, Group;
-def mmpx : Flag<["-"], "mmpx">, Group;
-def msgx : Flag<["-"], "msgx">, Group;
-def mprefetchwt1 : Flag<["-"], "mprefetchwt1">, Group;
 def mips16 : Flag<["-"], "mips16">, Group;
 def mno_mips16 : Flag<["-"], "mno-mips16">, Group;
 def mmicromips : Flag<["-"], "mmicromips">, Group;
@@ -2521,6 +2400,131 @@ def mno_hexagon_hvx_double
       Group,
       HelpText<"Disable Hexagon Double Vector eXtensions">;
 
+
+// X86 feature flags
+def mx87 : Flag<["-"], "mx87">, Group;
+def mno_x87 : Flag<["-"], "mno-x87">, Group;
+def m80387 : Flag<["-"], "m80387">, Alias;
+def mno_80387 : Flag<["-"], "mno-80387">, Alias;
+def mmmx : Flag<["-"], "mmmx">, Group;
+def mno_mmx : Flag<["-"], "mno-mmx">, Group;
+def m3dnow : Flag<["-"], "m3dnow">, Group;
+def mno_3dnow : Flag<["-"], "mno-3dnow">, Group;
+def m3dnowa : Flag<["-"], "m3dnowa">, Group;
+def mno_3dnowa : Flag<["-"], "mno-3dnowa">, Group;
+def msse : Flag<["-"], "msse">, Group;
+def mno_sse : Flag<["-"], "mno-sse">, Group;
+def msse2 : Flag<["-"], "msse2">, Group;
+def mno_sse2 : Flag<["-"], "mno-sse2">, Group;
+def msse3 : Flag<["-"], "msse3">, Group;
+def mno_sse3 : Flag<["-"], "mno-sse3">, Group;
+def mssse3 : Flag<["-"], "mssse3">, Group;
+def mno_ssse3 : Flag<["-"], "mno-ssse3">, Group;
+def msse4_1 : Flag<["-"], "msse4.1">, Group;
+def mno_sse4_1 : Flag<["-"], "mno-sse4.1">, Group;
+def msse4_2 : Flag<["-"], "msse4.2">, Group;
+def mno_sse4_2 : Flag<["-"], "mno-sse4.2">, Group;
+def msse4 : Flag<["-"], "msse4">, Alias;
+// -mno-sse4 turns off sse4.1 which has the effect of turning off everything
+// later than 4.1. -msse4 turns on 4.2 which has the effect of turning on
+// everything earlier than 4.2.
+def mno_sse4 : Flag<["-"], "mno-sse4">, Alias;
+def msse4a : Flag<["-"], "msse4a">, Group;
+def mno_sse4a : Flag<["-"], "mno-sse4a">, Group;
+def mavx : Flag<["-"], "mavx">, Group;
+def mno_avx : Flag<["-"], "mno-avx">, Group;
+def mavx2 : Flag<["-"], "mavx2">, Group;
+def mno_avx2 : Flag<["-"], "mno-avx2">, Group;
+def mavx512f : Flag<["-"], "mavx512f">, Group;
+def mno_avx512f : Flag<["-"], "mno-avx512f">, Group;
+def mavx512bw : Flag<["-"], "mavx512bw">, Group;
+def mno_avx512bw : Flag<["-"], "mno-avx512bw">, Group;
+def mavx512cd : Flag<["-"], "mavx512cd">, Group;
+def mno_avx512cd : Flag<["-"], "mno-avx512cd">, Group;
+def mavx512dq : Flag<["-"], "mavx512dq">, Group;
+def mno_avx512dq : Flag<["-"], "mno-avx512dq">, Group;
+def mavx512er : Flag<["-"], "mavx512er">, Group;
+def mno_avx512er : Flag<["-"], "mno-avx512er">, Group;
+def mavx512ifma : Flag<["-"], "mavx512ifma">, Group;
+def mno_avx512ifma : Flag<["-"], "mno-avx512ifma">, Group;
+def mavx512pf : Flag<["-"], "mavx512pf">, Group;
+def mno_avx512pf : Flag<["-"], "mno-avx512pf">, Group;
+def mavx512vbmi : Flag<["-"], "mavx512vbmi">, Group;
+def mno_avx512vbmi : Flag<["-"], "mno-avx512vbmi">, Group;
+def mavx512vl : Flag<["-"], "mavx512vl">, Group;
+def mno_avx512vl : Flag<["-"], "mno-avx512vl">, Group;
+def mavx512vpopcntdq : Flag<["-"], "mavx512vpopcntdq">, Group;
+def mno_avx512vpopcntdq : Flag<["-"], "mno-avx512vpopcntdq">, Group;
+def madx : Flag<["-"], "madx">, Group;
+def mno_adx : Flag<["-"], "mno-adx">, Group;
+def maes : Flag<["-"], "maes">, Group;
+def mno_aes : Flag<["-"], "mno-aes">, Group;
+def mbmi : Flag<["-"], "mbmi">, Group;
+def mno_bmi : Flag<["-"], "mno-bmi">, Group;
+def mbmi2 : Flag<["-"], "mbmi2">, Group;
+def mno_bmi2 : Flag<["-"], "mno-bmi2">, Group;
+def mclflushopt : Flag<["-"], "mclflushopt">, Group;
+def mno_clflushopt : Flag<["-"], "mno-clflushopt">, Group;
+def mclwb : Flag<["-"], "mclwb">, Group;
+def mno_clwb : Flag<["-"], "mno-clwb">, Group;
+def mclzero : Flag<["-"], "mclzero">, Group;
+def mno_clzero : Flag<["-"], "mno-clzero">, Group;
+def mcx16 : Flag<["-"], "mcx16">, Group;
+def mno_cx16 : Flag<["-"], "mno-cx16">, Group;
+def mf16c : Flag<["-"], "mf16c">, Group;
+def mno_f16c : Flag<["-"], "mno-f16c">, Group;
+def mfma : Flag<["-"], "mfma">, Group;
+def mno_fma : Flag<["-"], "mno-fma">, Group;
+def mfma4 : Flag<["-"], "mfma4">, Group;
+def mno_fma4 : Flag<["-"], "mno-fma4">, Group;
+def mfsgsbase : Flag<["-"], "mfsgsbase">, Group;
+def mno_fsgsbase : Flag<["-"], "mno-fsgsbase">, Group;
+def mfxsr : Flag<["-"], "mfxsr">, Group;
+def mno_fxsr : Flag<["-"], "mno-fxsr">, Group;
+def mlwp : Flag<["-"], "mlwp">, Group;
+def mno_lwp : Flag<["-"], "mno-lwp">, Group;
+def mlzcnt : Flag<["-"], "mlzcnt">, Group;
+def mno_lzcnt : Flag<["-"], "mno-lzcnt">, Group;
+def mmovbe : Flag<["-"], "mmovbe">, Group;
+def mno_movbe : Flag<["-"], "mno-movbe">, Group;
+def mmpx : Flag<["-"], "mmpx">, Group;
+def mno_mpx : Flag<["-"], "mno-mpx">, Group;
+def mmwaitx : Flag<["-"], "mmwaitx">, Group;
+def mno_mwaitx : Flag<["-"], "mno-mwaitx">, Group;
+def mpku : Flag<["-"], "mpku">, Group;
+def mno_pku : Flag<["-"], "mno-pku">, Group;
+def mpclmul : Flag<["-"], "mpclmul">, Group;
+def mno_pclmul : Flag<["-"], "mno-pclmul">, Group;
+def mpopcnt : Flag<["-"], "mpopcnt">, Group;
+def mno_popcnt : Flag<["-"], "mno-popcnt">, Group;
+def mprefetchwt1 : Flag<["-"], "mprefetchwt1">, Group;
+def mno_prefetchwt1 : Flag<["-"], "mno-prefetchwt1">, Group;
+def mprfchw : Flag<["-"], "mprfchw">, Group;
+def mno_prfchw : Flag<["-"], "mno-prfchw">, Group;
+def mrdrnd : Flag<["-"], "mrdrnd">, Group;
+def mno_rdrnd : Flag<["-"], "mno-rdrnd">, Group;
+def mrtm : Flag<["-"], "mrtm">, Group;
+def mno_rtm : Flag<["-"], "mno-rtm">, Group;
+def mrdseed : Flag<["-"], "mrdseed">, Group;
+def mno_rdseed : Flag<["-"], "mno-rdseed">, Group;
+def msgx : Flag<["-"], "msgx">, Group;
+def mno_sgx : Flag<["-"], "mno-sgx">, Group;
+def msha : Flag<["-"], "msha">, Group;
+def mno_sha : Flag<["-"], "mno-sha">, Group;
+def mtbm : Flag<["-"], "mtbm">, Group;
+def mno_tbm : Flag<["-"], "mno-tbm">, Group;
+def mxop : Flag<["-"], "mxop">, Group;
+def mno_xop : Flag<["-"], "mno-xop">, Group;
+def mxsave : Flag<["-"], "mxsave">, Group;
+def mno_xsave : Flag<["-"], "mno-xsave">, Group;
+def mxsavec : Flag<["-"], "mxsavec">, Group;
+def mno_xsavec : Flag<["-"], "mno-xsavec">, Group;
+def mxsaveopt : Flag<["-"], "mxsaveopt">, Group;
+def mno_xsaveopt : Flag<["-"], "mno-xsaveopt">, Group;
+def mxsaves : Flag<["-"], "mxsaves">, Group;
+def mno_xsaves : Flag<["-"], "mno-xsaves">, Group;
+
+
 // These are legacy user-facing driver-level option spellings. They are always
 // aliases for options that are spelled using the more common Unix / GNU flag
 // style of double-dash and equals-joined flags.
-- 
GitLab


From 3b4d273c998f39c228f0940515b9b2924451eadb Mon Sep 17 00:00:00 2001
From: Craig Topper 
Date: Thu, 26 Oct 2017 23:06:19 +0000
Subject: [PATCH 0098/1682] [X86] Make -march=i686 an alias of
 -march=pentiumpro

I think the only reason they are different is because we don't set tune_i686 for -march=i686 to match GCC. But GCC 4.9.0 seems to have changed this behavior and they do set it now. So I think they can aliases now.

Differential Revision: https://reviews.llvm.org/D39349

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316712 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Basic/Targets/X86.cpp                  | 16 +++-------------
 lib/Basic/Targets/X86.h                    |  1 -
 test/Preprocessor/predefined-arch-macros.c |  2 ++
 3 files changed, 5 insertions(+), 14 deletions(-)

diff --git a/lib/Basic/Targets/X86.cpp b/lib/Basic/Targets/X86.cpp
index d2716ac670..c1d0a84529 100644
--- a/lib/Basic/Targets/X86.cpp
+++ b/lib/Basic/Targets/X86.cpp
@@ -119,7 +119,6 @@ bool X86TargetInfo::initFeatureMap(
   case CK_i486:
   case CK_i586:
   case CK_Pentium:
-  case CK_i686:
   case CK_PentiumPro:
   case CK_Lakemont:
     break;
@@ -806,15 +805,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
     Builder.defineMacro("__tune_pentium2__");
     LLVM_FALLTHROUGH;
   case CK_PentiumPro:
-    Builder.defineMacro("__tune_i686__");
-    Builder.defineMacro("__tune_pentiumpro__");
-    LLVM_FALLTHROUGH;
-  case CK_i686:
-    Builder.defineMacro("__i686");
-    Builder.defineMacro("__i686__");
-    // Strangely, __tune_i686__ isn't defined by GCC when CPU == i686.
-    Builder.defineMacro("__pentiumpro");
-    Builder.defineMacro("__pentiumpro__");
+    defineCPUMacros(Builder, "i686");
+    defineCPUMacros(Builder, "pentiumpro");
     break;
   case CK_Pentium4:
     defineCPUMacros(Builder, "pentium4");
@@ -1542,7 +1534,6 @@ bool X86TargetInfo::checkCPUKind(CPUKind Kind) const {
   case CK_i586:
   case CK_Pentium:
   case CK_PentiumMMX:
-  case CK_i686:
   case CK_PentiumPro:
   case CK_Pentium2:
   case CK_Pentium3:
@@ -1606,8 +1597,7 @@ X86TargetInfo::CPUKind X86TargetInfo::getCPUKind(StringRef CPU) const {
       .Case("i586", CK_i586)
       .Case("pentium", CK_Pentium)
       .Case("pentium-mmx", CK_PentiumMMX)
-      .Case("i686", CK_i686)
-      .Case("pentiumpro", CK_PentiumPro)
+      .Cases("i686", "pentiumpro", CK_PentiumPro)
       .Case("pentium2", CK_Pentium2)
       .Cases("pentium3", "pentium3m", CK_Pentium3)
       .Case("pentium-m", CK_PentiumM)
diff --git a/lib/Basic/Targets/X86.h b/lib/Basic/Targets/X86.h
index 321ce65bd1..b86497f17b 100644
--- a/lib/Basic/Targets/X86.h
+++ b/lib/Basic/Targets/X86.h
@@ -122,7 +122,6 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
     /// \name i686
     /// i686-generation processors, P6 / Pentium M microarchitecture based.
     //@{
-    CK_i686,
     CK_PentiumPro,
     CK_Pentium2,
     CK_Pentium3,
diff --git a/test/Preprocessor/predefined-arch-macros.c b/test/Preprocessor/predefined-arch-macros.c
index 43dc469d3e..2f3d9e3047 100644
--- a/test/Preprocessor/predefined-arch-macros.c
+++ b/test/Preprocessor/predefined-arch-macros.c
@@ -156,6 +156,8 @@
 // CHECK_I686_M32: #define __i686__ 1
 // CHECK_I686_M32: #define __pentiumpro 1
 // CHECK_I686_M32: #define __pentiumpro__ 1
+// CHECK_I686_M32: #define __tune_i686__ 1
+// CHECK_I686_M32: #define __tune_pentiumpro__ 1
 // CHECK_I686_M32: #define i386 1
 // RUN: not %clang -march=i686 -m64 -E -dM %s -o - 2>&1 \
 // RUN:     -target i386-unknown-linux \
-- 
GitLab


From d724af7fa85aee225bfe4876b602151cc83f5dd0 Mon Sep 17 00:00:00 2001
From: Nico Weber 
Date: Thu, 26 Oct 2017 23:26:29 +0000
Subject: [PATCH 0099/1682] Use -fuse-init-array if no gcc installation is
 found.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

clang currently uses .init_array instead of .ctors on Linux if it detects gcc
4.7+. Make it so that it also uses .init_array if no gcc installation is found
at all – if there's no old gcc, there's nothing we need to be compatible with.

icecc for example runs clang in a very small chroot, so before this change
clang would use .ctors if run under icecc. And lld currently silently mislinks
inputs with .ctors sections, so before this clang + icecc + lld would produce
broken binaries. (But this seems like a good change independent of that lld
bug.)

https://reviews.llvm.org/D39317


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316713 91177308-0d34-0410-b5e6-96231b3b80d8
---
 docs/ReleaseNotes.rst         | 4 ++++
 lib/Driver/ToolChains/Gnu.cpp | 3 ++-
 test/Driver/constructors.c    | 6 ++++++
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
index 30afc52ad2..4c8099121e 100644
--- a/docs/ReleaseNotes.rst
+++ b/docs/ReleaseNotes.rst
@@ -105,6 +105,10 @@ Non-comprehensive list of changes in this release
   Users should generally expect this to be regularly raised to match the most
   recently released version of the Visual C++ compiler.
 
+- clang now defaults to ``.init_array`` if no gcc installation can be found.
+  If a gcc installation is found, it still prefers ``.ctors`` if the found
+  gcc is older than 4.7.0.
+
 New Compiler Flags
 ------------------
 
diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp
index 08d4aa51f2..08282ff003 100644
--- a/lib/Driver/ToolChains/Gnu.cpp
+++ b/lib/Driver/ToolChains/Gnu.cpp
@@ -2366,7 +2366,8 @@ void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs,
       getTriple().getArch() == llvm::Triple::aarch64 ||
       getTriple().getArch() == llvm::Triple::aarch64_be ||
       (getTriple().getOS() == llvm::Triple::Linux &&
-       (!V.isOlderThan(4, 7, 0) || getTriple().isAndroid())) ||
+       ((!GCCInstallation.isValid() || !V.isOlderThan(4, 7, 0)) ||
+        getTriple().isAndroid())) ||
       getTriple().getOS() == llvm::Triple::NaCl ||
       (getTriple().getVendor() == llvm::Triple::MipsTechnologies &&
        !getTriple().hasEnvironment()) ||
diff --git a/test/Driver/constructors.c b/test/Driver/constructors.c
index 39a199a3c6..884fbe8466 100644
--- a/test/Driver/constructors.c
+++ b/test/Driver/constructors.c
@@ -6,6 +6,12 @@
 //
 // RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1       \
 // RUN:     -target i386-unknown-linux \
+// RUN:     --sysroot=%S/Inputs/resource_dir \
+// RUN:     --gcc-toolchain="" \
+// RUN:   | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1       \
+// RUN:     -target i386-unknown-linux \
 // RUN:     --sysroot=%S/Inputs/fake_install_tree \
 // RUN:     --gcc-toolchain="" \
 // RUN:   | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
-- 
GitLab


From 498771461741398a3879ba145b2c9e5e19f0ae88 Mon Sep 17 00:00:00 2001
From: Craig Topper 
Date: Fri, 27 Oct 2017 00:18:16 +0000
Subject: [PATCH 0100/1682] [X86] Add 'sse4' to
 X86TargetInfo::isValidFeatureName

sse4 is valid for target attribute and functions as an alias of sse4.2.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316718 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Basic/Targets/X86.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/Basic/Targets/X86.cpp b/lib/Basic/Targets/X86.cpp
index c1d0a84529..c986363b23 100644
--- a/lib/Basic/Targets/X86.cpp
+++ b/lib/Basic/Targets/X86.cpp
@@ -1164,6 +1164,7 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const {
       .Case("sse2", true)
       .Case("sse3", true)
       .Case("ssse3", true)
+      .Case("sse4", true)
       .Case("sse4.1", true)
       .Case("sse4.2", true)
       .Case("sse4a", true)
-- 
GitLab


From 078b994a27a075f858c758881a7d6ed64e6cd0ec Mon Sep 17 00:00:00 2001
From: Sam Clegg 
Date: Fri, 27 Oct 2017 00:26:07 +0000
Subject: [PATCH 0101/1682] [WebAssembly] Include libclang_rt.builtins in the
 standard way

Differential Revision: https://reviews.llvm.org/D39218

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316719 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Driver/ToolChain.cpp              |  8 +++++++-
 lib/Driver/ToolChains/CommonArgs.cpp  | 10 +---------
 lib/Driver/ToolChains/WebAssembly.cpp |  2 +-
 test/Driver/wasm-toolchain.c          |  4 ++--
 4 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index 593cd82038..1269947166 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -309,7 +309,13 @@ static StringRef getArchNameForCompilerRTLib(const ToolChain &TC,
 
 std::string ToolChain::getCompilerRTPath() const {
   SmallString<128> Path(getDriver().ResourceDir);
-  StringRef OSLibName = Triple.isOSFreeBSD() ? "freebsd" : getOS();
+  StringRef OSLibName;
+  if (Triple.isOSFreeBSD())
+    OSLibName = "freebsd";
+  else if (Triple.isOSBinFormatWasm())
+    OSLibName = "wasm";
+  else
+    OSLibName = getOS();
   llvm::sys::path::append(Path, "lib", OSLibName);
   return Path.str();
 }
diff --git a/lib/Driver/ToolChains/CommonArgs.cpp b/lib/Driver/ToolChains/CommonArgs.cpp
index dc50c4f121..b359cbb77e 100644
--- a/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1027,15 +1027,7 @@ void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D,
 
   switch (RLT) {
   case ToolChain::RLT_CompilerRT:
-    switch (TC.getTriple().getOS()) {
-    default:
-      llvm_unreachable("unsupported OS");
-    case llvm::Triple::Win32:
-    case llvm::Triple::Linux:
-    case llvm::Triple::Fuchsia:
-      CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins"));
-      break;
-    }
+    CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins"));
     break;
   case ToolChain::RLT_Libgcc:
     // Make sure libgcc is not used under MSVC environment by default
diff --git a/lib/Driver/ToolChains/WebAssembly.cpp b/lib/Driver/ToolChains/WebAssembly.cpp
index 354f77fd66..9f91237705 100644
--- a/lib/Driver/ToolChains/WebAssembly.cpp
+++ b/lib/Driver/ToolChains/WebAssembly.cpp
@@ -61,7 +61,7 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
     CmdArgs.push_back("-allow-undefined-file");
     CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("wasm.syms")));
     CmdArgs.push_back("-lc");
-    CmdArgs.push_back("-lcompiler_rt");
+    AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args);
   }
 
   CmdArgs.push_back("-o");
diff --git a/test/Driver/wasm-toolchain.c b/test/Driver/wasm-toolchain.c
index 39401c94ab..6ef1b1fdb7 100644
--- a/test/Driver/wasm-toolchain.c
+++ b/test/Driver/wasm-toolchain.c
@@ -27,10 +27,10 @@
 
 // RUN: %clang -### -no-canonical-prefixes -target wasm32-unknown-unknown --sysroot=/foo %s 2>&1 | FileCheck -check-prefix=LINK %s
 // LINK: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]"
-// LINK: lld{{.*}}" "-flavor" "wasm" "-L/foo/lib" "[[temp]]" "-allow-undefined-file" "wasm.syms" "-lc" "-lcompiler_rt" "-o" "a.out"
+// LINK: lld{{.*}}" "-flavor" "wasm" "-L/foo/lib" "[[temp]]" "-allow-undefined-file" "wasm.syms" "-lc" "{{.*}}/libclang_rt.builtins-wasm32.a" "-o" "a.out"
 
 // A basic C link command-line with optimization.
 
 // RUN: %clang -### -O2 -no-canonical-prefixes -target wasm32-unknown-unknown --sysroot=/foo %s 2>&1 | FileCheck -check-prefix=LINK_OPT %s
 // LINK_OPT: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]"
-// LINK_OPT: lld{{.*}}" "-flavor" "wasm" "-L/foo/lib" "[[temp]]" "-allow-undefined-file" "wasm.syms" "-lc" "-lcompiler_rt" "-o" "a.out"
+// LINK_OPT: lld{{.*}}" "-flavor" "wasm" "-L/foo/lib" "[[temp]]" "-allow-undefined-file" "wasm.syms" "-lc" "{{.*}}/libclang_rt.builtins-wasm32.a" "-o" "a.out"
-- 
GitLab


From 3e7ea4aed7d671ff9c813d345492ee0def151dfb Mon Sep 17 00:00:00 2001
From: Volodymyr Sapsai 
Date: Fri, 27 Oct 2017 00:56:23 +0000
Subject: [PATCH 0102/1682] [CodeGen] Add support for IncompleteArrayType in
 Obj-C ivars.

Fixes an assertion failure when ivar is a struct containing incomplete
array. Also completes support for direct flexible array members.

rdar://problem/21054495

Reviewers: rjmccall, theraven

Reviewed By: rjmccall

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D38774



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316723 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/CodeGen/CGObjCMac.cpp                     |  5 ++++
 test/CodeGenObjC/ivar-layout-flexible-array.m | 28 +++++++++++++++++++
 2 files changed, 33 insertions(+)
 create mode 100644 test/CodeGenObjC/ivar-layout-flexible-array.m

diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 85901a6d65..992da81409 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -5084,6 +5084,11 @@ void IvarLayoutBuilder::visitField(const FieldDecl *field,
 
   // Drill down into arrays.
   uint64_t numElts = 1;
+  if (auto arrayType = CGM.getContext().getAsIncompleteArrayType(fieldType)) {
+    numElts = 0;
+    fieldType = arrayType->getElementType();
+  }
+  // Unlike incomplete arrays, constant arrays can be nested.
   while (auto arrayType = CGM.getContext().getAsConstantArrayType(fieldType)) {
     numElts *= arrayType->getSize().getZExtValue();
     fieldType = arrayType->getElementType();
diff --git a/test/CodeGenObjC/ivar-layout-flexible-array.m b/test/CodeGenObjC/ivar-layout-flexible-array.m
new file mode 100644
index 0000000000..28849c86c2
--- /dev/null
+++ b/test/CodeGenObjC/ivar-layout-flexible-array.m
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -Wno-objc-root-class -fobjc-arc -emit-llvm -o - %s | FileCheck %s
+
+// rdar://problem/21054495
+@interface FlexibleArrayMember {
+  char flexible_array[][4][2];
+}
+@end
+@implementation FlexibleArrayMember
+@end
+// CHECK: @OBJC_METH_VAR_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"flexible_array\00"
+// CHECK-NEXT: @OBJC_METH_VAR_TYPE_{{.*}} = private unnamed_addr constant {{.*}} c"^[4[2c]]\00"
+
+
+typedef char FlexibleArray[];
+
+struct Packet {
+  int size;
+  FlexibleArray data;
+};
+
+@interface VariableSizeIvar {
+  struct Packet flexible_struct;
+}
+@end
+@implementation VariableSizeIvar
+@end
+// CHECK: @OBJC_METH_VAR_NAME_{{.*}} = private unnamed_addr constant {{.*}} c"flexible_struct\00"
+// CHECK-NEXT: @OBJC_METH_VAR_TYPE_{{.*}} = private unnamed_addr constant {{.*}} c"{Packet=\22size\22i\22data\22[0c]}\00"
-- 
GitLab


From ca559e03cc2cedb2c76340f055f784dddac9f83f Mon Sep 17 00:00:00 2001
From: Sam Clegg 
Date: Fri, 27 Oct 2017 01:20:16 +0000
Subject: [PATCH 0103/1682] Fix test/Driver/wasm-toolchain.c on windows

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316725 91177308-0d34-0410-b5e6-96231b3b80d8
---
 test/Driver/wasm-toolchain.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/Driver/wasm-toolchain.c b/test/Driver/wasm-toolchain.c
index 6ef1b1fdb7..77407b899a 100644
--- a/test/Driver/wasm-toolchain.c
+++ b/test/Driver/wasm-toolchain.c
@@ -27,10 +27,10 @@
 
 // RUN: %clang -### -no-canonical-prefixes -target wasm32-unknown-unknown --sysroot=/foo %s 2>&1 | FileCheck -check-prefix=LINK %s
 // LINK: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]"
-// LINK: lld{{.*}}" "-flavor" "wasm" "-L/foo/lib" "[[temp]]" "-allow-undefined-file" "wasm.syms" "-lc" "{{.*}}/libclang_rt.builtins-wasm32.a" "-o" "a.out"
+// LINK: lld{{.*}}" "-flavor" "wasm" "-L/foo/lib" "[[temp]]" "-allow-undefined-file" "wasm.syms" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out"
 
 // A basic C link command-line with optimization.
 
 // RUN: %clang -### -O2 -no-canonical-prefixes -target wasm32-unknown-unknown --sysroot=/foo %s 2>&1 | FileCheck -check-prefix=LINK_OPT %s
 // LINK_OPT: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]"
-// LINK_OPT: lld{{.*}}" "-flavor" "wasm" "-L/foo/lib" "[[temp]]" "-allow-undefined-file" "wasm.syms" "-lc" "{{.*}}/libclang_rt.builtins-wasm32.a" "-o" "a.out"
+// LINK_OPT: lld{{.*}}" "-flavor" "wasm" "-L/foo/lib" "[[temp]]" "-allow-undefined-file" "wasm.syms" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out"
-- 
GitLab


From d2d3a85d2777c75fdda6b69b7b62c0361015288a Mon Sep 17 00:00:00 2001
From: Ivan Donchevskii 
Date: Fri, 27 Oct 2017 11:05:40 +0000
Subject: [PATCH 0104/1682] Test commit

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316758 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Sema/SemaCodeComplete.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index a0d8c9941e..72ab65fc58 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -47,7 +47,7 @@ namespace {
     /// the result set (when it returns true) and which declarations should be
     /// filtered out (returns false).
     typedef bool (ResultBuilder::*LookupFilter)(const NamedDecl *) const;
-    
+
     typedef CodeCompletionResult Result;
     
   private:
-- 
GitLab


From 224b1ed240890583d9623dfe9f63b81f14a05b99 Mon Sep 17 00:00:00 2001
From: Gabor Horvath 
Date: Fri, 27 Oct 2017 12:53:37 +0000
Subject: [PATCH 0105/1682] [CrossTU] Fix handling of Cross Translation Unit
 directory path

Differential Revision: https://reviews.llvm.org/D38842


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316764 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/CrossTU/CrossTranslationUnit.cpp          |  5 +---
 .../CrossTU/CrossTranslationUnitTest.cpp      | 26 ++++++++++++++++---
 2 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/lib/CrossTU/CrossTranslationUnit.cpp b/lib/CrossTU/CrossTranslationUnit.cpp
index a503578da0..e20ea77022 100644
--- a/lib/CrossTU/CrossTranslationUnit.cpp
+++ b/lib/CrossTU/CrossTranslationUnit.cpp
@@ -93,10 +93,7 @@ parseCrossTUIndex(StringRef IndexPath, StringRef CrossTUDir) {
             index_error_code::multiple_definitions, IndexPath.str(), LineNo);
       StringRef FileName = LineRef.substr(Pos + 1);
       SmallString<256> FilePath = CrossTUDir;
-      if (llvm::sys::path::is_absolute(FileName))
-        FilePath = FileName;
-      else
-        llvm::sys::path::append(FilePath, FileName);
+      llvm::sys::path::append(FilePath, FileName);
       Result[FunctionLookupName] = FilePath.str().str();
     } else
       return llvm::make_error(
diff --git a/unittests/CrossTU/CrossTranslationUnitTest.cpp b/unittests/CrossTU/CrossTranslationUnitTest.cpp
index 795a4351b5..5fbf56ed43 100644
--- a/unittests/CrossTU/CrossTranslationUnitTest.cpp
+++ b/unittests/CrossTU/CrossTranslationUnitTest.cpp
@@ -109,9 +109,9 @@ TEST(CrossTranslationUnit, CanLoadFunctionDefinition) {
 
 TEST(CrossTranslationUnit, IndexFormatCanBeParsed) {
   llvm::StringMap Index;
-  Index["a"] = "b";
-  Index["c"] = "d";
-  Index["e"] = "f";
+  Index["a"] = "/b/f1";
+  Index["c"] = "/d/f2";
+  Index["e"] = "/f/f3";
   std::string IndexText = createCrossTUIndexString(Index);
 
   int IndexFD;
@@ -134,5 +134,25 @@ TEST(CrossTranslationUnit, IndexFormatCanBeParsed) {
     EXPECT_TRUE(Index.count(E.getKey()));
 }
 
+TEST(CrossTranslationUnit, CTUDirIsHandledCorrectly) {
+  llvm::StringMap Index;
+  Index["a"] = "/b/c/d";
+  std::string IndexText = createCrossTUIndexString(Index);
+
+  int IndexFD;
+  llvm::SmallString<256> IndexFileName;
+  ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("index", "txt", IndexFD,
+                                                  IndexFileName));
+  llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD);
+  IndexFile.os() << IndexText;
+  IndexFile.os().flush();
+  EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName));
+  llvm::Expected> IndexOrErr =
+      parseCrossTUIndex(IndexFileName, "/ctudir");
+  EXPECT_TRUE((bool)IndexOrErr);
+  llvm::StringMap ParsedIndex = IndexOrErr.get();
+  EXPECT_EQ(ParsedIndex["a"], "/ctudir/b/c/d");
+}
+
 } // end namespace cross_tu
 } // end namespace clang
-- 
GitLab


From 67b501a5256569fb097039d007f701327f7e0e6b Mon Sep 17 00:00:00 2001
From: Don Hinton 
Date: Fri, 27 Oct 2017 17:02:33 +0000
Subject: [PATCH 0106/1682] New lldb python module for managing diagnostic
 breakpoints

Summary:
Can be used to set breakpoints for either the diagnostics actually
emitted for the current compilation, a particular DiagID, or all
DiagIDs for a particular warning.

Differential Revision: https://reviews.llvm.org/D36347

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316773 91177308-0d34-0410-b5e6-96231b3b80d8
---
 utils/clangdiag.py | 192 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 192 insertions(+)
 create mode 100755 utils/clangdiag.py

diff --git a/utils/clangdiag.py b/utils/clangdiag.py
new file mode 100755
index 0000000000..f434bfeaa4
--- /dev/null
+++ b/utils/clangdiag.py
@@ -0,0 +1,192 @@
+#!/usr/bin/python
+
+#----------------------------------------------------------------------
+# Be sure to add the python path that points to the LLDB shared library.
+#
+# # To use this in the embedded python interpreter using "lldb" just
+# import it with the full path using the "command script import"
+# command
+#   (lldb) command script import /path/to/clandiag.py
+#----------------------------------------------------------------------
+
+import lldb
+import argparse
+import commands
+import shlex
+import os
+import re
+import subprocess
+
+class MyParser(argparse.ArgumentParser):
+    def format_help(self):
+        return '''     Commands for managing clang diagnostic breakpoints
+
+Syntax: clangdiag enable [|]
+        clangdiag disable
+        clangdiag diagtool [|reset]
+
+The following subcommands are supported:
+
+      enable   -- Enable clang diagnostic breakpoints.
+      disable  -- Disable all clang diagnostic breakpoints.
+      diagtool -- Return, set, or reset diagtool path.
+
+This command sets breakpoints in clang, and clang based tools, that
+emit diagnostics.  When a diagnostic is emitted, and clangdiag is
+enabled, it will use the appropriate diagtool application to determine
+the name of the DiagID, and set breakpoints in all locations that
+'diag::name' appears in the source.  Since the new breakpoints are set
+after they are encountered, users will need to launch the executable a
+second time in order to hit the new breakpoints.
+
+For in-tree builds, the diagtool application, used to map DiagID's to
+names, is found automatically in the same directory as the target
+executable.  However, out-or-tree builds must use the 'diagtool'
+subcommand to set the appropriate path for diagtool in the clang debug
+bin directory.  Since this mapping is created at build-time, it's
+important for users to use the same version that was generated when
+clang was compiled, or else the id's won't match.
+
+Notes:
+- Substrings can be passed for both  and .
+- If  is passed, only enable the DiagID(s) for that warning.
+- If  is passed, only enable that DiagID.
+- Rerunning enable clears existing breakpoints.
+- diagtool is used in breakpoint callbacks, so it can be changed
+  without the need to rerun enable.
+- Adding this to your ~.lldbinit file makes clangdiag available at startup:
+  "command script import /path/to/clangdiag.py"
+
+'''
+
+def create_diag_options():
+    parser = MyParser(prog='clangdiag')
+    subparsers = parser.add_subparsers(
+        title='subcommands',
+        dest='subcommands',
+        metavar='')
+    disable_parser = subparsers.add_parser('disable')
+    enable_parser = subparsers.add_parser('enable')
+    enable_parser.add_argument('id', nargs='?')
+    diagtool_parser = subparsers.add_parser('diagtool')
+    diagtool_parser.add_argument('path', nargs='?')
+    return parser
+
+def getDiagtool(target, diagtool = None):
+    id = target.GetProcess().GetProcessID()
+    if 'diagtool' not in getDiagtool.__dict__:
+        getDiagtool.diagtool = {}
+    if diagtool:
+        if diagtool == 'reset':
+            getDiagtool.diagtool[id] = None
+        elif os.path.exists(diagtool):
+            getDiagtool.diagtool[id] = diagtool
+        else:
+            print('clangdiag: %s not found.' % diagtool)
+    if not id in getDiagtool.diagtool or not getDiagtool.diagtool[id]:
+        getDiagtool.diagtool[id] = None
+        exe = target.GetExecutable()
+        if not exe.Exists():
+            print('clangdiag: Target (%s) not set.' % exe.GetFilename())
+        else:
+            diagtool = os.path.join(exe.GetDirectory(), 'diagtool')
+            if os.path.exists(diagtool):
+                getDiagtool.diagtool[id] = diagtool
+            else:
+                print('clangdiag: diagtool not found along side %s' % exe)
+
+    return getDiagtool.diagtool[id]
+
+def setDiagBreakpoint(frame, bp_loc, dict):
+    id = frame.FindVariable("DiagID").GetValue()
+    if id is None:
+        print('clangdiag: id is None')
+        return False
+
+    # Don't need to test this time, since we did that in enable.
+    target = frame.GetThread().GetProcess().GetTarget()
+    diagtool = getDiagtool(target)
+    name = subprocess.check_output([diagtool, "find-diagnostic-id", id]).rstrip();
+    # Make sure we only consider errors, warnings, and extentions.
+    # FIXME: Make this configurable?
+    prefixes = ['err_', 'warn_', 'exp_']
+    if len([prefix for prefix in prefixes+[''] if name.startswith(prefix)][0]):
+        bp = target.BreakpointCreateBySourceRegex(name, lldb.SBFileSpec())
+        bp.AddName("clang::Diagnostic")
+
+    return False
+
+def enable(exe_ctx, args):
+    # Always disable existing breakpoints
+    disable(exe_ctx)
+
+    target = exe_ctx.GetTarget()
+    numOfBreakpoints = target.GetNumBreakpoints()
+
+    if args.id:
+        # Make sure we only consider errors, warnings, and extentions.
+        # FIXME: Make this configurable?
+        prefixes = ['err_', 'warn_', 'exp_']
+        if len([prefix for prefix in prefixes+[''] if args.id.startswith(prefix)][0]):
+            bp = target.BreakpointCreateBySourceRegex(args.id, lldb.SBFileSpec())
+            bp.AddName("clang::Diagnostic")
+        else:
+            diagtool = getDiagtool(target)
+            list = subprocess.check_output([diagtool, "list-warnings"]).rstrip();
+            for line in list.splitlines(True):
+                m = re.search(r' *(.*) .*\[\-W' + re.escape(args.id) + r'.*].*', line)
+                # Make sure we only consider warnings.
+                if m and m.group(1).startswith('warn_'):
+                    bp = target.BreakpointCreateBySourceRegex(m.group(1), lldb.SBFileSpec())
+                    bp.AddName("clang::Diagnostic")
+    else:
+        print('Adding callbacks.')
+        bp = target.BreakpointCreateByName('DiagnosticsEngine::Report')
+        bp.SetScriptCallbackFunction('clangdiag.setDiagBreakpoint')
+        bp.AddName("clang::Diagnostic")
+
+    count = target.GetNumBreakpoints() - numOfBreakpoints
+    print('%i breakpoint%s added.' % (count, "s"[count==1:]))
+
+    return
+
+def disable(exe_ctx):
+    target = exe_ctx.GetTarget()
+    # Remove all diag breakpoints.
+    bkpts = lldb.SBBreakpointList(target)
+    target.FindBreakpointsByName("clang::Diagnostic", bkpts)
+    for i in range(bkpts.GetSize()):
+        target.BreakpointDelete(bkpts.GetBreakpointAtIndex(i).GetID())
+
+    return
+
+def the_diag_command(debugger, command, exe_ctx, result, dict):
+    # Use the Shell Lexer to properly parse up command options just like a
+    # shell would
+    command_args = shlex.split(command)
+    parser = create_diag_options()
+    try:
+        args = parser.parse_args(command_args)
+    except:
+        return
+
+    if args.subcommands == 'enable':
+        enable(exe_ctx, args)
+    elif args.subcommands == 'disable':
+        disable(exe_ctx)
+    else:
+        diagtool = getDiagtool(exe_ctx.GetTarget(), args.path)
+        print('diagtool = %s' % diagtool)
+
+    return
+
+def __lldb_init_module(debugger, dict):
+    # This initializer is being run from LLDB in the embedded command interpreter
+    # Make the options so we can generate the help text for the new LLDB
+    # command line command prior to registering it with LLDB below
+    parser = create_diag_options()
+    the_diag_command.__doc__ = parser.format_help()
+    # Add any commands contained in this module to LLDB
+    debugger.HandleCommand(
+        'command script add -f clangdiag.the_diag_command clangdiag')
+    print 'The "clangdiag" command has been installed, type "help clangdiag" or "clangdiag --help" for detailed help.'
-- 
GitLab


From d64b9c663c0575c69a772118b184928319e4689c Mon Sep 17 00:00:00 2001
From: Sam Clegg 
Date: Fri, 27 Oct 2017 18:10:19 +0000
Subject: [PATCH 0107/1682] [WebAssembly] Add crt1.o with calling lld

Also, for OS unknown targets like wasm, don't include
'unknown' in the library path. This is a fix for rL316719.

Differential Revision: https://reviews.llvm.org/D39354

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316777 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Driver/ToolChain.cpp              | 14 ++++++--------
 lib/Driver/ToolChains/WebAssembly.cpp |  3 +++
 test/Driver/wasm-toolchain.c          |  4 ++--
 3 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index 1269947166..416d78509d 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -309,14 +309,12 @@ static StringRef getArchNameForCompilerRTLib(const ToolChain &TC,
 
 std::string ToolChain::getCompilerRTPath() const {
   SmallString<128> Path(getDriver().ResourceDir);
-  StringRef OSLibName;
-  if (Triple.isOSFreeBSD())
-    OSLibName = "freebsd";
-  else if (Triple.isOSBinFormatWasm())
-    OSLibName = "wasm";
-  else
-    OSLibName = getOS();
-  llvm::sys::path::append(Path, "lib", OSLibName);
+  if (Triple.isOSUnknown()) {
+    llvm::sys::path::append(Path, "lib");
+  } else {
+    StringRef OSLibName = Triple.isOSFreeBSD() ? "freebsd" : getOS();
+    llvm::sys::path::append(Path, "lib", OSLibName);
+  }
   return Path.str();
 }
 
diff --git a/lib/Driver/ToolChains/WebAssembly.cpp b/lib/Driver/ToolChains/WebAssembly.cpp
index 9f91237705..b57989ce45 100644
--- a/lib/Driver/ToolChains/WebAssembly.cpp
+++ b/lib/Driver/ToolChains/WebAssembly.cpp
@@ -49,6 +49,9 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
   Args.AddAllArgs(CmdArgs, options::OPT_L);
   ToolChain.AddFilePathLibArgs(Args, CmdArgs);
 
+  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles))
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o")));
+
   AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
 
   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
diff --git a/test/Driver/wasm-toolchain.c b/test/Driver/wasm-toolchain.c
index 77407b899a..e9862f0b7d 100644
--- a/test/Driver/wasm-toolchain.c
+++ b/test/Driver/wasm-toolchain.c
@@ -27,10 +27,10 @@
 
 // RUN: %clang -### -no-canonical-prefixes -target wasm32-unknown-unknown --sysroot=/foo %s 2>&1 | FileCheck -check-prefix=LINK %s
 // LINK: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]"
-// LINK: lld{{.*}}" "-flavor" "wasm" "-L/foo/lib" "[[temp]]" "-allow-undefined-file" "wasm.syms" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out"
+// LINK: lld{{.*}}" "-flavor" "wasm" "-L/foo/lib" "crt1.o" "[[temp]]" "-allow-undefined-file" "wasm.syms" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out"
 
 // A basic C link command-line with optimization.
 
 // RUN: %clang -### -O2 -no-canonical-prefixes -target wasm32-unknown-unknown --sysroot=/foo %s 2>&1 | FileCheck -check-prefix=LINK_OPT %s
 // LINK_OPT: clang{{.*}}" "-cc1" {{.*}} "-o" "[[temp:[^"]*]]"
-// LINK_OPT: lld{{.*}}" "-flavor" "wasm" "-L/foo/lib" "[[temp]]" "-allow-undefined-file" "wasm.syms" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out"
+// LINK_OPT: lld{{.*}}" "-flavor" "wasm" "-L/foo/lib" "crt1.o" "[[temp]]" "-allow-undefined-file" "wasm.syms" "-lc" "{{.*[/\\]}}libclang_rt.builtins-wasm32.a" "-o" "a.out"
-- 
GitLab


From 1c09b76713c0a3521937e035b3ab4edef687e7ee Mon Sep 17 00:00:00 2001
From: Alex Lorenz 
Date: Fri, 27 Oct 2017 18:13:31 +0000
Subject: [PATCH 0108/1682] [Sema] Fix an assert-on-invalid by avoiding
 function template specialisation deduction for invalid functions

The fabricated template parameters cause an assertion because their depth
is invalid.

rdar://34109988

Differential Revision: https://reviews.llvm.org/D37341


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316778 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Sema/SemaDecl.cpp                           |  8 ++++----
 test/SemaTemplate/deduction-crash.cpp           | 17 +++++++++++++++++
 .../explicit-specialization-member.cpp          | 12 ++++--------
 3 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 573c1af8d2..d68b430bae 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -8962,10 +8962,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
           diag::ext_function_specialization_in_class :
           diag::err_function_specialization_in_class)
           << NewFD->getDeclName();
-      } else if (CheckFunctionTemplateSpecialization(NewFD,
-                                  (HasExplicitTemplateArgs ? &TemplateArgs
-                                                           : nullptr),
-                                                     Previous))
+      } else if (!NewFD->isInvalidDecl() &&
+                 CheckFunctionTemplateSpecialization(
+                     NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr),
+                     Previous))
         NewFD->setInvalidDecl();
 
       // C++ [dcl.stc]p1:
diff --git a/test/SemaTemplate/deduction-crash.cpp b/test/SemaTemplate/deduction-crash.cpp
index 74a25865aa..2c58fefa06 100644
--- a/test/SemaTemplate/deduction-crash.cpp
+++ b/test/SemaTemplate/deduction-crash.cpp
@@ -144,3 +144,20 @@ namespace var_template_partial_spec_incomplete {
   template int n; // expected-error +{{}} expected-note {{}}
   int k = n;
 }
+
+namespace deduceFunctionSpecializationForInvalidOutOfLineFunction {
+
+template 
+struct SourceSelectionRequirement {
+  template
+  OutputT evaluateSelectionRequirement(InputT &&Value) {
+  }
+};
+
+template 
+OutputT SourceSelectionRequirement::
+evaluateSelectionRequirement(InputT &&Value) { // expected-error {{cannot specialize a member of an unspecialized template}}
+  return Value;
+}
+
+}
diff --git a/test/SemaTemplate/explicit-specialization-member.cpp b/test/SemaTemplate/explicit-specialization-member.cpp
index c0c36808b4..e8165ac9ca 100644
--- a/test/SemaTemplate/explicit-specialization-member.cpp
+++ b/test/SemaTemplate/explicit-specialization-member.cpp
@@ -38,24 +38,20 @@ namespace PR18246 {
 
   template
   template
-  void Baz::bar() { // expected-note {{couldn't infer template argument 'N'}}
+  void Baz::bar() {
   }
 
-  // FIXME: We shouldn't try to match this against a prior declaration if
-  // template parameter matching failed.
   template
-  void Baz::bar<0>() { // expected-error {{cannot specialize a member of an unspecialized template}} \
-                          // expected-error {{no function template matches}}
+  void Baz::bar<0>() { // expected-error {{cannot specialize a member of an unspecialized template}}
   }
 }
 
 namespace PR19340 {
 template struct Helper {
-  template static void func(const T *m) {} // expected-note {{failed template argument deduction}}
+  template static void func(const T *m) {}
 };
 
-template void Helper::func<2>() {} // expected-error {{cannot specialize a member}} \
-                                                  // expected-error {{no function template matches}}
+template void Helper::func<2>() {} // expected-error {{cannot specialize a member}}
 }
 
 namespace SpecLoc {
-- 
GitLab


From 99af5f07de88d6757dedc7ee6a8197fab0fe8c0f Mon Sep 17 00:00:00 2001
From: Alex Lorenz 
Date: Fri, 27 Oct 2017 18:19:11 +0000
Subject: [PATCH 0109/1682] [refactor] Describe refactorings in the operation
 classes

This commit changes the way that the refactoring operation classes are
structured:
- Users have to call `initiate` instead of constructing an instance of the
  class. The `initiate` is now supposed to have custom initiation logic, and
  you don't need to subclass the builtin requirements.
- A new `describe` function returns a structure with the id, title and the
  description of the refactoring operation.

The refactoring action classes are now placed into one common place in
RefactoringActions.cpp instead of being separate.

Differential Revision: https://reviews.llvm.org/D38985


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316780 91177308-0d34-0410-b5e6-96231b3b80d8
---
 .../Tooling/Refactoring/Extract/Extract.h     |  53 ++++++++
 .../Refactoring/RefactoringActionRegistry.def |   8 --
 .../Refactoring/RefactoringActionRule.h       |  14 +++
 .../RefactoringActionRulesInternal.h          |   7 +-
 .../Refactoring/Rename/RenamingAction.h       |  22 +++-
 include/clang/module.modulemap                |   2 -
 lib/Tooling/Refactoring/Extract.cpp           | 115 +++++-------------
 .../Refactoring/RefactoringActions.cpp        |  71 ++++++++++-
 .../Refactoring/Rename/RenamingAction.cpp     |  86 +++++--------
 .../Tooling/RefactoringActionRulesTest.cpp    |  28 ++++-
 10 files changed, 242 insertions(+), 164 deletions(-)
 create mode 100644 include/clang/Tooling/Refactoring/Extract/Extract.h
 delete mode 100644 include/clang/Tooling/Refactoring/RefactoringActionRegistry.def

diff --git a/include/clang/Tooling/Refactoring/Extract/Extract.h b/include/clang/Tooling/Refactoring/Extract/Extract.h
new file mode 100644
index 0000000000..2fd76d252c
--- /dev/null
+++ b/include/clang/Tooling/Refactoring/Extract/Extract.h
@@ -0,0 +1,53 @@
+//===--- Extract.h - Clang refactoring library ----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_REFACTOR_EXTRACT_EXTRACT_H
+#define LLVM_CLANG_TOOLING_REFACTOR_EXTRACT_EXTRACT_H
+
+#include "clang/Tooling/Refactoring/ASTSelection.h"
+#include "clang/Tooling/Refactoring/RefactoringActionRules.h"
+
+namespace clang {
+namespace tooling {
+
+/// An "Extract Function" refactoring moves code into a new function that's
+/// then called from the place where the original code was.
+class ExtractFunction final : public SourceChangeRefactoringRule {
+public:
+  /// Initiates the extract function refactoring operation.
+  ///
+  /// \param Code     The selected set of statements.
+  /// \param DeclName The name name of the extract function. If None,
+  ///                 "extracted" is used.
+  static Expected initiate(RefactoringRuleContext &Context,
+                                            CodeRangeASTSelection Code,
+                                            Optional DeclName);
+
+  static const RefactoringDescriptor &describe();
+
+private:
+  ExtractFunction(CodeRangeASTSelection Code, Optional DeclName)
+      : Code(std::move(Code)),
+        DeclName(DeclName ? std::move(*DeclName) : "extracted") {}
+
+  Expected
+  createSourceReplacements(RefactoringRuleContext &Context) override;
+
+  CodeRangeASTSelection Code;
+
+  // FIXME: Account for naming collisions:
+  //  - error when name is specified by user.
+  //  - rename to "extractedN" when name is implicit.
+  std::string DeclName;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_REFACTOR_EXTRACT_EXTRACT_H
diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRegistry.def b/include/clang/Tooling/Refactoring/RefactoringActionRegistry.def
deleted file mode 100644
index 9aeead4148..0000000000
--- a/include/clang/Tooling/Refactoring/RefactoringActionRegistry.def
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef REFACTORING_ACTION
-#define REFACTORING_ACTION(Name)
-#endif
-
-REFACTORING_ACTION(LocalRename)
-REFACTORING_ACTION(Extract)
-
-#undef REFACTORING_ACTION
diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRule.h b/include/clang/Tooling/Refactoring/RefactoringActionRule.h
index 294ccc381b..4130e29d8d 100644
--- a/include/clang/Tooling/Refactoring/RefactoringActionRule.h
+++ b/include/clang/Tooling/Refactoring/RefactoringActionRule.h
@@ -11,6 +11,8 @@
 #define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_H
 
 #include "clang/Basic/LLVM.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
 #include 
 
 namespace clang {
@@ -20,6 +22,15 @@ class RefactoringOptionVisitor;
 class RefactoringResultConsumer;
 class RefactoringRuleContext;
 
+struct RefactoringDescriptor {
+  /// A unique identifier for the specific refactoring.
+  StringRef Name;
+  /// A human readable title for the refactoring.
+  StringRef Title;
+  /// A human readable description of what the refactoring does.
+  StringRef Description;
+};
+
 /// A common refactoring action rule interface that defines the 'invoke'
 /// function that performs the refactoring operation (either fully or
 /// partially).
@@ -33,6 +44,9 @@ public:
   /// consumer to propagate the result of the refactoring action.
   virtual void invoke(RefactoringResultConsumer &Consumer,
                       RefactoringRuleContext &Context) = 0;
+
+  /// Returns the structure that describes the refactoring.
+  // static const RefactoringDescriptor &describe() = 0;
 };
 
 /// A refactoring action rule is a wrapper class around a specific refactoring
diff --git a/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h b/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h
index 443c7f86df..75b6c8f70d 100644
--- a/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h
+++ b/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h
@@ -57,7 +57,11 @@ void invokeRuleAfterValidatingRequirements(
     return Consumer.handleError(std::move(Err));
   // Construct the target action rule by extracting the evaluated
   // requirements from Expected<> wrappers and then run it.
-  RuleType(std::move((*std::get(Values)))...).invoke(Consumer, Context);
+  auto Rule =
+      RuleType::initiate(Context, std::move((*std::get(Values)))...);
+  if (!Rule)
+    return Consumer.handleError(Rule.takeError());
+  Rule->invoke(Consumer, Context);
 }
 
 inline void visitRefactoringOptionsImpl(RefactoringOptionVisitor &) {}
@@ -141,7 +145,6 @@ createRefactoringActionRule(const RequirementTypes &... Requirements) {
           Visitor, Requirements,
           llvm::index_sequence_for());
     }
-
   private:
     std::tuple Requirements;
   };
diff --git a/include/clang/Tooling/Refactoring/Rename/RenamingAction.h b/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
index f2d9a7bb4d..d9ed7d3a1f 100644
--- a/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
+++ b/include/clang/Tooling/Refactoring/Rename/RenamingAction.h
@@ -17,6 +17,7 @@
 
 #include "clang/Tooling/Refactoring.h"
 #include "clang/Tooling/Refactoring/AtomicChange.h"
+#include "clang/Tooling/Refactoring/RefactoringActionRules.h"
 #include "clang/Tooling/Refactoring/RefactoringOptions.h"
 #include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h"
 #include "llvm/Support/Error.h"
@@ -46,12 +47,23 @@ private:
   bool PrintLocations;
 };
 
-class NewNameOption : public RequiredRefactoringOption {
+class RenameOccurrences final : public SourceChangeRefactoringRule {
 public:
-  StringRef getName() const override { return "new-name"; }
-  StringRef getDescription() const override {
-    return "The new name to change the symbol to";
-  }
+  static Expected initiate(RefactoringRuleContext &Context,
+                                              SourceRange SelectionRange,
+                                              std::string NewName);
+
+  static const RefactoringDescriptor &describe();
+
+private:
+  RenameOccurrences(const NamedDecl *ND, std::string NewName)
+      : ND(ND), NewName(std::move(NewName)) {}
+
+  Expected
+  createSourceReplacements(RefactoringRuleContext &Context) override;
+
+  const NamedDecl *ND;
+  std::string NewName;
 };
 
 /// Returns source replacements that correspond to the rename of the given
diff --git a/include/clang/module.modulemap b/include/clang/module.modulemap
index 1e3262188f..41cf73d910 100644
--- a/include/clang/module.modulemap
+++ b/include/clang/module.modulemap
@@ -146,8 +146,6 @@ module Clang_Tooling {
   // importing the AST matchers library gives a link dependency on the AST
   // matchers (and thus the AST), which clang-format should not have.
   exclude header "Tooling/RefactoringCallbacks.h"
-
-  textual header "Tooling/Refactoring/RefactoringActionRegistry.def"
 }
 
 module Clang_ToolingCore {
diff --git a/lib/Tooling/Refactoring/Extract.cpp b/lib/Tooling/Refactoring/Extract.cpp
index 616900c181..b1000b60ee 100644
--- a/lib/Tooling/Refactoring/Extract.cpp
+++ b/lib/Tooling/Refactoring/Extract.cpp
@@ -13,12 +13,10 @@
 ///
 //===----------------------------------------------------------------------===//
 
+#include "clang/Tooling/Refactoring/Extract/Extract.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Expr.h"
 #include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/Tooling/Refactoring/RefactoringAction.h"
-#include "clang/Tooling/Refactoring/RefactoringActionRules.h"
-#include "clang/Tooling/Refactoring/RefactoringOptions.h"
 
 namespace clang {
 namespace tooling {
@@ -44,58 +42,43 @@ bool isSimpleExpression(const Expr *E) {
   }
 }
 
-class ExtractableCodeSelectionRequirement final
-    : public CodeRangeASTSelectionRequirement {
-public:
-  Expected
-  evaluate(RefactoringRuleContext &Context) const {
-    Expected Selection =
-        CodeRangeASTSelectionRequirement::evaluate(Context);
-    if (!Selection)
-      return Selection.takeError();
-    CodeRangeASTSelection &Code = *Selection;
-
-    // We would like to extract code out of functions/methods/blocks.
-    // Prohibit extraction from things like global variable / field
-    // initializers and other top-level expressions.
-    if (!Code.isInFunctionLikeBodyOfCode())
-      return Context.createDiagnosticError(
-          diag::err_refactor_code_outside_of_function);
-
-    // Avoid extraction of simple literals and references.
-    if (Code.size() == 1 && isSimpleExpression(dyn_cast(Code[0])))
-      return Context.createDiagnosticError(
-          diag::err_refactor_extract_simple_expression);
-
-    // FIXME (Alex L): Prohibit extraction of Objective-C property setters.
-    return Selection;
-  }
-};
-
-class ExtractFunction final : public SourceChangeRefactoringRule {
-public:
-  ExtractFunction(CodeRangeASTSelection Code, Optional DeclName)
-      : Code(std::move(Code)),
-        DeclName(DeclName ? std::move(*DeclName) : "extracted") {}
-
-  Expected
-  createSourceReplacements(RefactoringRuleContext &Context) override;
-
-private:
-  CodeRangeASTSelection Code;
-
-  // FIXME: Account for naming collisions:
-  //  - error when name is specified by user.
-  //  - rename to "extractedN" when name is implicit.
-  std::string DeclName;
-};
-
 SourceLocation computeFunctionExtractionLocation(const Decl *D) {
   // FIXME (Alex L): Method -> function extraction should place function before
   // C++ record if the method is defined inside the record.
   return D->getLocStart();
 }
 
+} // end anonymous namespace
+
+const RefactoringDescriptor &ExtractFunction::describe() {
+  static const RefactoringDescriptor Descriptor = {
+      "extract-function",
+      "Extract Function",
+      "(WIP action; use with caution!) Extracts code into a new function",
+  };
+  return Descriptor;
+}
+
+Expected
+ExtractFunction::initiate(RefactoringRuleContext &Context,
+                          CodeRangeASTSelection Code,
+                          Optional DeclName) {
+  // We would like to extract code out of functions/methods/blocks.
+  // Prohibit extraction from things like global variable / field
+  // initializers and other top-level expressions.
+  if (!Code.isInFunctionLikeBodyOfCode())
+    return Context.createDiagnosticError(
+        diag::err_refactor_code_outside_of_function);
+
+  // Avoid extraction of simple literals and references.
+  if (Code.size() == 1 && isSimpleExpression(dyn_cast(Code[0])))
+    return Context.createDiagnosticError(
+        diag::err_refactor_extract_simple_expression);
+
+  // FIXME (Alex L): Prohibit extraction of Objective-C property setters.
+  return ExtractFunction(std::move(Code), DeclName);
+}
+
 // FIXME: Support C++ method extraction.
 // FIXME: Support Objective-C method extraction.
 Expected
@@ -194,39 +177,5 @@ ExtractFunction::createSourceReplacements(RefactoringRuleContext &Context) {
   return AtomicChanges{std::move(Change)};
 }
 
-class DeclNameOption final : public OptionalRefactoringOption {
-public:
-  StringRef getName() const { return "name"; }
-  StringRef getDescription() const {
-    return "Name of the extracted declaration";
-  }
-};
-
-class ExtractRefactoring final : public RefactoringAction {
-public:
-  StringRef getCommand() const override { return "extract"; }
-
-  StringRef getDescription() const override {
-    return "(WIP action; use with caution!) Extracts code into a new function "
-           "/ method / variable";
-  }
-
-  /// Returns a set of refactoring actions rules that are defined by this
-  /// action.
-  RefactoringActionRules createActionRules() const override {
-    RefactoringActionRules Rules;
-    Rules.push_back(createRefactoringActionRule(
-        ExtractableCodeSelectionRequirement(),
-        OptionRequirement()));
-    return Rules;
-  }
-};
-
-} // end anonymous namespace
-
-std::unique_ptr createExtractAction() {
-  return llvm::make_unique();
-}
-
 } // end namespace tooling
 } // end namespace clang
diff --git a/lib/Tooling/Refactoring/RefactoringActions.cpp b/lib/Tooling/Refactoring/RefactoringActions.cpp
index 25f055b727..73a3118396 100644
--- a/lib/Tooling/Refactoring/RefactoringActions.cpp
+++ b/lib/Tooling/Refactoring/RefactoringActions.cpp
@@ -7,21 +7,80 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/Tooling/Refactoring/Extract/Extract.h"
 #include "clang/Tooling/Refactoring/RefactoringAction.h"
+#include "clang/Tooling/Refactoring/RefactoringOptions.h"
+#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
 
 namespace clang {
 namespace tooling {
 
-// Forward declare the individual create*Action functions.
-#define REFACTORING_ACTION(Name)                                               \
-  std::unique_ptr create##Name##Action();
-#include "clang/Tooling/Refactoring/RefactoringActionRegistry.def"
+namespace {
+
+class DeclNameOption final : public OptionalRefactoringOption {
+public:
+  StringRef getName() const { return "name"; }
+  StringRef getDescription() const {
+    return "Name of the extracted declaration";
+  }
+};
+
+// FIXME: Rewrite the Actions to avoid duplication of descriptions/names with
+// rules.
+class ExtractRefactoring final : public RefactoringAction {
+public:
+  StringRef getCommand() const override { return "extract"; }
+
+  StringRef getDescription() const override {
+    return "(WIP action; use with caution!) Extracts code into a new function";
+  }
+
+  /// Returns a set of refactoring actions rules that are defined by this
+  /// action.
+  RefactoringActionRules createActionRules() const override {
+    RefactoringActionRules Rules;
+    Rules.push_back(createRefactoringActionRule(
+        CodeRangeASTSelectionRequirement(),
+        OptionRequirement()));
+    return Rules;
+  }
+};
+
+class NewNameOption : public RequiredRefactoringOption {
+public:
+  StringRef getName() const override { return "new-name"; }
+  StringRef getDescription() const override {
+    return "The new name to change the symbol to";
+  }
+};
+
+// FIXME: Rewrite the Actions to avoid duplication of descriptions/names with
+// rules.
+class LocalRename final : public RefactoringAction {
+public:
+  StringRef getCommand() const override { return "local-rename"; }
+
+  StringRef getDescription() const override {
+    return "Finds and renames symbols in code with no indexer support";
+  }
+
+  /// Returns a set of refactoring actions rules that are defined by this
+  /// action.
+  RefactoringActionRules createActionRules() const override {
+    RefactoringActionRules Rules;
+    Rules.push_back(createRefactoringActionRule(
+        SourceRangeSelectionRequirement(), OptionRequirement()));
+    return Rules;
+  }
+};
+
+} // end anonymous namespace
 
 std::vector> createRefactoringActions() {
   std::vector> Actions;
 
-#define REFACTORING_ACTION(Name) Actions.push_back(create##Name##Action());
-#include "clang/Tooling/Refactoring/RefactoringActionRegistry.def"
+  Actions.push_back(llvm::make_unique());
+  Actions.push_back(llvm::make_unique());
 
   return Actions;
 }
diff --git a/lib/Tooling/Refactoring/Rename/RenamingAction.cpp b/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
index 28912c3e13..210b45b79e 100644
--- a/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
+++ b/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
@@ -41,22 +41,6 @@ namespace tooling {
 
 namespace {
 
-class SymbolSelectionRequirement : public SourceRangeSelectionRequirement {
-public:
-  Expected evaluate(RefactoringRuleContext &Context) const {
-    Expected Selection =
-        SourceRangeSelectionRequirement::evaluate(Context);
-    if (!Selection)
-      return Selection.takeError();
-    const NamedDecl *ND =
-        getNamedDeclAt(Context.getASTContext(), Selection->getBegin());
-    if (!ND)
-      return Context.createDiagnosticError(
-          Selection->getBegin(), diag::err_refactor_selection_no_symbol);
-    return getCanonicalSymbolDeclaration(ND);
-  }
-};
-
 class OccurrenceFinder final : public FindSymbolOccurrencesRefactoringRule {
 public:
   OccurrenceFinder(const NamedDecl *ND) : ND(ND) {}
@@ -74,50 +58,38 @@ private:
   const NamedDecl *ND;
 };
 
-class RenameOccurrences final : public SourceChangeRefactoringRule {
-public:
-  RenameOccurrences(const NamedDecl *ND, std::string NewName)
-      : Finder(ND), NewName(std::move(NewName)) {}
-
-  Expected
-  createSourceReplacements(RefactoringRuleContext &Context) override {
-    Expected Occurrences =
-        Finder.findSymbolOccurrences(Context);
-    if (!Occurrences)
-      return Occurrences.takeError();
-    // FIXME: Verify that the new name is valid.
-    SymbolName Name(NewName);
-    return createRenameReplacements(
-        *Occurrences, Context.getASTContext().getSourceManager(), Name);
-  }
-
-private:
-  OccurrenceFinder Finder;
-  std::string NewName;
-};
-
-class LocalRename final : public RefactoringAction {
-public:
-  StringRef getCommand() const override { return "local-rename"; }
-
-  StringRef getDescription() const override {
-    return "Finds and renames symbols in code with no indexer support";
-  }
+} // end anonymous namespace
 
-  /// Returns a set of refactoring actions rules that are defined by this
-  /// action.
-  RefactoringActionRules createActionRules() const override {
-    RefactoringActionRules Rules;
-    Rules.push_back(createRefactoringActionRule(
-        SymbolSelectionRequirement(), OptionRequirement()));
-    return Rules;
-  }
-};
+const RefactoringDescriptor &RenameOccurrences::describe() {
+  static const RefactoringDescriptor Descriptor = {
+      "local-rename",
+      "Rename",
+      "Finds and renames symbols in code with no indexer support",
+  };
+  return Descriptor;
+}
 
-} // end anonymous namespace
+Expected
+RenameOccurrences::initiate(RefactoringRuleContext &Context,
+                            SourceRange SelectionRange, std::string NewName) {
+  const NamedDecl *ND =
+      getNamedDeclAt(Context.getASTContext(), SelectionRange.getBegin());
+  if (!ND)
+    return Context.createDiagnosticError(
+        SelectionRange.getBegin(), diag::err_refactor_selection_no_symbol);
+  return RenameOccurrences(getCanonicalSymbolDeclaration(ND), NewName);
+}
 
-std::unique_ptr createLocalRenameAction() {
-  return llvm::make_unique();
+Expected
+RenameOccurrences::createSourceReplacements(RefactoringRuleContext &Context) {
+  Expected Occurrences =
+      OccurrenceFinder(ND).findSymbolOccurrences(Context);
+  if (!Occurrences)
+    return Occurrences.takeError();
+  // FIXME: Verify that the new name is valid.
+  SymbolName Name(NewName);
+  return createRenameReplacements(
+      *Occurrences, Context.getASTContext().getSourceManager(), Name);
 }
 
 Expected>
diff --git a/unittests/Tooling/RefactoringActionRulesTest.cpp b/unittests/Tooling/RefactoringActionRulesTest.cpp
index 132a3a4496..f0b6466fec 100644
--- a/unittests/Tooling/RefactoringActionRulesTest.cpp
+++ b/unittests/Tooling/RefactoringActionRulesTest.cpp
@@ -10,7 +10,8 @@
 #include "ReplacementTest.h"
 #include "RewriterTestContext.h"
 #include "clang/Tooling/Refactoring.h"
-#include "clang/Tooling/Refactoring/RefactoringActionRules.h"
+#include "clang/Tooling/Refactoring/Extract/Extract.h"
+#include "clang/Tooling/Refactoring/RefactoringAction.h"
 #include "clang/Tooling/Refactoring/RefactoringDiagnostic.h"
 #include "clang/Tooling/Refactoring/Rename/SymbolName.h"
 #include "clang/Tooling/Tooling.h"
@@ -63,6 +64,12 @@ TEST_F(RefactoringActionRulesTest, MyFirstRefactoringRule) {
     ReplaceAWithB(std::pair Selection)
         : Selection(Selection) {}
 
+    static Expected
+    initiate(RefactoringRuleContext &Cotnext,
+             std::pair Selection) {
+      return ReplaceAWithB(Selection);
+    }
+
     Expected
     createSourceReplacements(RefactoringRuleContext &Context) {
       const SourceManager &SM = Context.getSources();
@@ -141,6 +148,11 @@ TEST_F(RefactoringActionRulesTest, MyFirstRefactoringRule) {
 TEST_F(RefactoringActionRulesTest, ReturnError) {
   class ErrorRule : public SourceChangeRefactoringRule {
   public:
+    static Expected initiate(RefactoringRuleContext &,
+                                        SourceRange R) {
+      return ErrorRule(R);
+    }
+
     ErrorRule(SourceRange R) {}
     Expected createSourceReplacements(RefactoringRuleContext &) {
       return llvm::make_error(
@@ -191,6 +203,11 @@ TEST_F(RefactoringActionRulesTest, ReturnSymbolOccurrences) {
   public:
     FindOccurrences(SourceRange Selection) : Selection(Selection) {}
 
+    static Expected initiate(RefactoringRuleContext &,
+                                              SourceRange Selection) {
+      return FindOccurrences(Selection);
+    }
+
     Expected
     findSymbolOccurrences(RefactoringRuleContext &) override {
       SymbolOccurrences Occurrences;
@@ -219,4 +236,13 @@ TEST_F(RefactoringActionRulesTest, ReturnSymbolOccurrences) {
             SourceRange(Cursor, Cursor.getLocWithOffset(strlen("test"))));
 }
 
+TEST_F(RefactoringActionRulesTest, EditorCommandBinding) {
+  const RefactoringDescriptor &Descriptor = ExtractFunction::describe();
+  EXPECT_EQ(Descriptor.Name, "extract-function");
+  EXPECT_EQ(
+      Descriptor.Description,
+      "(WIP action; use with caution!) Extracts code into a new function");
+  EXPECT_EQ(Descriptor.Title, "Extract Function");
+}
+
 } // end anonymous namespace
-- 
GitLab


From d86c46ef9674cc4f45d296ebd48263588ca3744c Mon Sep 17 00:00:00 2001
From: Erich Keane 
Date: Fri, 27 Oct 2017 18:29:02 +0000
Subject: [PATCH 0110/1682] Remove x86,x86_32/64 from isValidFeatureName

These are not valid values for this, and are pretty
non-sensical, since LLVM doesn't understand them.

Differential Revision: https://reviews.llvm.org/D39378


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316781 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Basic/Targets/X86.cpp | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/lib/Basic/Targets/X86.cpp b/lib/Basic/Targets/X86.cpp
index c986363b23..8338e510dc 100644
--- a/lib/Basic/Targets/X86.cpp
+++ b/lib/Basic/Targets/X86.cpp
@@ -1169,9 +1169,6 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const {
       .Case("sse4.2", true)
       .Case("sse4a", true)
       .Case("tbm", true)
-      .Case("x86", true)
-      .Case("x86_32", true)
-      .Case("x86_64", true)
       .Case("xop", true)
       .Case("xsave", true)
       .Case("xsavec", true)
-- 
GitLab


From 0cb2a76a4f9397e6b33d60159f0197d1bcb898e9 Mon Sep 17 00:00:00 2001
From: Erich Keane 
Date: Fri, 27 Oct 2017 18:32:23 +0000
Subject: [PATCH 0111/1682] Filter out invalid 'target' items from being passed
 to LLVM

Craig noticed that CodeGen wasn't properly ignoring the
values sent to the target attribute. This patch ignores
them.

This patch also sets the 'default' for this checking to
'supported', since only X86 has implemented the support
for checking valid CPU names and Feature Names.

One test was changed to i686, since it uses a lakemont,
which would otherwise be prohibited in x86_64.

Differential Revision: https://reviews.llvm.org/D39357



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316783 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Basic/TargetInfo.h |  4 ++--
 lib/Basic/Targets/X86.cpp        |  1 +
 lib/CodeGen/CGCall.cpp           |  5 +++--
 lib/CodeGen/CodeGenModule.cpp    | 13 +++++++++++--
 test/CodeGen/attr-target-x86.c   | 16 ++++++++--------
 5 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 046c3317b5..f80f6b7a6b 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -861,7 +861,7 @@ public:
 
   /// brief Determine whether this TargetInfo supports the given CPU name.
   virtual bool isValidCPUName(StringRef Name) const {
-    return false;
+    return true;
   }
 
   /// \brief Use the specified ABI.
@@ -888,7 +888,7 @@ public:
 
   /// \brief Determine whether this TargetInfo supports the given feature.
   virtual bool isValidFeatureName(StringRef Feature) const {
-    return false;
+    return true;
   }
 
   /// \brief Perform initialization based on the user configured
diff --git a/lib/Basic/Targets/X86.cpp b/lib/Basic/Targets/X86.cpp
index 8338e510dc..93dcd4e234 100644
--- a/lib/Basic/Targets/X86.cpp
+++ b/lib/Basic/Targets/X86.cpp
@@ -1169,6 +1169,7 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const {
       .Case("sse4.2", true)
       .Case("sse4a", true)
       .Case("tbm", true)
+      .Case("x87", true)
       .Case("xop", true)
       .Case("xsave", true)
       .Case("xsavec", true)
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index d022c99711..c19fb097f6 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -1885,10 +1885,11 @@ void CodeGenModule::ConstructAttributeList(
       // the function.
       const auto *TD = FD->getAttr();
       TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse();
-      if (ParsedAttr.Architecture != "")
+      if (ParsedAttr.Architecture != "" &&
+          getTarget().isValidCPUName(ParsedAttr.Architecture))
         TargetCPU = ParsedAttr.Architecture;
       if (TargetCPU != "")
-        FuncAttrs.addAttribute("target-cpu", TargetCPU);
+         FuncAttrs.addAttribute("target-cpu", TargetCPU);
       if (!Features.empty()) {
         std::sort(Features.begin(), Features.end());
         FuncAttrs.addAttribute(
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 4be2a94b16..4f7d6eaed6 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -4582,14 +4582,23 @@ void CodeGenModule::getFunctionFeatureMap(llvm::StringMap &FeatureMap,
     // If we have a TargetAttr build up the feature map based on that.
     TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse();
 
+    ParsedAttr.Features.erase(
+        llvm::remove_if(ParsedAttr.Features,
+                        [&](const std::string &Feat) {
+                          return !Target.isValidFeatureName(
+                              StringRef{Feat}.substr(1));
+                        }),
+        ParsedAttr.Features.end());
+
     // Make a copy of the features as passed on the command line into the
     // beginning of the additional features from the function to override.
     ParsedAttr.Features.insert(ParsedAttr.Features.begin(),
                             Target.getTargetOpts().FeaturesAsWritten.begin(),
                             Target.getTargetOpts().FeaturesAsWritten.end());
 
-    if (ParsedAttr.Architecture != "")
-      TargetCPU = ParsedAttr.Architecture ;
+    if (ParsedAttr.Architecture != "" &&
+        Target.isValidCPUName(ParsedAttr.Architecture))
+      TargetCPU = ParsedAttr.Architecture;
 
     // Now populate the feature map, first with the TargetCPU which is either
     // the default or a new one from the target attribute string. Then we'll use
diff --git a/test/CodeGen/attr-target-x86.c b/test/CodeGen/attr-target-x86.c
index a1cb4518dc..6ec2d6578d 100644
--- a/test/CodeGen/attr-target-x86.c
+++ b/test/CodeGen/attr-target-x86.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -target-cpu x86-64 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i686-linux-gnu -target-cpu i686 -emit-llvm %s -o - | FileCheck %s
 
 int baz(int a) { return 4; }
 
@@ -19,7 +19,7 @@ int __attribute__((target("no-aes, arch=ivybridge"))) qax(int a) { return 4; }
 
 int __attribute__((target("no-mmx"))) qq(int a) { return 40; }
 
-int __attribute__((target("arch=lakemont"))) lake(int a) { return 4; }
+int __attribute__((target("arch=lakemont,mmx"))) lake(int a) { return 4; }
 
 // Check that we emit the additional subtarget and cpu features for foo and not for baz or bar.
 // CHECK: baz{{.*}} #0
@@ -36,11 +36,11 @@ int __attribute__((target("arch=lakemont"))) lake(int a) { return 4; }
 // CHECK: qax{{.*}} #5
 // CHECK: qq{{.*}} #6
 // CHECK: lake{{.*}} #7
-// CHECK: #0 = {{.*}}"target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87"
+// CHECK: #0 = {{.*}}"target-cpu"="i686" "target-features"="+x87"
 // CHECK: #1 = {{.*}}"target-cpu"="ivybridge" "target-features"="+aes,+avx,+cx16,+f16c,+fsgsbase,+fxsr,+mmx,+pclmul,+popcnt,+rdrnd,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"
-// CHECK: #2 = {{.*}}"target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+x87,-aes,-avx,-avx2,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512ifma,-avx512pf,-avx512vbmi,-avx512vl,-avx512vpopcntdq,-f16c,-fma,-fma4,-pclmul,-sha,-sse2,-sse3,-sse4.1,-sse4.2,-sse4a,-ssse3,-xop,-xsave,-xsaveopt"
-// CHECK: #3 = {{.*}}"target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"
-// CHECK: #4 = {{.*}}"target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87,-avx,-avx2,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512ifma,-avx512pf,-avx512vbmi,-avx512vl,-avx512vpopcntdq,-f16c,-fma,-fma4,-sse4.1,-sse4.2,-xop,-xsave,-xsaveopt"
+// CHECK: #2 = {{.*}}"target-cpu"="i686" "target-features"="+x87,-aes,-avx,-avx2,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512ifma,-avx512pf,-avx512vbmi,-avx512vl,-avx512vpopcntdq,-f16c,-fma,-fma4,-pclmul,-sha,-sse2,-sse3,-sse4.1,-sse4.2,-sse4a,-ssse3,-xop,-xsave,-xsaveopt"
+// CHECK: #3 = {{.*}}"target-cpu"="i686" "target-features"="+mmx,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"
+// CHECK: #4 = {{.*}}"target-cpu"="i686" "target-features"="+x87,-avx,-avx2,-avx512bw,-avx512cd,-avx512dq,-avx512er,-avx512f,-avx512ifma,-avx512pf,-avx512vbmi,-avx512vl,-avx512vpopcntdq,-f16c,-fma,-fma4,-sse4.1,-sse4.2,-xop,-xsave,-xsaveopt"
 // CHECK: #5 = {{.*}}"target-cpu"="ivybridge" "target-features"="+avx,+cx16,+f16c,+fsgsbase,+fxsr,+mmx,+pclmul,+popcnt,+rdrnd,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt,-aes"
-// CHECK: #6 = {{.*}}"target-cpu"="x86-64" "target-features"="+fxsr,+sse,+sse2,+x87,-3dnow,-3dnowa,-mmx"
-// CHECK: #7 = {{.*}}"target-cpu"="lakemont" "target-features"="+mmx,+sse,+sse2"
+// CHECK: #6 = {{.*}}"target-cpu"="i686" "target-features"="+x87,-3dnow,-3dnowa,-mmx"
+// CHECK: #7 = {{.*}}"target-cpu"="lakemont" "target-features"="+mmx"
-- 
GitLab


From 5a3b980ac2b255fcbb006f820218d4935f98e271 Mon Sep 17 00:00:00 2001
From: Erich Keane 
Date: Fri, 27 Oct 2017 18:45:06 +0000
Subject: [PATCH 0112/1682] Replace a few usages of llvm::join with
 range-version[NFC]

I noticed a few usages of llvm::join that were using
begin/end rather than just the range version.  This patch
just replaces those.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316784 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/CodeGen/CGCall.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index c19fb097f6..971455a873 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -1742,7 +1742,7 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone,
     std::vector &Recips = getTarget().getTargetOpts().Reciprocals;
     if (!Recips.empty())
       FuncAttrs.addAttribute("reciprocal-estimates",
-                             llvm::join(Recips.begin(), Recips.end(), ","));
+                             llvm::join(Recips, ","));
 
     if (CodeGenOpts.StackRealignment)
       FuncAttrs.addAttribute("stackrealign");
@@ -1894,7 +1894,7 @@ void CodeGenModule::ConstructAttributeList(
         std::sort(Features.begin(), Features.end());
         FuncAttrs.addAttribute(
             "target-features",
-            llvm::join(Features.begin(), Features.end(), ","));
+            llvm::join(Features, ","));
       }
     } else {
       // Otherwise just add the existing target cpu and target features to the
@@ -1906,7 +1906,7 @@ void CodeGenModule::ConstructAttributeList(
         std::sort(Features.begin(), Features.end());
         FuncAttrs.addAttribute(
             "target-features",
-            llvm::join(Features.begin(), Features.end(), ","));
+            llvm::join(Features, ","));
       }
     }
   }
-- 
GitLab


From 4cd56764e034749c30dbdf2c3a1105c739d45c8c Mon Sep 17 00:00:00 2001
From: David Blaikie 
Date: Fri, 27 Oct 2017 20:40:44 +0000
Subject: [PATCH 0113/1682] ASTContext.h: Modularize/fix ODR violations by
 removing 'static' from inline functions in headers

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316791 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/AST/ASTContext.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 09035be021..1498c366d7 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -2779,13 +2779,13 @@ public:
 };
 
 /// \brief Utility function for constructing a nullary selector.
-static inline Selector GetNullarySelector(StringRef name, ASTContext& Ctx) {
+inline Selector GetNullarySelector(StringRef name, ASTContext &Ctx) {
   IdentifierInfo* II = &Ctx.Idents.get(name);
   return Ctx.Selectors.getSelector(0, &II);
 }
 
 /// \brief Utility function for constructing an unary selector.
-static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) {
+inline Selector GetUnarySelector(StringRef name, ASTContext &Ctx) {
   IdentifierInfo* II = &Ctx.Idents.get(name);
   return Ctx.Selectors.getSelector(1, &II);
 }
-- 
GitLab


From befc935d638b53d222f18ef4db6cb7777e7ab3d9 Mon Sep 17 00:00:00 2001
From: David Blaikie 
Date: Fri, 27 Oct 2017 20:40:45 +0000
Subject: [PATCH 0114/1682] CharInfo.h: Modularize/fix ODR violations by making
 inline functions in header not static

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316792 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Basic/CharInfo.h | 42 +++++++++++++++++-----------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/include/clang/Basic/CharInfo.h b/include/clang/Basic/CharInfo.h
index dd9c55431e..cc27bbb48e 100644
--- a/include/clang/Basic/CharInfo.h
+++ b/include/clang/Basic/CharInfo.h
@@ -40,14 +40,14 @@ namespace charinfo {
 } // end namespace charinfo
 
 /// Returns true if this is an ASCII character.
-LLVM_READNONE static inline bool isASCII(char c) {
+LLVM_READNONE inline bool isASCII(char c) {
   return static_cast(c) <= 127;
 }
 
 /// Returns true if this is a valid first character of a C identifier,
 /// which is [a-zA-Z_].
-LLVM_READONLY static inline bool isIdentifierHead(unsigned char c,
-                                                  bool AllowDollar = false) {
+LLVM_READONLY inline bool isIdentifierHead(unsigned char c,
+                                           bool AllowDollar = false) {
   using namespace charinfo;
   if (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_UNDER))
     return true;
@@ -56,8 +56,8 @@ LLVM_READONLY static inline bool isIdentifierHead(unsigned char c,
 
 /// Returns true if this is a body character of a C identifier,
 /// which is [a-zA-Z0-9_].
-LLVM_READONLY static inline bool isIdentifierBody(unsigned char c,
-                                                  bool AllowDollar = false) {
+LLVM_READONLY inline bool isIdentifierBody(unsigned char c,
+                                           bool AllowDollar = false) {
   using namespace charinfo;
   if (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_DIGIT|CHAR_UNDER))
     return true;
@@ -68,7 +68,7 @@ LLVM_READONLY static inline bool isIdentifierBody(unsigned char c,
 /// ' ', '\\t', '\\f', '\\v'.
 ///
 /// Note that this returns false for '\\0'.
-LLVM_READONLY static inline bool isHorizontalWhitespace(unsigned char c) {
+LLVM_READONLY inline bool isHorizontalWhitespace(unsigned char c) {
   using namespace charinfo;
   return (InfoTable[c] & (CHAR_HORZ_WS|CHAR_SPACE)) != 0;
 }
@@ -76,7 +76,7 @@ LLVM_READONLY static inline bool isHorizontalWhitespace(unsigned char c) {
 /// Returns true if this character is vertical ASCII whitespace: '\\n', '\\r'.
 ///
 /// Note that this returns false for '\\0'.
-LLVM_READONLY static inline bool isVerticalWhitespace(unsigned char c) {
+LLVM_READONLY inline bool isVerticalWhitespace(unsigned char c) {
   using namespace charinfo;
   return (InfoTable[c] & CHAR_VERT_WS) != 0;
 }
@@ -85,43 +85,43 @@ LLVM_READONLY static inline bool isVerticalWhitespace(unsigned char c) {
 /// ' ', '\\t', '\\f', '\\v', '\\n', '\\r'.
 ///
 /// Note that this returns false for '\\0'.
-LLVM_READONLY static inline bool isWhitespace(unsigned char c) {
+LLVM_READONLY inline bool isWhitespace(unsigned char c) {
   using namespace charinfo;
   return (InfoTable[c] & (CHAR_HORZ_WS|CHAR_VERT_WS|CHAR_SPACE)) != 0;
 }
 
 /// Return true if this character is an ASCII digit: [0-9]
-LLVM_READONLY static inline bool isDigit(unsigned char c) {
+LLVM_READONLY inline bool isDigit(unsigned char c) {
   using namespace charinfo;
   return (InfoTable[c] & CHAR_DIGIT) != 0;
 }
 
 /// Return true if this character is a lowercase ASCII letter: [a-z]
-LLVM_READONLY static inline bool isLowercase(unsigned char c) {
+LLVM_READONLY inline bool isLowercase(unsigned char c) {
   using namespace charinfo;
   return (InfoTable[c] & CHAR_LOWER) != 0;
 }
 
 /// Return true if this character is an uppercase ASCII letter: [A-Z]
-LLVM_READONLY static inline bool isUppercase(unsigned char c) {
+LLVM_READONLY inline bool isUppercase(unsigned char c) {
   using namespace charinfo;
   return (InfoTable[c] & CHAR_UPPER) != 0;
 }
 
 /// Return true if this character is an ASCII letter: [a-zA-Z]
-LLVM_READONLY static inline bool isLetter(unsigned char c) {
+LLVM_READONLY inline bool isLetter(unsigned char c) {
   using namespace charinfo;
   return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER)) != 0;
 }
 
 /// Return true if this character is an ASCII letter or digit: [a-zA-Z0-9]
-LLVM_READONLY static inline bool isAlphanumeric(unsigned char c) {
+LLVM_READONLY inline bool isAlphanumeric(unsigned char c) {
   using namespace charinfo;
   return (InfoTable[c] & (CHAR_DIGIT|CHAR_UPPER|CHAR_LOWER)) != 0;
 }
 
 /// Return true if this character is an ASCII hex digit: [0-9a-fA-F]
-LLVM_READONLY static inline bool isHexDigit(unsigned char c) {
+LLVM_READONLY inline bool isHexDigit(unsigned char c) {
   using namespace charinfo;
   return (InfoTable[c] & (CHAR_DIGIT|CHAR_XLETTER)) != 0;
 }
@@ -129,7 +129,7 @@ LLVM_READONLY static inline bool isHexDigit(unsigned char c) {
 /// Return true if this character is an ASCII punctuation character.
 ///
 /// Note that '_' is both a punctuation character and an identifier character!
-LLVM_READONLY static inline bool isPunctuation(unsigned char c) {
+LLVM_READONLY inline bool isPunctuation(unsigned char c) {
   using namespace charinfo;
   return (InfoTable[c] & (CHAR_UNDER|CHAR_PERIOD|CHAR_RAWDEL|CHAR_PUNCT)) != 0;
 }
@@ -137,7 +137,7 @@ LLVM_READONLY static inline bool isPunctuation(unsigned char c) {
 /// Return true if this character is an ASCII printable character; that is, a
 /// character that should take exactly one column to print in a fixed-width
 /// terminal.
-LLVM_READONLY static inline bool isPrintable(unsigned char c) {
+LLVM_READONLY inline bool isPrintable(unsigned char c) {
   using namespace charinfo;
   return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD|CHAR_PUNCT|
                           CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL|CHAR_SPACE)) != 0;
@@ -145,14 +145,14 @@ LLVM_READONLY static inline bool isPrintable(unsigned char c) {
 
 /// Return true if this is the body character of a C preprocessing number,
 /// which is [a-zA-Z0-9_.].
-LLVM_READONLY static inline bool isPreprocessingNumberBody(unsigned char c) {
+LLVM_READONLY inline bool isPreprocessingNumberBody(unsigned char c) {
   using namespace charinfo;
   return (InfoTable[c] &
           (CHAR_UPPER|CHAR_LOWER|CHAR_DIGIT|CHAR_UNDER|CHAR_PERIOD)) != 0;
 }
 
 /// Return true if this is the body character of a C++ raw string delimiter.
-LLVM_READONLY static inline bool isRawStringDelimBody(unsigned char c) {
+LLVM_READONLY inline bool isRawStringDelimBody(unsigned char c) {
   using namespace charinfo;
   return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD|
                           CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL)) != 0;
@@ -162,7 +162,7 @@ LLVM_READONLY static inline bool isRawStringDelimBody(unsigned char c) {
 /// Converts the given ASCII character to its lowercase equivalent.
 ///
 /// If the character is not an uppercase character, it is returned as is.
-LLVM_READONLY static inline char toLowercase(char c) {
+LLVM_READONLY inline char toLowercase(char c) {
   if (isUppercase(c))
     return c + 'a' - 'A';
   return c;
@@ -171,7 +171,7 @@ LLVM_READONLY static inline char toLowercase(char c) {
 /// Converts the given ASCII character to its uppercase equivalent.
 ///
 /// If the character is not a lowercase character, it is returned as is.
-LLVM_READONLY static inline char toUppercase(char c) {
+LLVM_READONLY inline char toUppercase(char c) {
   if (isLowercase(c))
     return c + 'A' - 'a';
   return c;
@@ -182,7 +182,7 @@ LLVM_READONLY static inline char toUppercase(char c) {
 ///
 /// Note that this is a very simple check; it does not accept '$' or UCNs as
 /// valid identifier characters.
-LLVM_READONLY static inline bool isValidIdentifier(StringRef S) {
+LLVM_READONLY inline bool isValidIdentifier(StringRef S) {
   if (S.empty() || !isIdentifierHead(S[0]))
     return false;
 
-- 
GitLab


From 8ce4920de009cfa00b4748417695b8af611639d8 Mon Sep 17 00:00:00 2001
From: David Blaikie 
Date: Fri, 27 Oct 2017 20:40:45 +0000
Subject: [PATCH 0115/1682] Sanitizers.h: Modularize/Fix ODR violations by
 making inline functions non-static

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316793 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Basic/Sanitizers.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/clang/Basic/Sanitizers.h b/include/clang/Basic/Sanitizers.h
index 5317720095..1b936c7d11 100644
--- a/include/clang/Basic/Sanitizers.h
+++ b/include/clang/Basic/Sanitizers.h
@@ -80,7 +80,7 @@ SanitizerMask parseSanitizerValue(StringRef Value, bool AllowGroups);
 SanitizerMask expandSanitizerGroups(SanitizerMask Kinds);
 
 /// Return the sanitizers which do not affect preprocessing.
-static inline SanitizerMask getPPTransparentSanitizers() {
+inline SanitizerMask getPPTransparentSanitizers() {
   return SanitizerKind::CFI | SanitizerKind::Integer |
          SanitizerKind::Nullability | SanitizerKind::Undefined;
 }
-- 
GitLab


From d6689452f55d5a852bff083e2855e5abcde49997 Mon Sep 17 00:00:00 2001
From: David Blaikie 
Date: Fri, 27 Oct 2017 20:40:46 +0000
Subject: [PATCH 0116/1682] StaticAnalyzer: Modularize/fix ODR violations
 making functions inline but non-static in headers

Also move these out of the llvm namespace & rely on ADL as is
appropriate for these op<< overloads.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316794 91177308-0d34-0410-b5e6-96231b3b80d8
---
 .../StaticAnalyzer/Core/PathSensitive/MemRegion.h | 15 ++++++---------
 .../StaticAnalyzer/Core/PathSensitive/SVals.h     |  9 ++++-----
 .../StaticAnalyzer/Core/PathSensitive/SymExpr.h   |  6 ++++++
 .../Core/PathSensitive/SymbolManager.h            |  7 -------
 4 files changed, 16 insertions(+), 21 deletions(-)

diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index a827a21ed1..8ab6656230 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -1412,21 +1412,18 @@ public:
   bool hasTrait(SymbolRef Sym, InvalidationKinds IK) const;
   bool hasTrait(const MemRegion *MR, InvalidationKinds IK) const;
 };
-  
-} // end GR namespace
-
-} // end clang namespace
 
 //===----------------------------------------------------------------------===//
 // Pretty-printing regions.
 //===----------------------------------------------------------------------===//
-
-namespace llvm {
-static inline raw_ostream &operator<<(raw_ostream &os,
-                                      const clang::ento::MemRegion* R) {
+inline raw_ostream &operator<<(raw_ostream &os,
+                               const clang::ento::MemRegion *R) {
   R->dumpToStream(os);
   return os;
 }
-} // end llvm namespace
+
+} // namespace ento
+
+} // namespace clang
 
 #endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 935f001832..af1af4590d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -198,6 +198,10 @@ public:
   }
 };
 
+inline raw_ostream &operator<<(raw_ostream &os, clang::ento::SVal V) {
+  V.dumpToStream(os);
+  return os;
+}
 
 class UndefinedVal : public SVal {
 public:
@@ -622,11 +626,6 @@ private:
 } // end clang namespace
 
 namespace llvm {
-static inline raw_ostream &operator<<(raw_ostream &os,
-                                            clang::ento::SVal V) {
-  V.dumpToStream(os);
-  return os;
-}
 
 template  struct isPodLike;
 template <> struct isPodLike {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
index f72033955e..9780d01447 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h
@@ -98,6 +98,12 @@ public:
   virtual const MemRegion *getOriginRegion() const { return nullptr; }
 };
 
+inline raw_ostream &operator<<(raw_ostream &os,
+                               const clang::ento::SymExpr *SE) {
+  SE->dumpToStream(os);
+  return os;
+}
+
 typedef const SymExpr *SymbolRef;
 typedef SmallVector SymbolRefSmallVectorTy;
 
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 34112f8dc5..7d2e5ad8ba 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -633,11 +633,4 @@ public:
 
 } // end clang namespace
 
-namespace llvm {
-static inline raw_ostream &operator<<(raw_ostream &os,
-                                      const clang::ento::SymExpr *SE) {
-  SE->dumpToStream(os);
-  return os;
-}
-} // end llvm namespace
 #endif
-- 
GitLab


From 0d8450b358fac348761b11924a92e8d269389cb1 Mon Sep 17 00:00:00 2001
From: George Karpenkov 
Date: Fri, 27 Oct 2017 22:39:54 +0000
Subject: [PATCH 0117/1682] [Analyzer] [Tests] Dump the output of scan-build to
 stdout on failure.

Eliminates extra lookup step during debugging.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316806 91177308-0d34-0410-b5e6-96231b3b80d8
---
 utils/analyzer/SATestBuild.py | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py
index 6f4ef2824b..ed700c0c8e 100755
--- a/utils/analyzer/SATestBuild.py
+++ b/utils/analyzer/SATestBuild.py
@@ -272,10 +272,11 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
                        stderr=PBuildLogFile,
                        stdout=PBuildLogFile,
                        shell=True)
-    except:
-        print "Error: scan-build failed. See ", PBuildLogFile.name,\
-              " for details."
-        raise
+    except CalledProcessError:
+        print "Error: scan-build failed. Its output was: "
+        PBuildLogFile.seek(0)
+        shutil.copyfileobj(PBuildLogFile, sys.stdout)
+        sys.exit(1)
 
 
 def runAnalyzePreprocessed(Dir, SBOutputDir, Mode):
@@ -373,7 +374,7 @@ def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
     os.makedirs(os.path.join(SBOutputDir, LogFolderName))
 
     # Build and analyze the project.
-    with open(BuildLogPath, "wb+") as PBuildLogFile:
+    with open(BuildLogPath, "r+b") as PBuildLogFile:
         if (ProjectBuildMode == 1):
             downloadAndPatch(Dir, PBuildLogFile)
             runCleanupScript(Dir, PBuildLogFile)
-- 
GitLab


From c124c77b3b52e2d04aed181a426f1971cb1614e4 Mon Sep 17 00:00:00 2001
From: Reid Kleckner 
Date: Fri, 27 Oct 2017 22:48:41 +0000
Subject: [PATCH 0118/1682] [MS] Allow access to ambiguous, inaccessible direct
 bases

Summary:
Clang typically warns that in the following class hierarchy, 'A' is
inaccessible because there is no series of casts that the user can
write to access it unambiguously:
  struct A { };
  struct B : A { };
  struct C : A, B { };

MSVC allows the user to convert from C* to A*, though, and we've
encountered this issue in the latest Windows SDK headers.

This patch allows this conversion when -fms-compatibility is set and
adds a warning for it under -Wmicrosoft-inaccessible-base.

Reviewers: rsmith

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D39389

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316807 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Basic/DiagnosticGroups.td       |  1 +
 include/clang/Basic/DiagnosticSemaKinds.td    |  3 +
 lib/Sema/SemaDeclCXX.cpp                      | 55 +++++++++++++------
 .../microsoft-inaccessible-base.cpp           | 20 +++++++
 test/SemaCXX/accessible-base.cpp              | 32 ++++++++++-
 5 files changed, 92 insertions(+), 19 deletions(-)
 create mode 100644 test/CodeGenCXX/microsoft-inaccessible-base.cpp

diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 4cceaf6ccc..c23183c81a 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -890,6 +890,7 @@ def MicrosoftVoidPseudoDtor : DiagGroup<"microsoft-void-pseudo-dtor">;
 def MicrosoftAnonTag : DiagGroup<"microsoft-anon-tag">;
 def MicrosoftCommentPaste : DiagGroup<"microsoft-comment-paste">;
 def MicrosoftEndOfFile : DiagGroup<"microsoft-end-of-file">;
+def MicrosoftInaccessibleBase : DiagGroup<"microsoft-inaccessible-base">;
 // Aliases.
 def : DiagGroup<"msvc-include", [MicrosoftInclude]>;
                 // -Wmsvc-include = -Wmicrosoft-include
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index b1cba0655c..b8538f92cb 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7565,6 +7565,9 @@ def err_ambiguous_derived_to_base_conv : Error<
 def err_ambiguous_memptr_conv : Error<
   "ambiguous conversion from pointer to member of %select{base|derived}0 "
   "class %1 to pointer to member of %select{derived|base}0 class %2:%3">;
+def ext_ms_ambiguous_direct_base : ExtWarn<
+  "accessing inaccessible direct base %0 of %1 is a Microsoft extension">,
+  InGroup;
 
 def err_memptr_conv_via_virtual : Error<
   "conversion from pointer to member of class %0 to pointer to member "
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 750e0623c5..fa9e9f3218 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2503,13 +2503,8 @@ bool Sema::IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base,
   return DerivedRD->isDerivedFrom(BaseRD, Paths);
 }
 
-void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
-                              CXXCastPath &BasePathArray) {
-  assert(BasePathArray.empty() && "Base path array must be empty!");
-  assert(Paths.isRecordingPaths() && "Must record paths!");
-
-  const CXXBasePath &Path = Paths.front();
-
+static void BuildBasePathArray(const CXXBasePath &Path,
+                               CXXCastPath &BasePathArray) {
   // We first go backward and check if we have a virtual base.
   // FIXME: It would be better if CXXBasePath had the base specifier for
   // the nearest virtual base.
@@ -2526,6 +2521,13 @@ void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
     BasePathArray.push_back(const_cast(Path[I].Base));
 }
 
+
+void Sema::BuildBasePathArray(const CXXBasePaths &Paths,
+                              CXXCastPath &BasePathArray) {
+  assert(BasePathArray.empty() && "Base path array must be empty!");
+  assert(Paths.isRecordingPaths() && "Must record paths!");
+  return ::BuildBasePathArray(Paths.front(), BasePathArray);
+}
 /// CheckDerivedToBaseConversion - Check whether the Derived-to-Base
 /// conversion (where Derived and Base are class types) is
 /// well-formed, meaning that the conversion is unambiguous (and
@@ -2557,23 +2559,42 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
          "Can only be used with a derived-to-base conversion");
   (void)DerivationOkay;
 
-  if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
+  const CXXBasePath *Path = nullptr;
+  if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType()))
+    Path = &Paths.front();
+
+  // For MSVC compatibility, check if Derived directly inherits from Base. Clang
+  // warns about this hierarchy under -Winaccessible-base, but MSVC allows the
+  // user to access such bases.
+  if (!Path && getLangOpts().MSVCCompat) {
+    for (const CXXBasePath &PossiblePath : Paths) {
+      if (PossiblePath.size() == 1) {
+        Path = &PossiblePath;
+        if (AmbigiousBaseConvID)
+          Diag(Loc, diag::ext_ms_ambiguous_direct_base)
+              << Base << Derived << Range;
+        break;
+      }
+    }
+  }
+
+  if (Path) {
     if (!IgnoreAccess) {
       // Check that the base class can be accessed.
-      switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
-                                   InaccessibleBaseID)) {
-        case AR_inaccessible:
-          return true;
-        case AR_accessible:
-        case AR_dependent:
-        case AR_delayed:
-          break;
+      switch (
+          CheckBaseClassAccess(Loc, Base, Derived, *Path, InaccessibleBaseID)) {
+      case AR_inaccessible:
+        return true;
+      case AR_accessible:
+      case AR_dependent:
+      case AR_delayed:
+        break;
       }
     }
 
     // Build a base path if necessary.
     if (BasePath)
-      BuildBasePathArray(Paths, *BasePath);
+      ::BuildBasePathArray(*Path, *BasePath);
     return false;
   }
 
diff --git a/test/CodeGenCXX/microsoft-inaccessible-base.cpp b/test/CodeGenCXX/microsoft-inaccessible-base.cpp
new file mode 100644
index 0000000000..2c0d124eb0
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-inaccessible-base.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fms-compatibility -triple x86_64-windows-msvc %s -emit-llvm -o - | FileCheck %s
+
+// Make sure we choose the *direct* base path when doing these conversions.
+
+// CHECK: %struct.C = type { %struct.A, %struct.B }
+// CHECK: %struct.D = type { %struct.B, %struct.A }
+
+struct A { int a; };
+struct B : A { int b; };
+
+struct C : A, B { };
+extern "C" A *a_from_c(C *p) { return p; }
+// CHECK-LABEL: define %struct.A* @a_from_c(%struct.C* %{{.*}})
+// CHECK: bitcast %struct.C* %{{.*}} to %struct.A*
+
+struct D : B, A { };
+extern "C" A *a_from_d(D *p) { return p; }
+// CHECK-LABEL: define %struct.A* @a_from_d(%struct.D* %{{.*}})
+// CHECK: %[[p_i8:[^ ]*]] = bitcast %struct.D* %{{.*}} to i8*
+// CHECK: getelementptr inbounds i8, i8* %[[p_i8]], i64 8
diff --git a/test/SemaCXX/accessible-base.cpp b/test/SemaCXX/accessible-base.cpp
index 6bf06ce126..2796985850 100644
--- a/test/SemaCXX/accessible-base.cpp
+++ b/test/SemaCXX/accessible-base.cpp
@@ -1,10 +1,11 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -DMS -fms-compatibility -Wmicrosoft-inaccessible-base -fsyntax-only -verify %s
 
 struct A {
   int a;
 };
 
-struct X1 : virtual A 
+struct X1 : virtual A
 {};
 
 struct Y1 : X1, virtual A
@@ -13,7 +14,7 @@ struct Y1 : X1, virtual A
 struct Y2 : X1, A // expected-warning{{direct base 'A' is inaccessible due to ambiguity:\n    struct Y2 -> struct X1 -> struct A\n    struct Y2 -> struct A}}
 {};
 
-struct X2 : A 
+struct X2 : A
 {};
 
 struct Z1 : X2, virtual A // expected-warning{{direct base 'A' is inaccessible due to ambiguity:\n    struct Z1 -> struct X2 -> struct A\n    struct Z1 -> struct A}}
@@ -21,3 +22,30 @@ struct Z1 : X2, virtual A // expected-warning{{direct base 'A' is inaccessible d
 
 struct Z2 : X2, A // expected-warning{{direct base 'A' is inaccessible due to ambiguity:\n    struct Z2 -> struct X2 -> struct A\n    struct Z2 -> struct A}}
 {};
+
+A *y2_to_a(Y2 *p) {
+#ifdef MS
+  // expected-warning@+4 {{accessing inaccessible direct base 'A' of 'Y2' is a Microsoft extension}}
+#else
+  // expected-error@+2 {{ambiguous conversion}}
+#endif
+  return p;
+}
+
+A *z1_to_a(Z1 *p) {
+#ifdef MS
+  // expected-warning@+4 {{accessing inaccessible direct base 'A' of 'Z1' is a Microsoft extension}}
+#else
+  // expected-error@+2 {{ambiguous conversion}}
+#endif
+  return p;
+}
+
+A *z1_to_a(Z2 *p) {
+#ifdef MS
+  // expected-warning@+4 {{accessing inaccessible direct base 'A' of 'Z2' is a Microsoft extension}}
+#else
+  // expected-error@+2 {{ambiguous conversion}}
+#endif
+  return p;
+}
-- 
GitLab


From b26cd8eec627bf081f512d7f65baed6d0ecd1b91 Mon Sep 17 00:00:00 2001
From: George Karpenkov 
Date: Fri, 27 Oct 2017 22:52:36 +0000
Subject: [PATCH 0119/1682] [Analyzer] [Tests] Fixing typo from the previous
 commit.

Can not open a non-existent file with r+.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316808 91177308-0d34-0410-b5e6-96231b3b80d8
---
 utils/analyzer/SATestBuild.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py
index ed700c0c8e..3c694fb038 100755
--- a/utils/analyzer/SATestBuild.py
+++ b/utils/analyzer/SATestBuild.py
@@ -374,7 +374,7 @@ def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
     os.makedirs(os.path.join(SBOutputDir, LogFolderName))
 
     # Build and analyze the project.
-    with open(BuildLogPath, "r+b") as PBuildLogFile:
+    with open(BuildLogPath, "wb+") as PBuildLogFile:
         if (ProjectBuildMode == 1):
             downloadAndPatch(Dir, PBuildLogFile)
             runCleanupScript(Dir, PBuildLogFile)
-- 
GitLab


From c10c256001ea8a7f9a126ae1ea20858007941d16 Mon Sep 17 00:00:00 2001
From: Saleem Abdulrasool 
Date: Fri, 27 Oct 2017 23:04:27 +0000
Subject: [PATCH 0120/1682] ARM: centralise SizeType, PtrDiffType, and
 IntPtrType

Centralise the definitions of these compiler vended types to aid
inspection to ensure that they are defined similarly.  The one case that
stands out is the Darwin case where the types do not match up.  This
fixes the API conformance for APCS-GNU as well.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316810 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Basic/Targets/ARM.cpp | 44 ++++++++++++---------------------------
 test/Preprocessor/init.c  |  5 +++++
 2 files changed, 18 insertions(+), 31 deletions(-)

diff --git a/lib/Basic/Targets/ARM.cpp b/lib/Basic/Targets/ARM.cpp
index 1b236dd220..bbbe75b483 100644
--- a/lib/Basic/Targets/ARM.cpp
+++ b/lib/Basic/Targets/ARM.cpp
@@ -28,14 +28,6 @@ void ARMTargetInfo::setABIAAPCS() {
   DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64;
   const llvm::Triple &T = getTriple();
 
-  // size_t is unsigned long on MachO-derived environments, NetBSD, and
-  // OpenBSD.
-  if (T.isOSBinFormatMachO() || T.getOS() == llvm::Triple::NetBSD ||
-      T.getOS() == llvm::Triple::OpenBSD)
-    SizeType = UnsignedLong;
-  else
-    SizeType = UnsignedInt;
-
   bool IsNetBSD = T.getOS() == llvm::Triple::NetBSD;
   bool IsOpenBSD = T.getOS() == llvm::Triple::OpenBSD;
   if (!T.isOSWindows() && !IsNetBSD && !IsOpenBSD)
@@ -83,12 +75,6 @@ void ARMTargetInfo::setABIAPCS(bool IsAAPCS16) {
   else
     DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32;
 
-  // size_t is unsigned int on FreeBSD.
-  if (T.getOS() == llvm::Triple::FreeBSD)
-    SizeType = UnsignedInt;
-  else
-    SizeType = UnsignedLong;
-
   WCharType = SignedInt;
 
   // Do not respect the alignment of bit-field types when laying out
@@ -225,22 +211,23 @@ ARMTargetInfo::ARMTargetInfo(const llvm::Triple &Triple,
                              const TargetOptions &Opts)
     : TargetInfo(Triple), FPMath(FP_Default), IsAAPCS(true), LDREX(0),
       HW_FP(0) {
-
-  switch (getTriple().getOS()) {
-  case llvm::Triple::NetBSD:
-  case llvm::Triple::OpenBSD:
-    PtrDiffType = SignedLong;
-    break;
-  default:
-    PtrDiffType = SignedInt;
-    break;
-  }
-
   bool IsOpenBSD = Triple.getOS() == llvm::Triple::OpenBSD;
   bool IsNetBSD = Triple.getOS() == llvm::Triple::NetBSD;
-  IntPtrType =
+
+  PtrDiffType = IntPtrType =
       (Triple.isOSDarwin() || IsOpenBSD || IsNetBSD) ? SignedLong : SignedInt;
 
+  // FIXME: the isOSBinFormatMachO is a workaround for identifying a Darwin-like
+  // environment where size_t is `unsigned long` rather than `unsigned int`
+  SizeType = (Triple.isOSDarwin() || Triple.isOSBinFormatMachO() || IsOpenBSD ||
+              IsNetBSD)
+                 ? UnsignedLong
+                 : UnsignedInt;
+
+  // ptrdiff_t is inconsistent on Darwin
+  if (Triple.isOSDarwin() && !Triple.isWatchABI())
+    PtrDiffType = SignedInt;
+
   // Cache arch related info.
   setArchInfo();
 
@@ -927,7 +914,6 @@ void ARMbeTargetInfo::getTargetDefines(const LangOptions &Opts,
 WindowsARMTargetInfo::WindowsARMTargetInfo(const llvm::Triple &Triple,
                                            const TargetOptions &Opts)
     : WindowsTargetInfo(Triple, Opts), Triple(Triple) {
-  SizeType = UnsignedInt;
 }
 
 void WindowsARMTargetInfo::getVisualStudioDefines(const LangOptions &Opts,
@@ -1047,10 +1033,6 @@ DarwinARMTargetInfo::DarwinARMTargetInfo(const llvm::Triple &Triple,
     // Darwin on iOS uses a variant of the ARM C++ ABI.
     TheCXXABI.set(TargetCXXABI::WatchOS);
 
-    // The 32-bit ABI is silent on what ptrdiff_t should be, but given that
-    // size_t is long, it's a bit weird for it to be int.
-    PtrDiffType = SignedLong;
-
     // BOOL should be a real boolean on the new ABI
     UseSignedCharForObjCBool = false;
   } else
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index 293a3d6ad0..228ae2d701 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -1791,6 +1791,11 @@
 // ARM:#define __arm 1
 // ARM:#define __arm__ 1
 
+// RUN: %clang_cc1 -dM -ffreestanding -triple arm-none-none -target-abi apcs-gnu -E /dev/null -o - | FileCheck -match-full-lines -check-prefix ARM-APCS-GNU %s
+// ARM-APCS-GNU: #define __INTPTR_TYPE__ int
+// ARM-APCS-GNU: #define __PTRDIFF_TYPE__ int
+// ARM-APCS-GNU: #define __SIZE_TYPE__ unsigned int
+
 // RUN: %clang_cc1 -E -dM -ffreestanding -triple=armeb-none-none < /dev/null | FileCheck -match-full-lines -check-prefix ARM-BE %s
 //
 // ARM-BE-NOT:#define _LP64
-- 
GitLab


From 7c2b4afc0b01cac25df584e802b91d9d351a1fee Mon Sep 17 00:00:00 2001
From: Richard Smith 
Date: Sat, 28 Oct 2017 01:15:00 +0000
Subject: [PATCH 0121/1682] Never try to instantiate a deduction guide's
 "definition". Fixes bogus warning when there inevitably isn't one.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316820 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Sema/SemaTemplateInstantiateDecl.cpp                 | 3 ++-
 test/SemaCXX/cxx1z-class-template-argument-deduction.cpp | 4 ++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index d93fbd7c83..5b528fa9c2 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3768,7 +3768,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
                                          bool Recursive,
                                          bool DefinitionRequired,
                                          bool AtEndOfTU) {
-  if (Function->isInvalidDecl() || Function->isDefined())
+  if (Function->isInvalidDecl() || Function->isDefined() ||
+      isa(Function))
     return;
 
   // Never instantiate an explicit specialization except if it is a class scope
diff --git a/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
index 9232a8b6eb..9080f67fe0 100644
--- a/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
+++ b/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -std=c++1z -verify %s -DERRORS
-// RUN: %clang_cc1 -std=c++1z -verify %s -UERRORS
+// RUN: %clang_cc1 -std=c++1z -verify %s -DERRORS -Wundefined-func-template
+// RUN: %clang_cc1 -std=c++1z -verify %s -UERRORS -Wundefined-func-template
 
 // This test is split into two because we only produce "undefined internal"
 // warnings if we didn't produce any errors.
-- 
GitLab


From 2fd1377b9138ac71f8aca6e8251c655caf549406 Mon Sep 17 00:00:00 2001
From: Saleem Abdulrasool 
Date: Sat, 28 Oct 2017 06:00:43 +0000
Subject: [PATCH 0122/1682] Basic: improve coverage for Darwin targets and fix
 ABI

The existing coverage for the Darwin targets wasn't enough to catch all
the variations.  Improve the coverage a bit further and fix a few cases
for Darwin targets.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316826 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Basic/Targets/ARM.cpp | 13 +++++---
 test/Preprocessor/init.c  | 62 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+), 4 deletions(-)

diff --git a/lib/Basic/Targets/ARM.cpp b/lib/Basic/Targets/ARM.cpp
index bbbe75b483..def490b99f 100644
--- a/lib/Basic/Targets/ARM.cpp
+++ b/lib/Basic/Targets/ARM.cpp
@@ -214,18 +214,23 @@ ARMTargetInfo::ARMTargetInfo(const llvm::Triple &Triple,
   bool IsOpenBSD = Triple.getOS() == llvm::Triple::OpenBSD;
   bool IsNetBSD = Triple.getOS() == llvm::Triple::NetBSD;
 
-  PtrDiffType = IntPtrType =
-      (Triple.isOSDarwin() || IsOpenBSD || IsNetBSD) ? SignedLong : SignedInt;
-
   // FIXME: the isOSBinFormatMachO is a workaround for identifying a Darwin-like
   // environment where size_t is `unsigned long` rather than `unsigned int`
+
+  PtrDiffType = IntPtrType =
+      (Triple.isOSDarwin() || Triple.isOSBinFormatMachO() || IsOpenBSD ||
+       IsNetBSD)
+          ? SignedLong
+          : SignedInt;
+
   SizeType = (Triple.isOSDarwin() || Triple.isOSBinFormatMachO() || IsOpenBSD ||
               IsNetBSD)
                  ? UnsignedLong
                  : UnsignedInt;
 
   // ptrdiff_t is inconsistent on Darwin
-  if (Triple.isOSDarwin() && !Triple.isWatchABI())
+  if ((Triple.isOSDarwin() || Triple.isOSBinFormatMachO()) &&
+      !Triple.isWatchABI())
     PtrDiffType = SignedInt;
 
   // Cache arch related info.
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index 228ae2d701..87a591923b 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -9925,3 +9925,65 @@
 // RUN: | FileCheck -check-prefix=DARWIN %s
 
 // DARWIN:#define __STDC_NO_THREADS__ 1
+
+// RUN: %clang_cc1 -triple i386-apple-macosx -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix MACOS-32 %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix MACOS-64 %s
+
+// MACOS-32: #define __INTPTR_TYPE__ long int
+// MACOS-32: #define __PTRDIFF_TYPE__ int
+// MACOS-32: #define __SIZE_TYPE__ long unsigned int
+
+// MACOS-64: #define __INTPTR_TYPE__ long int
+// MACOS-64: #define __PTRDIFF_TYPE__ long int
+// MACOS-64: #define __SIZE_TYPE__ long unsigned int
+
+// RUN: %clang_cc1 -triple i386-apple-ios-simulator -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix IOS-32 %s
+// RUN: %clang_cc1 -triple armv7-apple-ios -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix IOS-32 %s
+// RUN: %clang_cc1 -triple x86_64-apple-ios-simulator -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix IOS-64 %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix IOS-64 %s
+
+// IOS-32: #define __INTPTR_TYPE__ long int
+// IOS-32: #define __PTRDIFF_TYPE__ int
+// IOS-32: #define __SIZE_TYPE__ long unsigned int
+
+// IOS-64: #define __INTPTR_TYPE__ long int
+// IOS-64: #define __PTRDIFF_TYPE__ long int
+// IOS-64: #define __SIZE_TYPE__ long unsigned int
+
+// RUN: %clang_cc1 -triple i386-apple-tvos-simulator -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix TVOS-32 %s
+// RUN: %clang_cc1 -triple armv7-apple-tvos -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix TVOS-32 %s
+// RUN: %clang_cc1 -triple x86_64-apple-tvos-simulator -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix TVOS-64 %s
+// RUN: %clang_cc1 -triple arm64-apple-tvos -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix TVOS-64 %s
+
+// TVOS-32: #define __INTPTR_TYPE__ long int
+// TVOS-32: #define __PTRDIFF_TYPE__ int
+// TVOS-32: #define __SIZE_TYPE__ long unsigned int
+
+// TVOS-64: #define __INTPTR_TYPE__ long int
+// TVOS-64: #define __PTRDIFF_TYPE__ long int
+// TVOS-64: #define __SIZE_TYPE__ long unsigned int
+
+// RUN: %clang_cc1 -triple i386-apple-watchos-simulator -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix WATCHOS-32 %s
+// RUN: %clang_cc1 -triple armv7k-apple-watchos -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix WATCHOS-64 %s
+// RUN: %clang_cc1 -triple x86_64-apple-watchos-simulator -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix WATCHOS-64 %s
+// RUN: %clang_cc1 -triple arm64-apple-watchos -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix WATCHOS-64 %s
+
+// WATCHOS-32: #define __INTPTR_TYPE__ long int
+// WATCHOS-32: #define __PTRDIFF_TYPE__ int
+// WATCHOS-32: #define __SIZE_TYPE__ long unsigned int
+
+// WATCHOS-64: #define __INTPTR_TYPE__ long int
+// WATCHOS-64: #define __PTRDIFF_TYPE__ long int
+// WATCHOS-64: #define __SIZE_TYPE__ long unsigned int
+
+// RUN: %clang_cc1 -triple armv7-apple-none-macho -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix ARM-DARWIN-BAREMETAL-32 %s
+// RUN: %clang_cc1 -triple arm64-apple-none-macho -ffreestanding -dM -E /dev/null -o - | FileCheck -match-full-lines -check-prefix ARM-DARWIN-BAREMETAL-64 %s
+
+// ARM-DARWIN-BAREMETAL-32: #define __INTPTR_TYPE__ long int
+// ARM-DARWIN-BAREMETAL-32: #define __PTRDIFF_TYPE__ int
+// ARM-DARWIN-BAREMETAL-32: #define __SIZE_TYPE__ long unsigned int
+
+// ARM-DARWIN-BAREMETAL-64: #define __INTPTR_TYPE__ long int
+// ARM-DARWIN-BAREMETAL-64: #define __PTRDIFF_TYPE__ long int
+// ARM-DARWIN-BAREMETAL-64: #define __SIZE_TYPE__ long unsigned int
+
-- 
GitLab


From 5d548d284e653240a44965a6b3ce891de8435341 Mon Sep 17 00:00:00 2001
From: Peter Szecsi 
Date: Sat, 28 Oct 2017 12:19:08 +0000
Subject: [PATCH 0123/1682] [analyzer] LoopUnrolling: check the bitwidth of the
 used numbers (pr34943)

The loop unrolling feature aims to track the maximum possible steps a loop can
make. In order to implement this, it investigates the initial value of the
counter variable and the bound number. (It has to be known.)
These numbers are used as llvm::APInts, however, it was not checked if their
bitwidths are the same which lead to some crashes.
This revision solves this problem by extending the "shorter" one (to the length
of the "longer" one).
For the detailed bug report, see: https://bugs.llvm.org/show_bug.cgi?id=34943

Differential Revision: https://reviews.llvm.org/D38922



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316830 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/StaticAnalyzer/Core/LoopUnrolling.cpp | 11 +++++++++--
 test/Analysis/loop-unrolling.cpp          |  6 ++++++
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/lib/StaticAnalyzer/Core/LoopUnrolling.cpp b/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
index 98b6ebd367..a8c4b05cea 100644
--- a/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ b/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -208,9 +208,16 @@ bool shouldCompletelyUnroll(const Stmt *LoopStmt, ASTContext &ASTCtx,
     return false;
 
   auto CounterVar = Matches[0].getNodeAs("initVarName");
-  auto BoundNum = Matches[0].getNodeAs("boundNum")->getValue();
-  auto InitNum = Matches[0].getNodeAs("initNum")->getValue();
+  llvm::APInt BoundNum =
+      Matches[0].getNodeAs("boundNum")->getValue();
+  llvm::APInt InitNum =
+      Matches[0].getNodeAs("initNum")->getValue();
   auto CondOp = Matches[0].getNodeAs("conditionOperator");
+  if (InitNum.getBitWidth() != BoundNum.getBitWidth()) {
+    InitNum = InitNum.zextOrSelf(BoundNum.getBitWidth());
+    BoundNum = BoundNum.zextOrSelf(InitNum.getBitWidth());
+  }
+
   if (CondOp->getOpcode() == BO_GE || CondOp->getOpcode() == BO_LE)
     maxStep = (BoundNum - InitNum + 1).abs().getZExtValue();
   else
diff --git a/test/Analysis/loop-unrolling.cpp b/test/Analysis/loop-unrolling.cpp
index 8ea5b82aad..844d1f18ea 100644
--- a/test/Analysis/loop-unrolling.cpp
+++ b/test/Analysis/loop-unrolling.cpp
@@ -373,3 +373,9 @@ int num_steps_over_limit3() {
   return 0;
 }
 
+
+void pr34943() {
+  for (int i = 0; i < 6L; ++i) {
+    clang_analyzer_numTimesReached(); // expected-warning {{6}}
+  }
+}
-- 
GitLab


From abf6311767c074d44e74d01bb83b96c9ba7fb3ff Mon Sep 17 00:00:00 2001
From: Richard Smith 
Date: Sat, 28 Oct 2017 18:59:51 +0000
Subject: [PATCH 0124/1682] PR35039: Materialize temporary objects before
 wrapping them in an OpaqueValueExpr in a GNU binary conditional expression.

It's not meaningful for a non-materialized temporary object to be used as a
common subexpression of multiple expressions.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316836 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Sema/SemaExpr.cpp                       | 10 +++
 test/Analysis/temp-obj-dtors-cfg-output.cpp | 81 ++++++++++++++-------
 test/CodeGenCXX/cxx1z-copy-omission.cpp     | 26 +++++++
 3 files changed, 90 insertions(+), 27 deletions(-)

diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 1d8b9bc547..d80237d248 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -7242,6 +7242,16 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
       commonExpr = commonRes.get();
     }
 
+    // If the common expression is a class or array prvalue, materialize it
+    // so that we can safely refer to it multiple times.
+    if (commonExpr->isRValue() && (commonExpr->getType()->isRecordType() ||
+                                   commonExpr->getType()->isArrayType())) {
+      ExprResult MatExpr = TemporaryMaterializationConversion(commonExpr);
+      if (MatExpr.isInvalid())
+        return ExprError();
+      commonExpr = MatExpr.get();
+    }
+
     opaqueValue = new (Context) OpaqueValueExpr(commonExpr->getExprLoc(),
                                                 commonExpr->getType(),
                                                 commonExpr->getValueKind(),
diff --git a/test/Analysis/temp-obj-dtors-cfg-output.cpp b/test/Analysis/temp-obj-dtors-cfg-output.cpp
index 372443bedf..05b6a31059 100644
--- a/test/Analysis/temp-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/temp-obj-dtors-cfg-output.cpp
@@ -834,7 +834,8 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     Preds (1): B4
 // CHECK:     Succs (1): B1
 // CHECK:   [B4]
-// CHECK:     1: [B7.2] ?: [B6.6]
+// CXX98:     1: [B7.2] ?: [B6.6]
+// CXX11:     1: [B7.3] ?: [B6.6]
 // CHECK:     2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     3: [B4.2]
 // CHECK:     4: [B4.3] (CXXConstructExpr, class A)
@@ -843,10 +844,13 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     Preds (2): B5 B6
 // CHECK:     Succs (2): B3 B2
 // CHECK:   [B5]
-// CHECK:     1: [B7.2] (ImplicitCastExpr, NoOp, const class A)
-// CHECK:     2: [B5.1]
-// CHECK:     3: [B5.2] (CXXConstructExpr, class A)
-// CHECK:     4: [B5.3] (BindTemporary)
+// CXX98:     1: [B7.2] (ImplicitCastExpr, NoOp, const class A)
+// CXX98:     2: [B5.1]
+// CXX98:     3: [B5.2] (CXXConstructExpr, class A)
+// CXX98:     4: [B5.3] (BindTemporary)
+// CXX11:     1: [B7.3] (ImplicitCastExpr, NoOp, const class A)
+// CXX11:     2: [B5.1] (CXXConstructExpr, class A)
+// CXX11:     3: [B5.2] (BindTemporary)
 // CHECK:     Preds (1): B7
 // CHECK:     Succs (1): B4
 // CHECK:   [B6]
@@ -861,10 +865,15 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:   [B7]
 // CHECK:     1: A() (CXXConstructExpr, class A)
 // CHECK:     2: [B7.1] (BindTemporary)
-// CHECK:     3: [B7.2].operator bool
-// CHECK:     4: [B7.2]
-// CHECK:     5: [B7.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK:     T: [B7.5] ? ... : ...
+// CXX98:     3: [B7.2].operator bool
+// CXX98:     4: [B7.2]
+// CXX98:     5: [B7.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX98:     T: [B7.5] ? ... : ...
+// CXX11:     3: [B7.2]
+// CXX11:     4: [B7.3].operator bool
+// CXX11:     5: [B7.3]
+// CXX11:     6: [B7.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX11:     T: [B7.6] ? ... : ...
 // CHECK:     Preds (1): B8
 // CHECK:     Succs (2): B5 B6
 // CHECK:   [B0 (EXIT)]
@@ -886,7 +895,8 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     Preds (1): B4
 // CHECK:     Succs (1): B1
 // CHECK:   [B4]
-// CHECK:     1: [B7.4] ?: [B6.6]
+// CXX98:     1: [B7.4] ?: [B6.6]
+// CXX11:     1: [B7.5] ?: [B6.6]
 // CHECK:     2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     3: [B4.2]
 // CHECK:     4: [B7.2]([B4.3])
@@ -894,10 +904,13 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     Preds (2): B5 B6
 // CHECK:     Succs (2): B3 B2
 // CHECK:   [B5]
-// CHECK:     1: [B7.4] (ImplicitCastExpr, NoOp, const class A)
-// CHECK:     2: [B5.1]
-// CHECK:     3: [B5.2] (CXXConstructExpr, class A)
-// CHECK:     4: [B5.3] (BindTemporary)
+// CXX98:     1: [B7.4] (ImplicitCastExpr, NoOp, const class A)
+// CXX98:     2: [B5.1]
+// CXX98:     3: [B5.2] (CXXConstructExpr, class A)
+// CXX98:     4: [B5.3] (BindTemporary)
+// CXX11:     1: [B7.5] (ImplicitCastExpr, NoOp, const class A)
+// CXX11:     2: [B5.1] (CXXConstructExpr, class A)
+// CXX11:     3: [B5.2] (BindTemporary)
 // CHECK:     Preds (1): B7
 // CHECK:     Succs (1): B4
 // CHECK:   [B6]
@@ -914,10 +927,15 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     2: [B7.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
 // CHECK:     3: A() (CXXConstructExpr, class A)
 // CHECK:     4: [B7.3] (BindTemporary)
-// CHECK:     5: [B7.4].operator bool
-// CHECK:     6: [B7.4]
-// CHECK:     7: [B7.6] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK:     T: [B7.7] ? ... : ...
+// CXX98:     5: [B7.4].operator bool
+// CXX98:     6: [B7.4]
+// CXX98:     7: [B7.6] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX98:     T: [B7.7] ? ... : ...
+// CXX11:     5: [B7.4]
+// CXX11:     6: [B7.5].operator bool
+// CXX11:     7: [B7.5]
+// CXX11:     8: [B7.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX11:     T: [B7.8] ? ... : ...
 // CHECK:     Preds (2): B8 B9
 // CHECK:     Succs (2): B5 B6
 // CHECK:   [B8]
@@ -925,7 +943,8 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     Preds (1): B9
 // CHECK:     Succs (1): B7
 // CHECK:   [B9]
-// CHECK:     1: [B12.2] ?: [B11.6]
+// CXX98:     1: [B12.2] ?: [B11.6]
+// CXX11:     1: [B12.3] ?: [B11.6]
 // CHECK:     2: [B9.1] (ImplicitCastExpr, NoOp, const class A)
 // CHECK:     3: [B9.2]
 // CHECK:     4: const A &a = A() ?: A();
@@ -933,10 +952,13 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:     Preds (2): B10 B11
 // CHECK:     Succs (2): B8 B7
 // CHECK:   [B10]
-// CHECK:     1: [B12.2] (ImplicitCastExpr, NoOp, const class A)
-// CHECK:     2: [B10.1]
-// CHECK:     3: [B10.2] (CXXConstructExpr, class A)
-// CHECK:     4: [B10.3] (BindTemporary)
+// CXX98:     1: [B12.2] (ImplicitCastExpr, NoOp, const class A)
+// CXX98:     2: [B10.1]
+// CXX98:     3: [B10.2] (CXXConstructExpr, class A)
+// CXX98:     4: [B10.3] (BindTemporary)
+// CXX11:     1: [B12.3] (ImplicitCastExpr, NoOp, const class A)
+// CXX11:     2: [B10.1] (CXXConstructExpr, class A)
+// CXX11:     3: [B10.2] (BindTemporary)
 // CHECK:     Preds (1): B12
 // CHECK:     Succs (1): B9
 // CHECK:   [B11]
@@ -951,10 +973,15 @@ int testConsistencyNestedNormalReturn(bool value) {
 // CHECK:   [B12]
 // CHECK:     1: A() (CXXConstructExpr, class A)
 // CHECK:     2: [B12.1] (BindTemporary)
-// CHECK:     3: [B12.2].operator bool
-// CHECK:     4: [B12.2]
-// CHECK:     5: [B12.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK:     T: [B12.5] ? ... : ...
+// CXX98:     3: [B12.2].operator bool
+// CXX98:     4: [B12.2]
+// CXX98:     5: [B12.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX98:     T: [B12.5] ? ... : ...
+// CXX11:     3: [B12.2]
+// CXX11:     4: [B12.3].operator bool
+// CXX11:     5: [B12.3]
+// CXX11:     6: [B12.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX11:     T: [B12.6] ? ... : ...
 // CHECK:     Preds (1): B13
 // CHECK:     Succs (2): B10 B11
 // CHECK:   [B0 (EXIT)]
diff --git a/test/CodeGenCXX/cxx1z-copy-omission.cpp b/test/CodeGenCXX/cxx1z-copy-omission.cpp
index 234e4b1258..b33a218081 100644
--- a/test/CodeGenCXX/cxx1z-copy-omission.cpp
+++ b/test/CodeGenCXX/cxx1z-copy-omission.cpp
@@ -6,6 +6,8 @@ struct A {
   A(const A&);
   ~A();
 
+  operator bool();
+
   int arr[10];
 };
 
@@ -79,3 +81,27 @@ void i() {
 
   // CHECK-LABEL: }
 }
+
+// CHECK-LABEL: define {{.*}} @_Z1jv(
+void j() {
+  // CHECK:   alloca %{{.*}}*
+  // CHECK:   %[[OUTERTEMP:.*]] = alloca %{{.*}}
+  // CHECK:   %[[INNERTEMP:.*]] = alloca %{{.*}}
+  // CHECK:   call void @_ZN1AC1Ei(%{{.*}} %[[INNERTEMP]], i32 1)
+  // CHECK:   call zeroext i1 @_ZN1AcvbEv(%{{.*}} %[[INNERTEMP]])
+  // CHECK:   br i1
+  //
+  // CHECK:   call void @_ZN1AC1EOS_(%{{.*}} %[[OUTERTEMP]], %{{.*}} %[[INNERTEMP]])
+  // CHECK:   br label
+  //
+  // CHECK:   call void @_ZN1AC1Ei(%{{.*}} %[[OUTERTEMP]], i32 2)
+  // CHECK:   br label
+  //
+  // CHECK:   call void @_ZN1AD1Ev(%{{.*}} %[[INNERTEMP]])
+  A &&a = A(1) ?: A(2);
+
+  // CHECK:   call void @_Z1iv()
+  i();
+
+  // CHECK:   call void @_ZN1AD1Ev(%{{.*}} %[[OUTERTEMP]])
+}
-- 
GitLab


From a3962bae3fc11604e07e1a7b8f232967b7b610df Mon Sep 17 00:00:00 2001
From: Peter Szecsi 
Date: Sat, 28 Oct 2017 23:09:37 +0000
Subject: [PATCH 0125/1682] [analyzer] MisusedMovedObjectChecker: Fix false
 positive on state-resetting, handling method calls on base-class sub-objects

An earlier solution from Artem r315301 solves the reset problem, however, the
reports should be handled the same way in case of method calls. We should not
just report the base class of the object where the method was defined but the
whole object.

Fixed false positive which came from not removing the subobjects in case of a
state-resetting function. (Just replaced the State->remove(...) call to
removeFromState(..) which was defined exactly for that purpose.)

Some minor typos fixed in this patch as well which did not worth a whole new
patch in my opinion, so included them here.

Differential Revision: https://reviews.llvm.org/D31538



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316850 91177308-0d34-0410-b5e6-96231b3b80d8
---
 .../Checkers/MisusedMovedObjectChecker.cpp    | 27 ++++++++++---------
 test/Analysis/MisusedMovedObject.cpp          | 22 ++++++++++++---
 2 files changed, 34 insertions(+), 15 deletions(-)

diff --git a/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp b/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
index 4b69a1bd1e..9d405cd39c 100644
--- a/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
@@ -352,7 +352,7 @@ void MisusedMovedObjectChecker::checkPreCall(const CallEvent &Call,
   const LocationContext *LC = C.getLocationContext();
   ExplodedNode *N = nullptr;
 
-  // Remove the MemRegions from the map on which a ctor/dtor call or assignement
+  // Remove the MemRegions from the map on which a ctor/dtor call or assignment
   // happened.
 
   // Checking constructor calls.
@@ -380,8 +380,11 @@ void MisusedMovedObjectChecker::checkPreCall(const CallEvent &Call,
     return;
   // In case of destructor call we do not track the object anymore.
   const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
+  if (!ThisRegion)
+    return;
+
   if (dyn_cast_or_null(Call.getDecl())) {
-    State = removeFromState(State, IC->getCXXThisVal().getAsRegion());
+    State = removeFromState(State, ThisRegion);
     C.addTransition(State);
     return;
   }
@@ -412,28 +415,28 @@ void MisusedMovedObjectChecker::checkPreCall(const CallEvent &Call,
   }
 
   // The remaining part is check only for method call on a moved-from object.
+
+  // We want to investigate the whole object, not only sub-object of a parent
+  // class in which the encountered method defined.
+  while (const CXXBaseObjectRegion *BR =
+             dyn_cast(ThisRegion))
+    ThisRegion = BR->getSuperRegion();
+
   if (isMoveSafeMethod(MethodDecl))
     return;
 
   if (isStateResetMethod(MethodDecl)) {
-    // A state reset method resets the whole object, not only sub-object
-    // of a parent class in which it is defined.
-    const MemRegion *WholeObjectRegion = ThisRegion;
-    while (const CXXBaseObjectRegion *BR =
-               dyn_cast(WholeObjectRegion))
-      WholeObjectRegion = BR->getSuperRegion();
-
-    State = State->remove(WholeObjectRegion);
+    State = removeFromState(State, ThisRegion);
     C.addTransition(State);
     return;
   }
 
-  // If it is already reported then we dont report the bug again.
+  // If it is already reported then we don't report the bug again.
   const RegionState *ThisState = State->get(ThisRegion);
   if (!(ThisState && ThisState->isMoved()))
     return;
 
-  // Dont report it in case if any base region is already reported
+  // Don't report it in case if any base region is already reported
   if (isAnyBaseRegionReported(State, ThisRegion))
     return;
 
diff --git a/test/Analysis/MisusedMovedObject.cpp b/test/Analysis/MisusedMovedObject.cpp
index 57c1ecc912..645f1ab2e5 100644
--- a/test/Analysis/MisusedMovedObject.cpp
+++ b/test/Analysis/MisusedMovedObject.cpp
@@ -332,6 +332,8 @@ void moveStateResetFunctionsTest() {
     A b = std::move(a);
     a.reset(); // no-warning
     a.foo();   // no-warning
+    // Test if resets the state of subregions as well.
+    a.b.foo(); // no-warning
   }
   {
     A a;
@@ -344,6 +346,7 @@ void moveStateResetFunctionsTest() {
     A b = std::move(a);
     a.clear(); // no-warning
     a.foo();   // no-warning
+    a.b.foo(); // no-warning
   }
 }
 
@@ -444,7 +447,7 @@ void differentBranchesTest(int i) {
   // Same thing, but with a switch statement.
   {
     A a, b;
-    switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 448}}
+    switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 451}}
     case 1:
       b = std::move(a); // no-warning
       break;            // expected-note {{Execution jumps to the end of the function}}
@@ -456,7 +459,7 @@ void differentBranchesTest(int i) {
   // However, if there's a fallthrough, we do warn.
   {
     A a, b;
-    switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 460}}
+    switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 463}}
     case 1:
       b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
     case 2:
@@ -598,6 +601,7 @@ void ifStmtSequencesDeclAndConditionTest() {
   }
 }
 
+class C : public A {};
 void subRegionMoveTest() {
   {
     A a;
@@ -616,12 +620,24 @@ void subRegionMoveTest() {
     a.foo();             // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
     a.b.foo();           // no-warning
   }
+  {
+    C c;
+    C c1 = std::move(c); // expected-note {{'c' became 'moved-from' here}}
+    c.foo();             // expected-warning {{Method call on a 'moved-from' object 'c'}} expected-note {{Method call on a 'moved-from' object 'c'}}
+    c.b.foo();           // no-warning
+  }
 }
 
-class C: public A {};
 void resetSuperClass() {
   C c;
   C c1 = std::move(c);
   c.clear();
   C c2 = c; // no-warning
 }
+
+void reportSuperClass() {
+  C c;
+  C c1 = std::move(c); // expected-note {{'c' became 'moved-from' here}}
+  c.foo();             // expected-warning {{Method call on a 'moved-from' object 'c'}} expected-note {{Method call on a 'moved-from' object 'c'}}
+  C c2 = c;            // no-warning
+}
-- 
GitLab


From b25397ba806743e5d82df01cd72d400a9485493b Mon Sep 17 00:00:00 2001
From: Peter Szecsi 
Date: Sat, 28 Oct 2017 23:24:00 +0000
Subject: [PATCH 0126/1682] [analyzer] MisusedMovedObjectChecker: More precise
 warning message

Added new enum in order to differentiate the warning messages on "misusing" into
3 categories: function calls, moving an object, copying an object. (At the
moment the checker gives the same message in case of copying and moving.)

Additional test cases added as well.

Differential Revision: https://reviews.llvm.org/D38674



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316852 91177308-0d34-0410-b5e6-96231b3b80d8
---
 .../Checkers/MisusedMovedObjectChecker.cpp    | 32 +++++++----
 test/Analysis/MisusedMovedObject.cpp          | 54 +++++++++++++++----
 2 files changed, 66 insertions(+), 20 deletions(-)

diff --git a/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp b/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
index 9d405cd39c..497978f078 100644
--- a/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MisusedMovedObjectChecker.cpp
@@ -60,6 +60,7 @@ public:
                   const char *NL, const char *Sep) const override;
 
 private:
+  enum MisuseKind {MK_FunCall, MK_Copy, MK_Move};
   class MovedBugVisitor : public BugReporterVisitorImpl {
   public:
     MovedBugVisitor(const MemRegion *R) : Region(R), Found(false) {}
@@ -83,7 +84,7 @@ private:
 
   mutable std::unique_ptr BT;
   ExplodedNode *reportBug(const MemRegion *Region, const CallEvent &Call,
-                          CheckerContext &C, bool isCopy) const;
+                          CheckerContext &C, MisuseKind MK) const;
   bool isInMoveSafeContext(const LocationContext *LC) const;
   bool isStateResetMethod(const CXXMethodDecl *MethodDec) const;
   bool isMoveSafeMethod(const CXXMethodDecl *MethodDec) const;
@@ -179,7 +180,7 @@ const ExplodedNode *MisusedMovedObjectChecker::getMoveLocation(
 ExplodedNode *MisusedMovedObjectChecker::reportBug(const MemRegion *Region,
                                                    const CallEvent &Call,
                                                    CheckerContext &C,
-                                                   bool isCopy = false) const {
+                                                   MisuseKind MK) const {
   if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
     if (!BT)
       BT.reset(new BugType(this, "Usage of a 'moved-from' object",
@@ -195,10 +196,17 @@ ExplodedNode *MisusedMovedObjectChecker::reportBug(const MemRegion *Region,
 
     // Creating the error message.
     std::string ErrorMessage;
-    if (isCopy)
-      ErrorMessage = "Copying a 'moved-from' object";
-    else
-      ErrorMessage = "Method call on a 'moved-from' object";
+    switch(MK) {
+      case MK_FunCall:
+        ErrorMessage = "Method call on a 'moved-from' object";
+        break;
+      case MK_Copy:
+        ErrorMessage = "Copying a 'moved-from' object";
+        break;
+      case MK_Move:
+        ErrorMessage = "Moving a 'moved-from' object";
+        break;
+    }
     if (const auto DecReg = Region->getAs()) {
       const auto *RegionDecl = dyn_cast(DecReg->getDecl());
       ErrorMessage += " '" + RegionDecl->getNameAsString() + "'";
@@ -365,7 +373,10 @@ void MisusedMovedObjectChecker::checkPreCall(const CallEvent &Call,
       const RegionState *ArgState = State->get(ArgRegion);
       if (ArgState && ArgState->isMoved()) {
         if (!isInMoveSafeContext(LC)) {
-          N = reportBug(ArgRegion, Call, C, /*isCopy=*/true);
+          if(CtorDec->isMoveConstructor())
+            N = reportBug(ArgRegion, Call, C, MK_Move);
+          else
+            N = reportBug(ArgRegion, Call, C, MK_Copy);
           State = State->set(ArgRegion,
                                                RegionState::getReported());
         }
@@ -405,7 +416,10 @@ void MisusedMovedObjectChecker::checkPreCall(const CallEvent &Call,
           State->get(IC->getArgSVal(0).getAsRegion());
       if (ArgState && ArgState->isMoved() && !isInMoveSafeContext(LC)) {
         const MemRegion *ArgRegion = IC->getArgSVal(0).getAsRegion();
-        N = reportBug(ArgRegion, Call, C, /*isCopy=*/true);
+        if(MethodDecl->isMoveAssignmentOperator())
+          N = reportBug(ArgRegion, Call, C, MK_Move);
+        else
+          N = reportBug(ArgRegion, Call, C, MK_Copy);
         State =
             State->set(ArgRegion, RegionState::getReported());
       }
@@ -443,7 +457,7 @@ void MisusedMovedObjectChecker::checkPreCall(const CallEvent &Call,
   if (isInMoveSafeContext(LC))
     return;
 
-  N = reportBug(ThisRegion, Call, C);
+  N = reportBug(ThisRegion, Call, C, MK_FunCall);
   State = State->set(ThisRegion, RegionState::getReported());
   C.addTransition(State, N);
 }
diff --git a/test/Analysis/MisusedMovedObject.cpp b/test/Analysis/MisusedMovedObject.cpp
index 645f1ab2e5..132a65de10 100644
--- a/test/Analysis/MisusedMovedObject.cpp
+++ b/test/Analysis/MisusedMovedObject.cpp
@@ -38,6 +38,7 @@ public:
   B() = default;
   B(const B &) = default;
   B(B &&) = default;
+  B& operator=(const B &q) = default;
   void operator=(B &&b) {
     return;
   }
@@ -70,6 +71,12 @@ public:
   A(A &&other, char *k) {
     moveconstruct(std::move(other));
   }
+  void operator=(const A &other) {
+    i = other.i;
+    d = other.d;
+    b = other.b;
+    return;
+  }
   void operator=(A &&other) {
     moveconstruct(std::move(other));
     return;
@@ -105,17 +112,42 @@ void copyOrMoveCall(A a) {
 }
 
 void simpleMoveCtorTest() {
-  A a;
-  A b;
-  b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
-  a.foo();          // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+  {
+    A a;
+    A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+    a.foo();            // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+  }
+  {
+    A a;
+    A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+    b = a;              // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+  }
+  {
+    A a;
+    A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+    b = std::move(a);   // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}}
+  }
 }
 
 void simpleMoveAssignementTest() {
-  A a;
-  A b;
-  b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
-  a.foo();          // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+  {
+    A a;
+    A b;
+    b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+    a.foo();          // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+  }
+  {
+    A a;
+    A b;
+    b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+    A c(a);           // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+  }
+  {
+    A a;
+    A b;
+    b = std::move(a);  // expected-note {{'a' became 'moved-from' here}}
+    A c(std::move(a)); // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}}
+  }
 }
 
 void moveInInitListTest() {
@@ -270,7 +302,7 @@ void loopTest() {
   {
     A a;
     for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is true.  Entering loop body}} expected-note {{Loop condition is true.  Entering loop body}}
-      constCopyOrMoveCall(std::move(a)); // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+      constCopyOrMoveCall(std::move(a)); // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}}
       // expected-note@-1 {{'a' became 'moved-from' here}}
     }
   }
@@ -447,7 +479,7 @@ void differentBranchesTest(int i) {
   // Same thing, but with a switch statement.
   {
     A a, b;
-    switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 451}}
+    switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 483}}
     case 1:
       b = std::move(a); // no-warning
       break;            // expected-note {{Execution jumps to the end of the function}}
@@ -459,7 +491,7 @@ void differentBranchesTest(int i) {
   // However, if there's a fallthrough, we do warn.
   {
     A a, b;
-    switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 463}}
+    switch (i) { // expected-note {{Control jumps to 'case 1:'  at line 495}}
     case 1:
       b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
     case 2:
-- 
GitLab


From 68e041468bfb4a364acdfa32abb0c7e38cfb938e Mon Sep 17 00:00:00 2001
From: Saleem Abdulrasool 
Date: Sun, 29 Oct 2017 06:01:14 +0000
Subject: [PATCH 0127/1682] Driver: default to `unsigned int` `wchar_t` for ARM

AAPCS and AAPCS64 mandate that `wchar_t` with `-fno-short-wchar` is an
`unsigned int` rather than a `signed int`.  Ensure that the driver does
not flip the signedness of `wchar_t` for those targets.

Add additional tests to ensure that this does not regress.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316858 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Driver/ToolChains/Clang.cpp    |  7 +++-
 test/Driver/arm-wchar_t-defaults.c | 53 ++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 1 deletion(-)
 create mode 100644 test/Driver/arm-wchar_t-defaults.c

diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp
index adaf39abc5..c1c8813cc4 100644
--- a/lib/Driver/ToolChains/Clang.cpp
+++ b/lib/Driver/ToolChains/Clang.cpp
@@ -2622,8 +2622,13 @@ static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T,
       CmdArgs.push_back("-fwchar-type=short");
       CmdArgs.push_back("-fno-signed-wchar");
     } else {
+      bool IsARM = T.isARM() || T.isThumb() || T.isAArch64();
       CmdArgs.push_back("-fwchar-type=int");
-      CmdArgs.push_back("-fsigned-wchar");
+      if (IsARM && !(T.isOSWindows() || T.getOS() == llvm::Triple::NetBSD ||
+                     T.getOS() == llvm::Triple::OpenBSD))
+        CmdArgs.push_back("-fno-signed-wchar");
+      else
+        CmdArgs.push_back("-fsigned-wchar");
     }
   }
 }
diff --git a/test/Driver/arm-wchar_t-defaults.c b/test/Driver/arm-wchar_t-defaults.c
new file mode 100644
index 0000000000..8b2ae29d00
--- /dev/null
+++ b/test/Driver/arm-wchar_t-defaults.c
@@ -0,0 +1,53 @@
+// RUN: %clang -### -target armv7-unknown-none-eabi -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7-unknown-none-eabi -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-UNSIGNED %s
+// RUN: %clang -### -target armv7-unknown-none-eabi -mthumb -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7-unknown-none-eabi -mthumb -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-UNSIGNED %s
+// RUN: %clang -### -target armv7eb-unknown-none-eabi -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7eb-unknown-none-eabi -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-UNSIGNED %s
+// RUN: %clang -### -target armv7eb-unknown-none-eabi -mthumb -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7eb-unknown-none-eabi -mthumb -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-UNSIGNED %s
+// RUN: %clang -### -target aarch64-unknown-none-eabi -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target aarch64-unknown-none-eabi -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-UNSIGNED %s
+// RUN: %clang -### -target aarch64_be-unknown-none-eabi -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target aarch64_be-unknown-none-eabi -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-UNSIGNED %s
+
+// RUN: %clang -### -target armv7-unknown-netbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7-unknown-netbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target armv7-unknown-netbsd -mthumb -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7-unknown-netbsd -mthumb -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target armv7eb-unknown-netbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7eb-unknown-netbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target armv7eb-unknown-netbsd -mthumb -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7eb-unknown-netbsd -mthumb -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target aarch64-unknown-netbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target aarch64-unknown-netbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target aarch64_be-unknown-netbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target aarch64_be-unknown-netbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+
+// RUN: %clang -### -target armv7-unknown-openbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7-unknown-openbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target armv7-unknown-openbsd -mthumb -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7-unknown-openbsd -mthumb -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target armv7eb-unknown-openbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7eb-unknown-openbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target armv7eb-unknown-openbsd -mthumb -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7eb-unknown-openbsd -mthumb -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target aarch64-unknown-openbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target aarch64-unknown-openbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target aarch64_be-unknown-openbsd -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target aarch64_be-unknown-openbsd -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+
+// RUN: %clang -### -target armv7-unknown-windows-msvc -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target armv7-unknown-windows-msvc -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+// RUN: %clang -### -target aarch64-unknown-windows-msvc -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-SHORT %s
+// RUN: %clang -### -target aarch64-unknown-windows-msvc -fno-short-wchar -c %s -o /dev/null 2>&1 | FileCheck -check-prefix CHECK-LONG-SIGNED %s
+
+// CHECK-SHORT-NOT: "-fwchar-type=int"
+// CHECK-SHORT-NOT: "-fno-signed-wchar"
+
+// CHECK-LONG-UNSIGNED: "-fwchar-type=int"
+// CHECK-LONG-UNSIGNED: "-fno-signed-wchar"
+
+// CHECK-LONG-SIGNED: "-fwchar-type=int"
+// CHECK-LONG-SIGNED: "-fsigned-wchar"
+
-- 
GitLab


From 2ad457f76010c2f1ffe14f8324410d5ef4c8a8c2 Mon Sep 17 00:00:00 2001
From: Gabor Horvath 
Date: Mon, 30 Oct 2017 08:47:13 +0000
Subject: [PATCH 0128/1682] [analyzer] Handle ObjC messages conservatively in
 CallDescription

Differential Revision: https://reviews.llvm.org/D37470


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316885 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/StaticAnalyzer/Core/CallEvent.cpp     | 4 +++-
 test/Analysis/block-in-critical-section.m | 9 +++++++++
 2 files changed, 12 insertions(+), 1 deletion(-)
 create mode 100644 test/Analysis/block-in-critical-section.m

diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index f0a817616d..776369be9d 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -211,7 +211,9 @@ ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
 }
 
 bool CallEvent::isCalled(const CallDescription &CD) const {
-  assert(getKind() != CE_ObjCMessage && "Obj-C methods are not supported");
+  // FIXME: Add ObjC Message support.
+  if (getKind() == CE_ObjCMessage)
+    return false;
   if (!CD.IsLookupDone) {
     CD.IsLookupDone = true;
     CD.II = &getState()->getStateManager().getContext().Idents.get(CD.FuncName);
diff --git a/test/Analysis/block-in-critical-section.m b/test/Analysis/block-in-critical-section.m
new file mode 100644
index 0000000000..c04a0afb2a
--- /dev/null
+++ b/test/Analysis/block-in-critical-section.m
@@ -0,0 +1,9 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.BlockInCriticalSection -verify -Wno-objc-root-class %s
+
+@interface SomeClass
+-(void)someMethod;
+@end
+
+void shouldNotCrash(SomeClass *o) {
+  [o someMethod];
+}
-- 
GitLab


From 402bbf7dc2644b64a530dc77fd120b0fd9a6a45b Mon Sep 17 00:00:00 2001
From: Gabor Horvath 
Date: Mon, 30 Oct 2017 09:01:48 +0000
Subject: [PATCH 0129/1682] Add missing expected-no-diagnostics comment to
 test.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316886 91177308-0d34-0410-b5e6-96231b3b80d8
---
 test/Analysis/block-in-critical-section.m | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test/Analysis/block-in-critical-section.m b/test/Analysis/block-in-critical-section.m
index c04a0afb2a..73d58479f4 100644
--- a/test/Analysis/block-in-critical-section.m
+++ b/test/Analysis/block-in-critical-section.m
@@ -1,4 +1,5 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.BlockInCriticalSection -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
 
 @interface SomeClass
 -(void)someMethod;
-- 
GitLab


From a621a8df84caef38f942e31b2a3a6e2fbadf1732 Mon Sep 17 00:00:00 2001
From: Gabor Horvath 
Date: Mon, 30 Oct 2017 10:09:55 +0000
Subject: [PATCH 0130/1682] [analyzer] lock_guard and unique_lock extension for
 BlockInCriticalSection checker
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

A patch by zdtorok (Zoltán Dániel Török)!

Differential Revision: https://reviews.llvm.org/D33729


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316892 91177308-0d34-0410-b5e6-96231b3b80d8
---
 .../BlockInCriticalSectionChecker.cpp         | 54 +++++++++++++++----
 test/Analysis/block-in-critical-section.cpp   | 42 +++++++++++++++
 2 files changed, 85 insertions(+), 11 deletions(-)

diff --git a/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
index d19630eeef..c31f2794df 100644
--- a/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
@@ -26,15 +26,22 @@ using namespace ento;
 
 namespace {
 
-class BlockInCriticalSectionChecker : public Checker {
+class BlockInCriticalSectionChecker : public Checker {
+
+  mutable IdentifierInfo *IILockGuard, *IIUniqueLock;
 
   CallDescription LockFn, UnlockFn, SleepFn, GetcFn, FgetsFn, ReadFn, RecvFn,
                   PthreadLockFn, PthreadTryLockFn, PthreadUnlockFn,
                   MtxLock, MtxTimedLock, MtxTryLock, MtxUnlock;
 
+  StringRef ClassLockGuard, ClassUniqueLock;
+
+  mutable bool IdentifierInfoInitialized;
+
   std::unique_ptr BlockInCritSectionBugType;
 
+  void initIdentifierInfo(ASTContext &Ctx) const;
+
   void reportBlockInCritSection(SymbolRef FileDescSym,
                                 const CallEvent &call,
                                 CheckerContext &C) const;
@@ -46,13 +53,10 @@ public:
   bool isLockFunction(const CallEvent &Call) const;
   bool isUnlockFunction(const CallEvent &Call) const;
 
-  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
-
   /// Process unlock.
   /// Process lock.
   /// Process blocking functions (sleep, getc, fgets, read, recv)
   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
-
 };
 
 } // end anonymous namespace
@@ -60,7 +64,8 @@ public:
 REGISTER_TRAIT_WITH_PROGRAMSTATE(MutexCounter, unsigned)
 
 BlockInCriticalSectionChecker::BlockInCriticalSectionChecker()
-    : LockFn("lock"), UnlockFn("unlock"), SleepFn("sleep"), GetcFn("getc"),
+    : IILockGuard(nullptr), IIUniqueLock(nullptr),
+      LockFn("lock"), UnlockFn("unlock"), SleepFn("sleep"), GetcFn("getc"),
       FgetsFn("fgets"), ReadFn("read"), RecvFn("recv"),
       PthreadLockFn("pthread_mutex_lock"),
       PthreadTryLockFn("pthread_mutex_trylock"),
@@ -68,13 +73,29 @@ BlockInCriticalSectionChecker::BlockInCriticalSectionChecker()
       MtxLock("mtx_lock"),
       MtxTimedLock("mtx_timedlock"),
       MtxTryLock("mtx_trylock"),
-      MtxUnlock("mtx_unlock") {
+      MtxUnlock("mtx_unlock"),
+      ClassLockGuard("lock_guard"),
+      ClassUniqueLock("unique_lock"),
+      IdentifierInfoInitialized(false) {
   // Initialize the bug type.
   BlockInCritSectionBugType.reset(
       new BugType(this, "Call to blocking function in critical section",
                         "Blocking Error"));
 }
 
+void BlockInCriticalSectionChecker::initIdentifierInfo(ASTContext &Ctx) const {
+  if (!IdentifierInfoInitialized) {
+    /* In case of checking C code, or when the corresponding headers are not
+     * included, we might end up query the identifier table every time when this
+     * function is called instead of early returning it. To avoid this, a bool
+     * variable (IdentifierInfoInitialized) is used and the function will be run
+     * only once. */
+    IILockGuard  = &Ctx.Idents.get(ClassLockGuard);
+    IIUniqueLock = &Ctx.Idents.get(ClassUniqueLock);
+    IdentifierInfoInitialized = true;
+  }
+}
+
 bool BlockInCriticalSectionChecker::isBlockingFunction(const CallEvent &Call) const {
   if (Call.isCalled(SleepFn)
       || Call.isCalled(GetcFn)
@@ -87,6 +108,12 @@ bool BlockInCriticalSectionChecker::isBlockingFunction(const CallEvent &Call) co
 }
 
 bool BlockInCriticalSectionChecker::isLockFunction(const CallEvent &Call) const {
+  if (const auto *Ctor = dyn_cast(&Call)) {
+    auto IdentifierInfo = Ctor->getDecl()->getParent()->getIdentifier();
+    if (IdentifierInfo == IILockGuard || IdentifierInfo == IIUniqueLock)
+      return true;
+  }
+
   if (Call.isCalled(LockFn)
       || Call.isCalled(PthreadLockFn)
       || Call.isCalled(PthreadTryLockFn)
@@ -99,6 +126,13 @@ bool BlockInCriticalSectionChecker::isLockFunction(const CallEvent &Call) const
 }
 
 bool BlockInCriticalSectionChecker::isUnlockFunction(const CallEvent &Call) const {
+  if (const auto *Dtor = dyn_cast(&Call)) {
+    const auto *DRecordDecl = dyn_cast(Dtor->getDecl()->getParent());
+    auto IdentifierInfo = DRecordDecl->getIdentifier();
+    if (IdentifierInfo == IILockGuard || IdentifierInfo == IIUniqueLock)
+      return true;
+  }
+
   if (Call.isCalled(UnlockFn)
        || Call.isCalled(PthreadUnlockFn)
        || Call.isCalled(MtxUnlock)) {
@@ -107,12 +141,10 @@ bool BlockInCriticalSectionChecker::isUnlockFunction(const CallEvent &Call) cons
   return false;
 }
 
-void BlockInCriticalSectionChecker::checkPreCall(const CallEvent &Call,
-                                                 CheckerContext &C) const {
-}
-
 void BlockInCriticalSectionChecker::checkPostCall(const CallEvent &Call,
                                                   CheckerContext &C) const {
+  initIdentifierInfo(C.getASTContext());
+
   if (!isBlockingFunction(Call)
       && !isLockFunction(Call)
       && !isUnlockFunction(Call))
diff --git a/test/Analysis/block-in-critical-section.cpp b/test/Analysis/block-in-critical-section.cpp
index c65cc612cf..fcf6188fc0 100644
--- a/test/Analysis/block-in-critical-section.cpp
+++ b/test/Analysis/block-in-critical-section.cpp
@@ -7,6 +7,20 @@ struct mutex {
   void lock() {}
   void unlock() {}
 };
+template
+struct lock_guard {
+  lock_guard(std::mutex) {}
+  ~lock_guard() {}
+};
+template
+struct unique_lock {
+  unique_lock(std::mutex) {}
+  ~unique_lock() {}
+};
+template
+struct not_real_lock {
+  not_real_lock(std::mutex) {}
+};
 }
 
 void getc() {}
@@ -110,3 +124,31 @@ void testBlockInCriticalSectionUnexpectedUnlock() {
   m.lock();
   sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
 }
+
+void testBlockInCriticalSectionLockGuard() {
+  std::mutex g_mutex;
+  std::not_real_lock not_real_lock(g_mutex);
+  sleep(1); // no-warning
+
+  std::lock_guard lock(g_mutex);
+  sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
+}
+
+void testBlockInCriticalSectionLockGuardNested() {
+  testBlockInCriticalSectionLockGuard();
+  sleep(1); // no-warning
+}
+
+void testBlockInCriticalSectionUniqueLock() {
+  std::mutex g_mutex;
+  std::not_real_lock not_real_lock(g_mutex);
+  sleep(1); // no-warning
+
+  std::unique_lock lock(g_mutex);
+  sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
+}
+
+void testBlockInCriticalSectionUniqueLockNested() {
+  testBlockInCriticalSectionUniqueLock();
+  sleep(1); // no-warning
+}
-- 
GitLab


From 7fc4b5017f6fa01d6078ef7d5fb156f044a69125 Mon Sep 17 00:00:00 2001
From: Haojian Wu 
Date: Mon, 30 Oct 2017 11:17:09 +0000
Subject: [PATCH 0131/1682] [refactor] Fix a clang-tidy warning.

NFC

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316895 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Tooling/Refactoring/Rename/RenamingAction.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/Tooling/Refactoring/Rename/RenamingAction.cpp b/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
index 210b45b79e..695fa553b4 100644
--- a/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
+++ b/lib/Tooling/Refactoring/Rename/RenamingAction.cpp
@@ -77,7 +77,8 @@ RenameOccurrences::initiate(RefactoringRuleContext &Context,
   if (!ND)
     return Context.createDiagnosticError(
         SelectionRange.getBegin(), diag::err_refactor_selection_no_symbol);
-  return RenameOccurrences(getCanonicalSymbolDeclaration(ND), NewName);
+  return RenameOccurrences(getCanonicalSymbolDeclaration(ND),
+                           std::move(NewName));
 }
 
 Expected
-- 
GitLab


From a855bcfaf28c168e378e403990848acf17cefb69 Mon Sep 17 00:00:00 2001
From: "Ivan A. Kosarev" 
Date: Mon, 30 Oct 2017 11:49:31 +0000
Subject: [PATCH 0132/1682] [CodeGen] Generate TBAA info for reference loads

Differential Revision: https://reviews.llvm.org/D39177


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316896 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/CodeGen/CGBlocks.cpp        |  4 +-
 lib/CodeGen/CGExpr.cpp          | 94 ++++++++++++++++-----------------
 lib/CodeGen/CGOpenMPRuntime.cpp |  4 +-
 lib/CodeGen/CGStmtOpenMP.cpp    |  3 +-
 lib/CodeGen/CodeGenFunction.h   | 15 ++++--
 test/CodeGen/tbaa-reference.cpp | 36 ++++++++-----
 6 files changed, 84 insertions(+), 72 deletions(-)

diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 8b79893405..850681471d 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -1189,8 +1189,8 @@ Address CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable,
                                  variable->getName());
   }
 
-  if (auto refType = capture.fieldType()->getAs())
-    addr = EmitLoadOfReference(addr, refType);
+  if (capture.fieldType()->isReferenceType())
+    addr = EmitLoadOfReference(MakeAddrLValue(addr, capture.fieldType()));
 
   return addr;
 }
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 6837377de8..431ffa55d1 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -2160,22 +2160,30 @@ static LValue EmitThreadPrivateVarDeclLValue(
   return CGF.MakeAddrLValue(Addr, T, AlignmentSource::Decl);
 }
 
-Address CodeGenFunction::EmitLoadOfReference(Address Addr,
-                                             const ReferenceType *RefTy,
-                                             LValueBaseInfo *BaseInfo,
-                                             TBAAAccessInfo *TBAAInfo) {
-  llvm::Value *Ptr = Builder.CreateLoad(Addr);
-  return Address(Ptr, getNaturalTypeAlignment(RefTy->getPointeeType(),
-                                              BaseInfo, TBAAInfo,
-                                              /* forPointeeType= */ true));
-}
-
-LValue CodeGenFunction::EmitLoadOfReferenceLValue(Address RefAddr,
-                                                  const ReferenceType *RefTy) {
-  LValueBaseInfo BaseInfo;
-  TBAAAccessInfo TBAAInfo;
-  Address Addr = EmitLoadOfReference(RefAddr, RefTy, &BaseInfo, &TBAAInfo);
-  return MakeAddrLValue(Addr, RefTy->getPointeeType(), BaseInfo, TBAAInfo);
+Address
+CodeGenFunction::EmitLoadOfReference(LValue RefLVal,
+                                     LValueBaseInfo *PointeeBaseInfo,
+                                     TBAAAccessInfo *PointeeTBAAInfo) {
+  llvm::LoadInst *Load = Builder.CreateLoad(RefLVal.getAddress(),
+                                            RefLVal.isVolatile());
+  TBAAAccessInfo RefTBAAInfo = RefLVal.getTBAAInfo();
+  if (RefLVal.getBaseInfo().getMayAlias())
+    RefTBAAInfo = CGM.getTBAAMayAliasAccessInfo();
+  CGM.DecorateInstructionWithTBAA(Load, RefTBAAInfo);
+
+  CharUnits Align = getNaturalTypeAlignment(RefLVal.getType()->getPointeeType(),
+                                            PointeeBaseInfo, PointeeTBAAInfo,
+                                            /* forPointeeType= */ true);
+  return Address(Load, Align);
+}
+
+LValue CodeGenFunction::EmitLoadOfReferenceLValue(LValue RefLVal) {
+  LValueBaseInfo PointeeBaseInfo;
+  TBAAAccessInfo PointeeTBAAInfo;
+  Address PointeeAddr = EmitLoadOfReference(RefLVal, &PointeeBaseInfo,
+                                            &PointeeTBAAInfo);
+  return MakeAddrLValue(PointeeAddr, RefLVal.getType()->getPointeeType(),
+                        PointeeBaseInfo, PointeeTBAAInfo);
 }
 
 Address CodeGenFunction::EmitLoadOfPointer(Address Ptr,
@@ -2210,17 +2218,15 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
   V = EmitBitCastOfLValueToProperType(CGF, V, RealVarTy);
   CharUnits Alignment = CGF.getContext().getDeclAlign(VD);
   Address Addr(V, Alignment);
-  LValue LV;
   // Emit reference to the private copy of the variable if it is an OpenMP
   // threadprivate variable.
   if (CGF.getLangOpts().OpenMP && VD->hasAttr())
     return EmitThreadPrivateVarDeclLValue(CGF, VD, T, Addr, RealVarTy,
                                           E->getExprLoc());
-  if (auto RefTy = VD->getType()->getAs()) {
-    LV = CGF.EmitLoadOfReferenceLValue(Addr, RefTy);
-  } else {
-    LV = CGF.MakeAddrLValue(Addr, T, AlignmentSource::Decl);
-  }
+  LValue LV = VD->getType()->isReferenceType() ?
+      CGF.EmitLoadOfReferenceLValue(Addr, VD->getType(),
+                                    AlignmentSource::Decl) :
+      CGF.MakeAddrLValue(Addr, T, AlignmentSource::Decl);
   setObjCGCLValueClass(CGF.getContext(), E, LV);
   return LV;
 }
@@ -2338,8 +2344,9 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
       else if (CapturedStmtInfo) {
         auto I = LocalDeclMap.find(VD);
         if (I != LocalDeclMap.end()) {
-          if (auto RefTy = VD->getType()->getAs())
-            return EmitLoadOfReferenceLValue(I->second, RefTy);
+          if (VD->getType()->isReferenceType())
+            return EmitLoadOfReferenceLValue(I->second, VD->getType(),
+                                             AlignmentSource::Decl);
           return MakeAddrLValue(I->second, T);
         }
         LValue CapLVal =
@@ -2410,12 +2417,9 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
     }
 
     // Drill into reference types.
-    LValue LV;
-    if (auto RefTy = VD->getType()->getAs()) {
-      LV = EmitLoadOfReferenceLValue(addr, RefTy);
-    } else {
-      LV = MakeAddrLValue(addr, T, AlignmentSource::Decl);
-    }
+    LValue LV = VD->getType()->isReferenceType() ?
+        EmitLoadOfReferenceLValue(addr, VD->getType(), AlignmentSource::Decl) :
+        MakeAddrLValue(addr, T, AlignmentSource::Decl);
 
     bool isLocalStorage = VD->hasLocalStorage();
 
@@ -3748,7 +3752,7 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
   }
 
   Address addr = base.getAddress();
-  unsigned cvr = base.getVRQualifiers();
+  unsigned RecordCVR = base.getVRQualifiers();
   if (rec->isUnion()) {
     // For unions, there is no pointer adjustment.
     assert(!FieldType->isReferenceType() && "union has reference member");
@@ -3763,22 +3767,16 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
     addr = emitAddrOfFieldStorage(*this, addr, field);
 
     // If this is a reference field, load the reference right now.
-    if (const ReferenceType *refType = FieldType->getAs()) {
-      llvm::LoadInst *load = Builder.CreateLoad(addr, "ref");
-      if (cvr & Qualifiers::Volatile) load->setVolatile(true);
-
-      CGM.DecorateInstructionWithTBAA(load, FieldTBAAInfo);
-
-      FieldType = refType->getPointeeType();
-      CharUnits Align = getNaturalTypeAlignment(FieldType, &FieldBaseInfo,
-                                                &FieldTBAAInfo,
-                                                /* forPointeeType= */ true);
-      addr = Address(load, Align);
-
-      // Qualifiers on the struct don't apply to the referencee, and
-      // we'll pick up CVR from the actual type later, so reset these
-      // additional qualifiers now.
-      cvr = 0;
+    if (FieldType->isReferenceType()) {
+      LValue RefLVal = MakeAddrLValue(addr, FieldType, FieldBaseInfo,
+                                      FieldTBAAInfo);
+      if (RecordCVR & Qualifiers::Volatile)
+        RefLVal.getQuals().setVolatile(true);
+      addr = EmitLoadOfReference(RefLVal, &FieldBaseInfo, &FieldTBAAInfo);
+
+      // Qualifiers on the struct don't apply to the referencee.
+      RecordCVR = 0;
+      FieldType = FieldType->getPointeeType();
     }
   }
 
@@ -3793,7 +3791,7 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
     addr = EmitFieldAnnotations(field, addr);
 
   LValue LV = MakeAddrLValue(addr, FieldType, FieldBaseInfo, FieldTBAAInfo);
-  LV.getQuals().addCVRQualifiers(cvr);
+  LV.getQuals().addCVRQualifiers(RecordCVR);
 
   // __weak attribute on a field is ignored.
   if (LV.getQuals().getObjCGCAttr() == Qualifiers::Weak)
diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp
index b23d601eb8..0a798b8903 100644
--- a/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -1037,8 +1037,8 @@ static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
     if (auto *PtrTy = BaseTy->getAs())
       BaseLV = CGF.EmitLoadOfPointerLValue(BaseLV.getAddress(), PtrTy);
     else {
-      BaseLV = CGF.EmitLoadOfReferenceLValue(BaseLV.getAddress(),
-                                             BaseTy->castAs());
+      LValue RefLVal = CGF.MakeAddrLValue(BaseLV.getAddress(), BaseTy);
+      BaseLV = CGF.EmitLoadOfReferenceLValue(RefLVal);
     }
     BaseTy = BaseTy->getPointeeType();
   }
diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp
index f46ca23c55..df7f7802d3 100644
--- a/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/lib/CodeGen/CGStmtOpenMP.cpp
@@ -417,8 +417,7 @@ static llvm::Function *emitOutlinedFunctionPrologue(
       Address ArgAddr = ArgLVal.getAddress();
       if (!VarTy->isReferenceType()) {
         if (ArgLVal.getType()->isLValueReferenceType()) {
-          ArgAddr = CGF.EmitLoadOfReference(
-              ArgAddr, ArgLVal.getType()->castAs());
+          ArgAddr = CGF.EmitLoadOfReference(ArgLVal);
         } else if (!VarTy->isVariablyModifiedType() || !VarTy->isPointerType()) {
           assert(ArgLVal.getType()->isPointerType());
           ArgAddr = CGF.EmitLoadOfPointer(
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 210dbaa993..2d919876e2 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1952,10 +1952,17 @@ public:
                                            LValueBaseInfo *BaseInfo = nullptr,
                                            TBAAAccessInfo *TBAAInfo = nullptr);
 
-  Address EmitLoadOfReference(Address Ref, const ReferenceType *RefTy,
-                              LValueBaseInfo *BaseInfo = nullptr,
-                              TBAAAccessInfo *TBAAInfo = nullptr);
-  LValue EmitLoadOfReferenceLValue(Address Ref, const ReferenceType *RefTy);
+  Address EmitLoadOfReference(LValue RefLVal,
+                              LValueBaseInfo *PointeeBaseInfo = nullptr,
+                              TBAAAccessInfo *PointeeTBAAInfo = nullptr);
+  LValue EmitLoadOfReferenceLValue(LValue RefLVal);
+  LValue EmitLoadOfReferenceLValue(Address RefAddr, QualType RefTy,
+                                   AlignmentSource Source =
+                                       AlignmentSource::Type) {
+    LValue RefLVal = MakeAddrLValue(RefAddr, RefTy, LValueBaseInfo(Source),
+                                    CGM.getTBAAAccessInfo(RefTy));
+    return EmitLoadOfReferenceLValue(RefLVal);
+  }
 
   Address EmitLoadOfPointer(Address Ptr, const PointerType *PtrTy,
                             LValueBaseInfo *BaseInfo = nullptr,
diff --git a/test/CodeGen/tbaa-reference.cpp b/test/CodeGen/tbaa-reference.cpp
index aae6a82a8f..ecdbfbee7f 100644
--- a/test/CodeGen/tbaa-reference.cpp
+++ b/test/CodeGen/tbaa-reference.cpp
@@ -6,24 +6,32 @@ struct S;
 
 struct B {
   S &s;
-  B(S &s) : s(s) {}
-  void bar();
+  B(S &s);
+  S &get();
 };
 
-void foo(S &s) {
-  B b(s);
-  b.bar();
-}
-
-// CHECK-LABEL: _Z3fooR1S
-// Check initialization of the reference parameter in foo().
-// CHECK: store %struct.S* {{.*}}, %struct.S** {{.*}}, !tbaa [[TAG_pointer:!.*]]
-//
+B::B(S &s) : s(s) {
 // CHECK-LABEL: _ZN1BC2ER1S
-// TODO: Check loading of the reference parameter in B::B(S&).
-// Check initialization of B::s in B::B(S&).
+// Check initialization of the reference parameter.
+// CHECK: store %struct.S* {{.*}}, %struct.S** {{.*}}, !tbaa [[TAG_pointer:!.*]]
+
+// Check loading of the reference parameter.
+// CHECK: load %struct.S*, %struct.S** {{.*}}, !tbaa [[TAG_pointer]]
+
+// Check initialization of the reference member.
 // CHECK: store %struct.S* {{.*}}, %struct.S** {{.*}}, !tbaa [[TAG_pointer]]
-//
+}
+
+S &B::get() {
+// CHECK-LABEL: _ZN1B3getEv
+// Check that we access the reference as a structure member.
+// CHECK: load %struct.S*, %struct.S** {{.*}}, !tbaa [[TAG_B_s:!.*]]
+  return s;
+}
+
 // CHECK-DAG: [[TAG_pointer]] = !{[[TYPE_pointer:!.*]], [[TYPE_pointer]], i64 0}
+// CHECK-DAG: [[TAG_B_s]] = !{[[TYPE_B:!.*]], [[TYPE_pointer]], i64 0}
+//
+// CHECK-DAG: [[TYPE_B]] = !{!"_ZTS1B", [[TYPE_pointer]], i64 0}
 // CHECK-DAG: [[TYPE_pointer]] = !{!"any pointer", [[TYPE_char:!.*]], i64 0}
 // CHECK-DAG: [[TYPE_char]] = !{!"omnipotent char", {{!.*}}, i64 0}
-- 
GitLab


From a154e5b192b01366f25a62715a145a4cec3f8d23 Mon Sep 17 00:00:00 2001
From: Gabor Horvath 
Date: Mon, 30 Oct 2017 12:02:23 +0000
Subject: [PATCH 0133/1682] [analyzer] Make issue hash related tests more
 concise

Extend ExprInspection checker to make it possible to dump the issue hash of
arbitrary expressions. This change makes it possible to make issue hash related
tests more concise and also makes debugging issue hash related problems easier.

Differential Revision: https://reviews.llvm.org/D38844


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316899 91177308-0d34-0410-b5e6-96231b3b80d8
---
 .../clang/StaticAnalyzer/Checkers/Checkers.td |    4 -
 lib/StaticAnalyzer/Checkers/DebugCheckers.cpp |   33 -
 .../Checkers/ExprInspectionChecker.cpp        |   18 +-
 test/Analysis/bug_hash_test.cpp               | 1419 ++---------------
 test/Analysis/bug_hash_test.m                 | 1182 +-------------
 5 files changed, 125 insertions(+), 2531 deletions(-)

diff --git a/include/clang/StaticAnalyzer/Checkers/Checkers.td b/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 9eaf55f11c..be8b1494c8 100644
--- a/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -749,10 +749,6 @@ def ExplodedGraphViewer : Checker<"ViewExplodedGraph">,
   HelpText<"View Exploded Graphs using GraphViz">,
   DescFile<"DebugCheckers.cpp">;
 
-def BugHashDumper : Checker<"DumpBugHash">,
-  HelpText<"Dump the bug hash for all statements.">,
-  DescFile<"DebugCheckers.cpp">;
-
 } // end "debug"
 
 
diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index 2eef1688d4..810a33ed40 100644
--- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -16,7 +16,6 @@
 #include "clang/Analysis/Analyses/LiveVariables.h"
 #include "clang/Analysis/CallGraph.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/IssueHash.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -213,35 +212,3 @@ void ento::registerExplodedGraphViewer(CheckerManager &mgr) {
   mgr.registerChecker();
 }
 
-//===----------------------------------------------------------------------===//
-// DumpBugHash 
-//===----------------------------------------------------------------------===//
-
-namespace {
-class BugHashDumper : public Checker> {
-public:
-  mutable std::unique_ptr BT;
-
-  void checkPostStmt(const Stmt *S, CheckerContext &C) const {
-    if (!BT)
-      BT.reset(new BugType(this, "Dump hash components", "debug"));
-
-    ExplodedNode *N = C.generateNonFatalErrorNode();
-    if (!N)
-      return;
-
-    const LangOptions &Opts = C.getLangOpts();
-    const SourceManager &SM = C.getSourceManager();
-    FullSourceLoc FL(S->getLocStart(), SM);
-    std::string HashContent =
-        GetIssueString(SM, FL, getCheckName().getName(), BT->getCategory(),
-                       C.getLocationContext()->getDecl(), Opts);
-
-    C.emitReport(llvm::make_unique(*BT, HashContent, N));
-  }
-};
-}
-
-void ento::registerBugHashDumper(CheckerManager &mgr) {
-  mgr.registerChecker();
-}
diff --git a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index 4a581bddd9..0005ec470d 100644
--- a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -8,10 +8,11 @@
 //===----------------------------------------------------------------------===//
 
 #include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Checkers/SValExplainer.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/IssueHash.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Checkers/SValExplainer.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/Support/ScopedPrinter.h"
 
@@ -41,6 +42,7 @@ class ExprInspectionChecker : public CheckergetArg(0)->getLocStart(), SM);
+  std::string HashContent =
+      GetIssueString(SM, FL, getCheckName().getName(), "Category",
+                     C.getLocationContext()->getDecl(), Opts);
+
+  reportBug(HashContent, C);
+}
+
 void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
   Mgr.registerChecker();
 }
-
diff --git a/test/Analysis/bug_hash_test.cpp b/test/Analysis/bug_hash_test.cpp
index 0efcb5f7cd..f1fbb59a6a 100644
--- a/test/Analysis/bug_hash_test.cpp
+++ b/test/Analysis/bug_hash_test.cpp
@@ -1,1345 +1,118 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,debug.DumpBugHash -analyzer-output=plist %s -o %t.plist
-// RUN: FileCheck --input-file=%t.plist %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,debug.ExprInspection %s -verify
 
-int function(int p) {
-  return 5;
+constexpr int clang_analyzer_hashDump(int) { return 5; }
+
+void function(int) {
+  clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void function(int)$27$clang_analyzer_hashDump(5);$Category}}
 }
 
 namespace {
-int variadicParam(int p, ...) {
-  return 5;
-}
+void variadicParam(int, ...) {
+  clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void (anonymous namespace)::variadicParam(int, ...)$27$clang_analyzer_hashDump(5);$Category}}
 }
+} // namespace
 
-constexpr int f() { return 5; }
+constexpr int f() {
+  return clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$int f()$34$returnclang_analyzer_hashDump(5);$Category}}
+}
 
 namespace AA {
-  class X {
-    int priv;
-    X() : priv(5) { priv = 0; }
+class X {
+  X() {
+    clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$AA::X::X()$29$clang_analyzer_hashDump(5);$Category}}
+  }
 
-    static int static_method() {
-      return 5;
-    }
+  static void static_method() {
+    clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void AA::X::static_method()$29$clang_analyzer_hashDump(5);$Category}}
+    variadicParam(5);
+  }
 
-    int method() && {
-      class Y {
-        inline int method() const & {
-          return 5;
-        }
-      };
+  void method() && {
+    struct Y {
+      inline void method() const & {
+        clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void AA::X::method()::Y::method() const &$33$clang_analyzer_hashDump(5);$Category}}
+      }
+    };
 
-      return 5;
-    }
+    Y y;
+    y.method();
 
-    int OutOfLine();
+    clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void AA::X::method() &&$29$clang_analyzer_hashDump(5);$Category}}
+  }
 
-    X& operator=(int a) {
-      return *this;
-    }
+  void OutOfLine();
 
-    operator int() {
-      return 0;
-    }
+  X &operator=(int) {
+    clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$class AA::X & AA::X::operator=(int)$29$clang_analyzer_hashDump(5);$Category}}
+    return *this;
+  }
 
-    explicit operator float() {
-      return 0;
-    }
-  };
-}
+  operator int() {
+    clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$AA::X::operator int()$29$clang_analyzer_hashDump(5);$Category}}
+    return 0;
+  }
 
-int AA::X::OutOfLine() {
-  return 5;
+  explicit operator float() {
+    clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$AA::X::operator float()$29$clang_analyzer_hashDump(5);$Category}}
+    return 0;
+  }
+};
+} // namespace AA
+
+void AA::X::OutOfLine() {
+  clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void AA::X::OutOfLine()$27$clang_analyzer_hashDump(5);$Category}}
 }
 
 void testLambda() {
-  [] () {
-    return;
+  []() {
+    clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void testLambda()::(anonymous class)::operator()() const$29$clang_analyzer_hashDump(5);$Category}}
   }();
 }
 
-// CHECK: diagnostics
-// CHECK-NEXT: 
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line5
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line5
-// CHECK-NEXT:           col8
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line5
-// CHECK-NEXT:           col10
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line5
-// CHECK-NEXT:           col10
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line5
-// CHECK-NEXT:      col10
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line5
-// CHECK-NEXT:         col10
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line5
-// CHECK-NEXT:         col10
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$int function(int)$10$return5;$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$int function(int)$10$return5;$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$int function(int)$10$return5;$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_contexte7be204e83f8e5ad3c870ec011d5131d
-// CHECK-NEXT:  issue_context_kindfunction
-// CHECK-NEXT:  issue_contextfunction
-// CHECK-NEXT:  issue_hash_function_offset1
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line5
-// CHECK-NEXT:   col10
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line10
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line10
-// CHECK-NEXT:           col8
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line10
-// CHECK-NEXT:           col10
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line10
-// CHECK-NEXT:           col10
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line10
-// CHECK-NEXT:      col10
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line10
-// CHECK-NEXT:         col10
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line10
-// CHECK-NEXT:         col10
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$int (anonymous namespace)::variadicParam(int, ...)$10$return5;$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$int (anonymous namespace)::variadicParam(int, ...)$10$return5;$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$int (anonymous namespace)::variadicParam(int, ...)$10$return5;$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_contextbc5dc0507ee90f1d14259057d25fb2b9
-// CHECK-NEXT:  issue_context_kindfunction
-// CHECK-NEXT:  issue_contextvariadicParam
-// CHECK-NEXT:  issue_hash_function_offset1
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line10
-// CHECK-NEXT:   col10
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line14
-// CHECK-NEXT:           col21
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line14
-// CHECK-NEXT:           col26
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line14
-// CHECK-NEXT:           col28
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line14
-// CHECK-NEXT:           col28
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line14
-// CHECK-NEXT:      col28
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line14
-// CHECK-NEXT:         col28
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line14
-// CHECK-NEXT:         col28
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$int f()$28$constexprintf(){return5;}$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$int f()$28$constexprintf(){return5;}$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$int f()$28$constexprintf(){return5;}$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_contextf5471f52854dc14167fe96db50c4ba5f
-// CHECK-NEXT:  issue_context_kindfunction
-// CHECK-NEXT:  issue_contextf
-// CHECK-NEXT:  issue_hash_function_offset0
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line14
-// CHECK-NEXT:   col28
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line19
-// CHECK-NEXT:      col16
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line19
-// CHECK-NEXT:         col16
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line19
-// CHECK-NEXT:         col16
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$AA::X::X()$16$X():priv(5){priv=0;}$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$AA::X::X()$16$X():priv(5){priv=0;}$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$AA::X::X()$16$X():priv(5){priv=0;}$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_contextd23266517ac17d5ec5e2fbbdb1922af1
-// CHECK-NEXT:  issue_hash_function_offset0
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line19
-// CHECK-NEXT:   col16
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col16
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col16
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col21
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col24
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line19
-// CHECK-NEXT:      col21
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line19
-// CHECK-NEXT:         col21
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line19
-// CHECK-NEXT:         col24
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_context7bfcc45512a6a3f61dda6e3ecebc7384
-// CHECK-NEXT:  issue_hash_function_offset0
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line19
-// CHECK-NEXT:   col21
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col16
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col16
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col21
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col24
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col21
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col24
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col26
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col26
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line19
-// CHECK-NEXT:      col26
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line19
-// CHECK-NEXT:         col21
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line19
-// CHECK-NEXT:         col28
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_context95dbfbcdd1dd6401d262994c45d088be
-// CHECK-NEXT:  issue_hash_function_offset0
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line19
-// CHECK-NEXT:   col26
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col16
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col16
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col21
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col24
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col21
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col24
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col28
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col28
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line19
-// CHECK-NEXT:      col28
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line19
-// CHECK-NEXT:         col28
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line19
-// CHECK-NEXT:         col28
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$AA::X::X()$28$X():priv(5){priv=0;}$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$AA::X::X()$28$X():priv(5){priv=0;}$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$AA::X::X()$28$X():priv(5){priv=0;}$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_context064a01551caa8eca3202f1fd55b9c692
-// CHECK-NEXT:  issue_hash_function_offset0
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line19
-// CHECK-NEXT:   col28
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line22
-// CHECK-NEXT:           col7
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line22
-// CHECK-NEXT:           col12
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line22
-// CHECK-NEXT:           col14
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line22
-// CHECK-NEXT:           col14
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line22
-// CHECK-NEXT:      col14
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line22
-// CHECK-NEXT:         col14
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line22
-// CHECK-NEXT:         col14
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$int AA::X::static_method()$14$return5;$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$int AA::X::static_method()$14$return5;$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$int AA::X::static_method()$14$return5;$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_context651fcca72f8ad65771702903ecd5f68a
-// CHECK-NEXT:  issue_context_kindC++ method
-// CHECK-NEXT:  issue_contextstatic_method
-// CHECK-NEXT:  issue_hash_function_offset1
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line22
-// CHECK-NEXT:   col14
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line32
-// CHECK-NEXT:           col7
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line32
-// CHECK-NEXT:           col12
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line32
-// CHECK-NEXT:           col14
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line32
-// CHECK-NEXT:           col14
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line32
-// CHECK-NEXT:      col14
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line32
-// CHECK-NEXT:         col14
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line32
-// CHECK-NEXT:         col14
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$int AA::X::method() &&$14$return5;$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$int AA::X::method() &&$14$return5;$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$int AA::X::method() &&$14$return5;$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_contextc8ac8f24467234bea1f34adf5ad5007b
-// CHECK-NEXT:  issue_context_kindC++ method
-// CHECK-NEXT:  issue_contextmethod
-// CHECK-NEXT:  issue_hash_function_offset7
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line32
-// CHECK-NEXT:   col14
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line38
-// CHECK-NEXT:           col7
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line38
-// CHECK-NEXT:           col12
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line38
-// CHECK-NEXT:           col14
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line38
-// CHECK-NEXT:           col14
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line38
-// CHECK-NEXT:      col14
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line38
-// CHECK-NEXT:         col14
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line38
-// CHECK-NEXT:         col18
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$class AA::X & AA::X::operator=(int)$14$return*this;$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$class AA::X & AA::X::operator=(int)$14$return*this;$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$class AA::X & AA::X::operator=(int)$14$return*this;$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_contextb47cf7973c9b459d9c99c483e722db8e
-// CHECK-NEXT:  issue_context_kindC++ method
-// CHECK-NEXT:  issue_contextoperator=
-// CHECK-NEXT:  issue_hash_function_offset1
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line38
-// CHECK-NEXT:   col14
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line42
-// CHECK-NEXT:           col7
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line42
-// CHECK-NEXT:           col12
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line42
-// CHECK-NEXT:           col14
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line42
-// CHECK-NEXT:           col14
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line42
-// CHECK-NEXT:      col14
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line42
-// CHECK-NEXT:         col14
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line42
-// CHECK-NEXT:         col14
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$AA::X::operator int()$14$return0;$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$AA::X::operator int()$14$return0;$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$AA::X::operator int()$14$return0;$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_context0cbb0e1e5b03ba5b4f7f8f17504de671
-// CHECK-NEXT:  issue_hash_function_offset1
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line42
-// CHECK-NEXT:   col14
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line46
-// CHECK-NEXT:           col7
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line46
-// CHECK-NEXT:           col12
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line46
-// CHECK-NEXT:           col14
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line46
-// CHECK-NEXT:           col14
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line46
-// CHECK-NEXT:      col14
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line46
-// CHECK-NEXT:         col14
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line46
-// CHECK-NEXT:         col14
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$AA::X::operator float()$14$return0;$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$AA::X::operator float()$14$return0;$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$AA::X::operator float()$14$return0;$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_contextdf306826bf89e50c1b55e1d379a761b3
-// CHECK-NEXT:  issue_hash_function_offset1
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line46
-// CHECK-NEXT:   col14
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line52
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line52
-// CHECK-NEXT:           col8
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line52
-// CHECK-NEXT:           col10
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line52
-// CHECK-NEXT:           col10
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line52
-// CHECK-NEXT:      col10
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line52
-// CHECK-NEXT:         col10
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line52
-// CHECK-NEXT:         col10
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$int AA::X::OutOfLine()$10$return5;$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$int AA::X::OutOfLine()$10$return5;$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$int AA::X::OutOfLine()$10$return5;$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_context9dd7b17a6f62ed8c95b37a38cf71f3a9
-// CHECK-NEXT:  issue_context_kindC++ method
-// CHECK-NEXT:  issue_contextOutOfLine
-// CHECK-NEXT:  issue_hash_function_offset1
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line52
-// CHECK-NEXT:   col10
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line56
-// CHECK-NEXT:      col3
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line56
-// CHECK-NEXT:         col3
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line58
-// CHECK-NEXT:         col3
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$void testLambda()$3$[](){$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$void testLambda()$3$[](){$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$void testLambda()$3$[](){$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_context6ad4400e40885a78a0f57f585421a515
-// CHECK-NEXT:  issue_context_kindfunction
-// CHECK-NEXT:  issue_contexttestLambda
-// CHECK-NEXT:  issue_hash_function_offset1
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line56
-// CHECK-NEXT:   col3
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line56
-// CHECK-NEXT:      col3
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line56
-// CHECK-NEXT:         col3
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line58
-// CHECK-NEXT:         col5
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$void testLambda()$3$[](){$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$void testLambda()$3$[](){$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$void testLambda()$3$[](){$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_context6ad4400e40885a78a0f57f585421a515
-// CHECK-NEXT:  issue_context_kindfunction
-// CHECK-NEXT:  issue_contexttestLambda
-// CHECK-NEXT:  issue_hash_function_offset1
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line56
-// CHECK-NEXT:   col3
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line56
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line56
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line58
-// CHECK-NEXT:           col4
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line58
-// CHECK-NEXT:           col4
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line58
-// CHECK-NEXT:      col4
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line58
-// CHECK-NEXT:         col4
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line58
-// CHECK-NEXT:         col5
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$void testLambda()$4$}();$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$void testLambda()$4$}();$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$void testLambda()$4$}();$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_context378e6de75fb41b05bcef3950ad5ffa5e
-// CHECK-NEXT:  issue_context_kindfunction
-// CHECK-NEXT:  issue_contexttestLambda
-// CHECK-NEXT:  issue_hash_function_offset3
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line58
-// CHECK-NEXT:   col4
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT: 
+template 
+void f(T) {
+  clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void f(double)$27$clang_analyzer_hashDump(5);$Category}}
+                               // expected-warning@-1{{debug.ExprInspection$void f(int)$27$clang_analyzer_hashDump(5);$Category}}
+}
+
+template 
+struct TX {
+  void f(T) {
+    clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void TX::f(double)$29$clang_analyzer_hashDump(5);$Category}}
+                                 // expected-warning@-1{{debug.ExprInspection$void TX::f(int)$29$clang_analyzer_hashDump(5);$Category}}
+  }
+};
+
+template <>
+void f(long) {
+  clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void f(long)$27$clang_analyzer_hashDump(5);$Category}}
+}
+
+template <>
+struct TX {
+  void f(long) {
+    clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void TX::f(long)$29$clang_analyzer_hashDump(5);$Category}}
+  }
+};
+
+template 
+struct TTX {
+  template
+  void f(T, S) {
+    clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void TTX::f(int, int)$29$clang_analyzer_hashDump(5);$Category}}
+  }
+};
+
+void g() {
+  TX x;
+  TX y;
+  TX xl;
+  x.f(1);
+  xl.f(1);
+  f(5);
+  f(3.0);
+  y.f(2);
+  TTX z;
+  z.f(5, 5);
+  f(5l);
+}
diff --git a/test/Analysis/bug_hash_test.m b/test/Analysis/bug_hash_test.m
index 1e99d3c0b9..fbb70e5d62 100644
--- a/test/Analysis/bug_hash_test.m
+++ b/test/Analysis/bug_hash_test.m
@@ -1,5 +1,6 @@
-// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,debug.DumpBugHash -analyzer-output=plist %s -o %t.plist
-// RUN: FileCheck --input-file=%t.plist %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,debug.ExprInspection %s -verify
+
+void clang_analyzer_hashDump(int);
 
 @protocol NSObject
 + (id)alloc;
@@ -15,1178 +16,21 @@ __attribute__((objc_root_class))
 @end
 
 @implementation NSObject
++ (id)alloc {
+  return 0;
+}
+- (id)init {
+  return self;
+}
 - (void)method:(int)arg param:(int)arg2 {
-  arg = 5;
-  return;
+  clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$NSObject::method:param:$27$clang_analyzer_hashDump(5);$Category}}
 }
 @end
 
 
 void testBlocks() {
   int x = 5;
-  ^{ int y = 1 + x; }();
+  ^{
+    clang_analyzer_hashDump(x); // expected-warning {{debug.ExprInspection$$29$clang_analyzer_hashDump(x);$Category}}
+  }();
 }
-
-// CHECK: diagnostics
-// CHECK-NEXT: 
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col5
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col7
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col7
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line19
-// CHECK-NEXT:      col7
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line19
-// CHECK-NEXT:         col3
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line19
-// CHECK-NEXT:         col9
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$NSObject::method:param:$3$arg=5;$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$NSObject::method:param:$3$arg=5;$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$NSObject::method:param:$3$arg=5;$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_contextf9f569e94382c1f969aabd304581b294
-// CHECK-NEXT:  issue_context_kindObjective-C method
-// CHECK-NEXT:  issue_contextmethod:param:
-// CHECK-NEXT:  issue_hash_function_offset1
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line19
-// CHECK-NEXT:   col7
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col5
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col9
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line19
-// CHECK-NEXT:           col9
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line19
-// CHECK-NEXT:      col9
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line19
-// CHECK-NEXT:         col9
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line19
-// CHECK-NEXT:         col9
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$NSObject::method:param:$9$arg=5;$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$NSObject::method:param:$9$arg=5;$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$NSObject::method:param:$9$arg=5;$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_contextca44d6aa882ee55f76e11a80d5a66372
-// CHECK-NEXT:  issue_context_kindObjective-C method
-// CHECK-NEXT:  issue_contextmethod:param:
-// CHECK-NEXT:  issue_hash_function_offset1
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line19
-// CHECK-NEXT:   col9
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line26
-// CHECK-NEXT:      col3
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line26
-// CHECK-NEXT:         col3
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line26
-// CHECK-NEXT:         col7
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$void testBlocks()$3$intx=5;$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$void testBlocks()$3$intx=5;$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$void testBlocks()$3$intx=5;$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_context84ec7c854c1c7849abfa03f7f20b4f06
-// CHECK-NEXT:  issue_context_kindfunction
-// CHECK-NEXT:  issue_contexttestBlocks
-// CHECK-NEXT:  issue_hash_function_offset1
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line26
-// CHECK-NEXT:   col3
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col5
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col11
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col11
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line26
-// CHECK-NEXT:      col11
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line26
-// CHECK-NEXT:         col11
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line26
-// CHECK-NEXT:         col11
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$void testBlocks()$11$intx=5;$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$void testBlocks()$11$intx=5;$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$void testBlocks()$11$intx=5;$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_contextf91db2d7b129ed60e7c9caf6f8a84d5c
-// CHECK-NEXT:  issue_context_kindfunction
-// CHECK-NEXT:  issue_contexttestBlocks
-// CHECK-NEXT:  issue_hash_function_offset1
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line26
-// CHECK-NEXT:   col11
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col5
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line27
-// CHECK-NEXT:      col3
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col3
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col21
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_context0f1e9483a8ff59e787eaac18b68068ad
-// CHECK-NEXT:  issue_context_kindfunction
-// CHECK-NEXT:  issue_contexttestBlocks
-// CHECK-NEXT:  issue_hash_function_offset2
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line27
-// CHECK-NEXT:   col3
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col5
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line27
-// CHECK-NEXT:      col3
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col3
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col23
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_context0f1e9483a8ff59e787eaac18b68068ad
-// CHECK-NEXT:  issue_context_kindfunction
-// CHECK-NEXT:  issue_contexttestBlocks
-// CHECK-NEXT:  issue_hash_function_offset2
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line27
-// CHECK-NEXT:   col3
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col5
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line27
-// CHECK-NEXT:      col3
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col3
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col23
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     Calling anonymous block
-// CHECK-NEXT:     message
-// CHECK-NEXT:     Calling anonymous block
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line27
-// CHECK-NEXT:      col3
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth1
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     Entered call from 'testBlocks'
-// CHECK-NEXT:     message
-// CHECK-NEXT:     Entered call from 'testBlocks'
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col6
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col8
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line27
-// CHECK-NEXT:      col6
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col6
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col10
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth1
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$$6$^{inty=1+x;}();$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$$6$^{inty=1+x;}();$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$$6$^{inty=1+x;}();$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_context8a8e42efc427e1334b77d510d3fb6361
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line27
-// CHECK-NEXT:   col6
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col5
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line27
-// CHECK-NEXT:      col3
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col3
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col23
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     Calling anonymous block
-// CHECK-NEXT:     message
-// CHECK-NEXT:     Calling anonymous block
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line27
-// CHECK-NEXT:      col3
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth1
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     Entered call from 'testBlocks'
-// CHECK-NEXT:     message
-// CHECK-NEXT:     Entered call from 'testBlocks'
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col6
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col8
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col6
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col8
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col14
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col14
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line27
-// CHECK-NEXT:      col14
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col14
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col14
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth1
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$$14$^{inty=1+x;}();$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$$14$^{inty=1+x;}();$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$$14$^{inty=1+x;}();$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_context6d6028808f1d47ec5b74a417e96c2a02
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line27
-// CHECK-NEXT:   col14
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col5
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line27
-// CHECK-NEXT:      col3
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col3
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col23
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     Calling anonymous block
-// CHECK-NEXT:     message
-// CHECK-NEXT:     Calling anonymous block
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line27
-// CHECK-NEXT:      col3
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth1
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     Entered call from 'testBlocks'
-// CHECK-NEXT:     message
-// CHECK-NEXT:     Entered call from 'testBlocks'
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col16
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col16
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line27
-// CHECK-NEXT:      col16
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col14
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col18
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth1
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$$14$^{inty=1+x;}();$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$$14$^{inty=1+x;}();$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$$14$^{inty=1+x;}();$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_context162138b23629276baad7dd3e8051fd6f
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line27
-// CHECK-NEXT:   col16
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT:   path
-// CHECK-NEXT:   
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line26
-// CHECK-NEXT:           col5
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line27
-// CHECK-NEXT:      col3
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col3
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col23
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth0
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     Calling anonymous block
-// CHECK-NEXT:     message
-// CHECK-NEXT:     Calling anonymous block
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line27
-// CHECK-NEXT:      col3
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth1
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     Entered call from 'testBlocks'
-// CHECK-NEXT:     message
-// CHECK-NEXT:     Entered call from 'testBlocks'
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col3
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col6
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col8
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindcontrol
-// CHECK-NEXT:     edges
-// CHECK-NEXT:      
-// CHECK-NEXT:       
-// CHECK-NEXT:        start
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col6
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col8
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:        end
-// CHECK-NEXT:         
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col18
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:          
-// CHECK-NEXT:           line27
-// CHECK-NEXT:           col18
-// CHECK-NEXT:           file0
-// CHECK-NEXT:          
-// CHECK-NEXT:         
-// CHECK-NEXT:       
-// CHECK-NEXT:      
-// CHECK-NEXT:    
-// CHECK-NEXT:    
-// CHECK-NEXT:     kindevent
-// CHECK-NEXT:     location
-// CHECK-NEXT:     
-// CHECK-NEXT:      line27
-// CHECK-NEXT:      col18
-// CHECK-NEXT:      file0
-// CHECK-NEXT:     
-// CHECK-NEXT:     ranges
-// CHECK-NEXT:     
-// CHECK-NEXT:       
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col18
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:        
-// CHECK-NEXT:         line27
-// CHECK-NEXT:         col18
-// CHECK-NEXT:         file0
-// CHECK-NEXT:        
-// CHECK-NEXT:       
-// CHECK-NEXT:     
-// CHECK-NEXT:     depth1
-// CHECK-NEXT:     extended_message
-// CHECK-NEXT:     debug.DumpBugHash$$18$^{inty=1+x;}();$debug
-// CHECK-NEXT:     message
-// CHECK-NEXT:     debug.DumpBugHash$$18$^{inty=1+x;}();$debug
-// CHECK-NEXT:    
-// CHECK-NEXT:   
-// CHECK-NEXT:   descriptiondebug.DumpBugHash$$18$^{inty=1+x;}();$debug
-// CHECK-NEXT:   categorydebug
-// CHECK-NEXT:   typeDump hash components
-// CHECK-NEXT:   check_namedebug.DumpBugHash
-// CHECK-NEXT:   
-// CHECK-NEXT:   issue_hash_content_of_line_in_contextb3add78bcab0ebc3da3b640081057525
-// CHECK-NEXT:  location
-// CHECK-NEXT:  
-// CHECK-NEXT:   line27
-// CHECK-NEXT:   col18
-// CHECK-NEXT:   file0
-// CHECK-NEXT:  
-// CHECK-NEXT:  
-// CHECK-NEXT: 
-- 
GitLab


From 1157fbd7d668f9579b5a633dd245657bb940076b Mon Sep 17 00:00:00 2001
From: Gabor Horvath 
Date: Mon, 30 Oct 2017 12:16:07 +0000
Subject: [PATCH 0134/1682] [analyzer] Use the signature of the primary
 template for issue hash calculation

Now when a template is instantiated more times and there is a bug found in the
instantiations the issue hash will be different for each instantiation even if
every other property of the bug (path, message, location) is the same.

This patch aims to resolve this issue. Note that explicit specializations still
generate different hashes but that is intended.

Differential Revision: https://reviews.llvm.org/D38728


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316900 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/StaticAnalyzer/Core/IssueHash.cpp |  7 +++++++
 test/Analysis/bug_hash_test.cpp       | 14 +++++++++-----
 test/Analysis/edges-new.mm            |  2 +-
 3 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/lib/StaticAnalyzer/Core/IssueHash.cpp b/lib/StaticAnalyzer/Core/IssueHash.cpp
index abdea88b1d..274ebe7a94 100644
--- a/lib/StaticAnalyzer/Core/IssueHash.cpp
+++ b/lib/StaticAnalyzer/Core/IssueHash.cpp
@@ -33,6 +33,13 @@ static std::string GetSignature(const FunctionDecl *Target) {
     return "";
   std::string Signature;
 
+  // When a flow sensitive bug happens in templated code we should not generate
+  // distinct hash value for every instantiation. Use the signature from the
+  // primary template.
+  if (const FunctionDecl *InstantiatedFrom =
+          Target->getTemplateInstantiationPattern())
+    Target = InstantiatedFrom;
+
   if (!isa(Target) && !isa(Target) &&
       !isa(Target))
     Signature.append(Target->getReturnType().getAsString()).append(" ");
diff --git a/test/Analysis/bug_hash_test.cpp b/test/Analysis/bug_hash_test.cpp
index f1fbb59a6a..f397d181e6 100644
--- a/test/Analysis/bug_hash_test.cpp
+++ b/test/Analysis/bug_hash_test.cpp
@@ -71,15 +71,13 @@ void testLambda() {
 
 template 
 void f(T) {
-  clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void f(double)$27$clang_analyzer_hashDump(5);$Category}}
-                               // expected-warning@-1{{debug.ExprInspection$void f(int)$27$clang_analyzer_hashDump(5);$Category}}
+  clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void f(T)$27$clang_analyzer_hashDump(5);$Category}}
 }
 
 template 
 struct TX {
   void f(T) {
-    clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void TX::f(double)$29$clang_analyzer_hashDump(5);$Category}}
-                                 // expected-warning@-1{{debug.ExprInspection$void TX::f(int)$29$clang_analyzer_hashDump(5);$Category}}
+    clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void TX::f(T)$29$clang_analyzer_hashDump(5);$Category}}
   }
 };
 
@@ -99,11 +97,17 @@ template 
 struct TTX {
   template
   void f(T, S) {
-    clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void TTX::f(int, int)$29$clang_analyzer_hashDump(5);$Category}}
+    clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void TTX::f(T, S)$29$clang_analyzer_hashDump(5);$Category}}
   }
 };
 
 void g() {
+  // TX and TX is instantiated from the same code with the same
+  // source locations. The same error happining in both of the instantiations
+  // should share the common hash. This means we should not include the
+  // template argument for these types in the function signature.
+  // Note that, we still want the hash to be different for explicit
+  // specializations.
   TX x;
   TX y;
   TX xl;
diff --git a/test/Analysis/edges-new.mm b/test/Analysis/edges-new.mm
index 47a125ab09..f310f1bfa1 100644
--- a/test/Analysis/edges-new.mm
+++ b/test/Analysis/edges-new.mm
@@ -20288,7 +20288,7 @@ namespace rdar14960554 {
 // CHECK-NEXT:    typeBad deallocator
 // CHECK-NEXT:    check_nameunix.MismatchedDeallocator
 // CHECK-NEXT:    
-// CHECK-NEXT:    issue_hash_content_of_line_in_contextd9dbbf68db41ab74e2158f4b131abe34
+// CHECK-NEXT:    issue_hash_content_of_line_in_context046c88d1c91ff46d6506dff5ff880756
 // CHECK-NEXT:   issue_hash_function_offset0
 // CHECK-NEXT:   location
 // CHECK-NEXT:   
-- 
GitLab


From bd3b05d2cc22423f7eb44ff6bf948b44cc605309 Mon Sep 17 00:00:00 2001
From: Krasimir Georgiev 
Date: Mon, 30 Oct 2017 14:01:50 +0000
Subject: [PATCH 0135/1682] [clang-format] Format raw string literals

Summary:
This patch adds raw string literal formatting.

Reviewers: djasper, klimek

Reviewed By: klimek

Subscribers: klimek, mgorny

Differential Revision: https://reviews.llvm.org/D35943

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316903 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Format/Format.h             |  36 ++
 lib/Format/ContinuationIndenter.cpp       | 159 ++++-
 lib/Format/ContinuationIndenter.h         |  37 +-
 lib/Format/Format.cpp                     |  96 ++-
 lib/Format/FormatInternal.h               |  79 +++
 lib/Format/FormatTokenLexer.cpp           |   4 +-
 lib/Format/FormatTokenLexer.h             |   2 +-
 lib/Format/NamespaceEndCommentsFixer.cpp  |   4 +-
 lib/Format/NamespaceEndCommentsFixer.h    |   2 +-
 lib/Format/SortJavaScriptImports.cpp      |  10 +-
 lib/Format/TokenAnalyzer.cpp              |  35 +-
 lib/Format/TokenAnalyzer.h                |  47 +-
 lib/Format/TokenAnnotator.cpp             |   3 +-
 lib/Format/TokenAnnotator.h               |   5 +-
 lib/Format/UnwrappedLineFormatter.cpp     |  69 +-
 lib/Format/UnwrappedLineFormatter.h       |   8 +-
 lib/Format/UnwrappedLineParser.cpp        |   9 +-
 lib/Format/UnwrappedLineParser.h          |   7 +
 lib/Format/UsingDeclarationsSorter.cpp    |   4 +-
 lib/Format/UsingDeclarationsSorter.h      |   2 +-
 lib/Format/WhitespaceManager.cpp          |   5 +
 lib/Format/WhitespaceManager.h            |   2 +
 unittests/Format/CMakeLists.txt           |   1 +
 unittests/Format/FormatTest.cpp           |  14 +
 unittests/Format/FormatTestRawStrings.cpp | 733 ++++++++++++++++++++++
 25 files changed, 1266 insertions(+), 107 deletions(-)
 create mode 100644 lib/Format/FormatInternal.h
 create mode 100644 unittests/Format/FormatTestRawStrings.cpp

diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h
index 302ced3f78..a0e42f4e30 100644
--- a/include/clang/Format/Format.h
+++ b/include/clang/Format/Format.h
@@ -1327,6 +1327,41 @@ struct FormatStyle {
   /// \brief Pointer and reference alignment style.
   PointerAlignmentStyle PointerAlignment;
 
+  /// See documentation of ``RawStringFormats``.
+  struct RawStringFormat {
+    /// \brief The delimiter that this raw string format matches.
+    std::string Delimiter;
+    /// \brief The language of this raw string.
+    LanguageKind Language;
+    /// \brief The style name on which this raw string format is based on.
+    /// If not specified, the raw string format is based on the style that this
+    /// format is based on.
+    std::string BasedOnStyle;
+    bool operator==(const RawStringFormat &Other) const {
+      return Delimiter == Other.Delimiter && Language == Other.Language &&
+             BasedOnStyle == Other.BasedOnStyle;
+    }
+  };
+
+  /// \brief Raw string delimiters denoting that the raw string contents are
+  /// code in a particular language and can be reformatted.
+  ///
+  /// A raw string with a matching delimiter will be reformatted assuming the
+  /// specified language based on a predefined style given by 'BasedOnStyle'.
+  /// If 'BasedOnStyle' is not found, the formatting is based on llvm style.
+  ///
+  /// To configure this in the .clang-format file, use:
+  /// \code{.yaml}
+  ///   RawStringFormats:
+  ///     - Delimiter: 'pb'
+  ///       Language:  TextProto
+  ///       BasedOnStyle: llvm
+  ///     - Delimiter: 'proto'
+  ///       Language:  TextProto
+  ///       BasedOnStyle: google
+  /// \endcode
+  std::vector RawStringFormats;
+
   /// \brief If ``true``, clang-format will attempt to re-flow comments.
   /// \code
   ///    false:
@@ -1592,6 +1627,7 @@ struct FormatStyle {
            PenaltyExcessCharacter == R.PenaltyExcessCharacter &&
            PenaltyReturnTypeOnItsOwnLine == R.PenaltyReturnTypeOnItsOwnLine &&
            PointerAlignment == R.PointerAlignment &&
+           RawStringFormats == R.RawStringFormats &&
            SpaceAfterCStyleCast == R.SpaceAfterCStyleCast &&
            SpaceAfterTemplateKeyword == R.SpaceAfterTemplateKeyword &&
            SpaceBeforeAssignmentOperators == R.SpaceBeforeAssignmentOperators &&
diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp
index b57b8de2e7..4f624dd2fb 100644
--- a/lib/Format/ContinuationIndenter.cpp
+++ b/lib/Format/ContinuationIndenter.cpp
@@ -14,6 +14,7 @@
 
 #include "ContinuationIndenter.h"
 #include "BreakableToken.h"
+#include "FormatInternal.h"
 #include "WhitespaceManager.h"
 #include "clang/Basic/OperatorPrecedence.h"
 #include "clang/Basic/SourceManager.h"
@@ -76,6 +77,53 @@ static bool opensProtoMessageField(const FormatToken &LessTok,
            (LessTok.Previous && LessTok.Previous->is(tok::equal))));
 }
 
+// Returns the delimiter of a raw string literal, or None if TokenText is not
+// the text of a raw string literal. The delimiter could be the empty string.
+// For example, the delimiter of R"deli(cont)deli" is deli.
+static llvm::Optional getRawStringDelimiter(StringRef TokenText) {
+  if (TokenText.size() < 5 // The smallest raw string possible is 'R"()"'.
+      || !TokenText.startswith("R\"") || !TokenText.endswith("\""))
+    return None;
+
+  // A raw string starts with 'R"(' and delimiter is ascii and has
+  // size at most 16 by the standard, so the first '(' must be among the first
+  // 19 bytes.
+  size_t LParenPos = TokenText.substr(0, 19).find_first_of('(');
+  if (LParenPos == StringRef::npos)
+    return None;
+  StringRef Delimiter = TokenText.substr(2, LParenPos - 2);
+
+  // Check that the string ends in ')Delimiter"'.
+  size_t RParenPos = TokenText.size() - Delimiter.size() - 2;
+  if (TokenText[RParenPos] != ')')
+    return None;
+  if (!TokenText.substr(RParenPos + 1).startswith(Delimiter))
+    return None;
+  return Delimiter;
+}
+
+RawStringFormatStyleManager::RawStringFormatStyleManager(
+    const FormatStyle &CodeStyle) {
+  for (const auto &RawStringFormat : CodeStyle.RawStringFormats) {
+    FormatStyle Style;
+    if (!getPredefinedStyle(RawStringFormat.BasedOnStyle,
+                            RawStringFormat.Language, &Style)) {
+      Style = getLLVMStyle();
+      Style.Language = RawStringFormat.Language;
+    }
+    Style.ColumnLimit = CodeStyle.ColumnLimit;
+    DelimiterStyle.insert({RawStringFormat.Delimiter, Style});
+  }
+}
+
+llvm::Optional
+RawStringFormatStyleManager::get(StringRef Delimiter) const {
+  auto It = DelimiterStyle.find(Delimiter);
+  if (It == DelimiterStyle.end())
+    return None;
+  return It->second;
+}
+
 ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
                                            const AdditionalKeywords &Keywords,
                                            const SourceManager &SourceMgr,
@@ -85,14 +133,18 @@ ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style,
     : Style(Style), Keywords(Keywords), SourceMgr(SourceMgr),
       Whitespaces(Whitespaces), Encoding(Encoding),
       BinPackInconclusiveFunctions(BinPackInconclusiveFunctions),
-      CommentPragmasRegex(Style.CommentPragmas) {}
+      CommentPragmasRegex(Style.CommentPragmas), RawStringFormats(Style) {}
 
 LineState ContinuationIndenter::getInitialState(unsigned FirstIndent,
+                                                unsigned FirstStartColumn,
                                                 const AnnotatedLine *Line,
                                                 bool DryRun) {
   LineState State;
   State.FirstIndent = FirstIndent;
-  State.Column = FirstIndent;
+  if (FirstStartColumn && Line->First->NewlinesBefore == 0)
+    State.Column = FirstStartColumn;
+  else
+    State.Column = FirstIndent;
   // With preprocessor directive indentation, the line starts on column 0
   // since it's indented after the hash, but FirstIndent is set to the
   // preprocessor indent.
@@ -1216,6 +1268,89 @@ void ContinuationIndenter::moveStateToNewBlock(LineState &State) {
   State.Stack.back().BreakBeforeParameter = true;
 }
 
+static unsigned getLastLineEndColumn(StringRef Text, unsigned StartColumn,
+                                     unsigned TabWidth,
+                                     encoding::Encoding Encoding) {
+  size_t LastNewlinePos = Text.find_last_of("\n");
+  if (LastNewlinePos == StringRef::npos) {
+    return StartColumn +
+           encoding::columnWidthWithTabs(Text, StartColumn, TabWidth, Encoding);
+  } else {
+    return encoding::columnWidthWithTabs(Text.substr(LastNewlinePos),
+                                         /*StartColumn=*/0, TabWidth, Encoding);
+  }
+}
+
+unsigned ContinuationIndenter::reformatRawStringLiteral(
+    const FormatToken &Current, unsigned StartColumn, LineState &State,
+    StringRef Delimiter, const FormatStyle &RawStringStyle, bool DryRun) {
+  // The text of a raw string is between the leading 'R"delimiter(' and the
+  // trailing 'delimiter)"'.
+  unsigned PrefixSize = 3 + Delimiter.size();
+  unsigned SuffixSize = 2 + Delimiter.size();
+
+  // The first start column is the column the raw text starts.
+  unsigned FirstStartColumn = StartColumn + PrefixSize;
+
+  // The next start column is the intended indentation a line break inside
+  // the raw string at level 0. It is determined by the following rules:
+  //   - if the content starts on newline, it is one level more than the current
+  //     indent, and
+  //   - if the content does not start on a newline, it is the first start
+  //     column.
+  // These rules have the advantage that the formatted content both does not
+  // violate the rectangle rule and visually flows within the surrounding
+  // source.
+  bool ContentStartsOnNewline = Current.TokenText[PrefixSize] == '\n';
+  unsigned NextStartColumn = ContentStartsOnNewline
+                                 ? State.Stack.back().Indent + Style.IndentWidth
+                                 : FirstStartColumn;
+
+  // The last start column is the column the raw string suffix starts if it is
+  // put on a newline.
+  // The last start column is the intended indentation of the raw string postfix
+  // if it is put on a newline. It is determined by the following rules:
+  //   - if the raw string prefix starts on a newline, it is the column where
+  //     that raw string prefix starts, and
+  //   - if the raw string prefix does not start on a newline, it is the current
+  //     indent.
+  unsigned LastStartColumn = Current.NewlinesBefore
+                                 ? FirstStartColumn - PrefixSize
+                                 : State.Stack.back().Indent;
+
+  std::string RawText =
+      Current.TokenText.substr(PrefixSize).drop_back(SuffixSize);
+
+  std::pair Fixes = internal::reformat(
+      RawStringStyle, RawText, {tooling::Range(0, RawText.size())},
+      FirstStartColumn, NextStartColumn, LastStartColumn, "",
+      /*FormattingAttemptStatus=*/nullptr);
+
+  auto NewCode = applyAllReplacements(RawText, Fixes.first);
+  tooling::Replacements NoFixes;
+  if (!NewCode) {
+    State.Column += Current.ColumnWidth;
+    return 0;
+  }
+  if (!DryRun) {
+    SourceLocation OriginLoc =
+        Current.Tok.getLocation().getLocWithOffset(PrefixSize);
+    for (const tooling::Replacement &Fix : Fixes.first) {
+      auto Err = Whitespaces.addReplacement(tooling::Replacement(
+          SourceMgr, OriginLoc.getLocWithOffset(Fix.getOffset()),
+          Fix.getLength(), Fix.getReplacementText()));
+      if (Err) {
+        llvm::errs() << "Failed to reformat raw string: "
+                     << llvm::toString(std::move(Err)) << "\n";
+      }
+    }
+  }
+  unsigned RawLastLineEndColumn = getLastLineEndColumn(
+      *NewCode, FirstStartColumn, Style.TabWidth, Encoding);
+  State.Column = RawLastLineEndColumn + SuffixSize;
+  return Fixes.second;
+}
+
 unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current,
                                                  LineState &State) {
   if (!Current.IsMultiline)
@@ -1238,9 +1373,18 @@ unsigned ContinuationIndenter::addMultilineToken(const FormatToken &Current,
 unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
                                                     LineState &State,
                                                     bool DryRun) {
-  // Don't break multi-line tokens other than block comments. Instead, just
-  // update the state.
-  if (Current.isNot(TT_BlockComment) && Current.IsMultiline)
+  // Compute the raw string style to use in case this is a raw string literal
+  // that can be reformatted.
+  llvm::Optional Delimiter = None;
+  llvm::Optional RawStringStyle = None;
+  if (Current.isStringLiteral())
+    Delimiter = getRawStringDelimiter(Current.TokenText);
+  if (Delimiter)
+    RawStringStyle = RawStringFormats.get(*Delimiter);
+
+  // Don't break multi-line tokens other than block comments and raw string
+  // literals. Instead, just update the state.
+  if (Current.isNot(TT_BlockComment) && !RawStringStyle && Current.IsMultiline)
     return addMultilineToken(Current, State);
 
   // Don't break implicit string literals or import statements.
@@ -1275,6 +1419,11 @@ unsigned ContinuationIndenter::breakProtrudingToken(const FormatToken &Current,
     if (Current.IsUnterminatedLiteral)
       return 0;
 
+    if (RawStringStyle) {
+      RawStringStyle->ColumnLimit = ColumnLimit;
+      return reformatRawStringLiteral(Current, StartColumn, State, *Delimiter,
+                                      *RawStringStyle, DryRun);
+    } 
     StringRef Text = Current.TokenText;
     StringRef Prefix;
     StringRef Postfix;
diff --git a/lib/Format/ContinuationIndenter.h b/lib/Format/ContinuationIndenter.h
index 631129c1ea..3bc9929b3d 100644
--- a/lib/Format/ContinuationIndenter.h
+++ b/lib/Format/ContinuationIndenter.h
@@ -20,6 +20,8 @@
 #include "FormatToken.h"
 #include "clang/Format/Format.h"
 #include "llvm/Support/Regex.h"
+#include 
+#include 
 
 namespace clang {
 class SourceManager;
@@ -30,8 +32,17 @@ class AnnotatedLine;
 struct FormatToken;
 struct LineState;
 struct ParenState;
+struct RawStringFormatStyleManager;
 class WhitespaceManager;
 
+struct RawStringFormatStyleManager {
+  llvm::StringMap DelimiterStyle;
+
+  RawStringFormatStyleManager(const FormatStyle &CodeStyle);
+
+  llvm::Optional get(StringRef Delimiter) const;
+};
+
 class ContinuationIndenter {
 public:
   /// \brief Constructs a \c ContinuationIndenter to format \p Line starting in
@@ -44,9 +55,11 @@ public:
                        bool BinPackInconclusiveFunctions);
 
   /// \brief Get the initial state, i.e. the state after placing \p Line's
-  /// first token at \p FirstIndent.
-  LineState getInitialState(unsigned FirstIndent, const AnnotatedLine *Line,
-                            bool DryRun);
+  /// first token at \p FirstIndent. When reformatting a fragment of code, as in
+  /// the case of formatting inside raw string literals, \p FirstStartColumn is
+  /// the column at which the state of the parent formatter is.
+  LineState getInitialState(unsigned FirstIndent, unsigned FirstStartColumn,
+                            const AnnotatedLine *Line, bool DryRun);
 
   // FIXME: canBreak and mustBreak aren't strictly indentation-related. Find a
   // better home.
@@ -88,15 +101,24 @@ private:
   /// \brief Update 'State' with the next token opening a nested block.
   void moveStateToNewBlock(LineState &State);
 
+  /// \brief Reformats a raw string literal.
+  /// 
+  /// \returns An extra penalty induced by reformatting the token.
+  unsigned reformatRawStringLiteral(const FormatToken &Current,
+                                    unsigned StartColumn, LineState &State,
+                                    StringRef Delimiter,
+                                    const FormatStyle &RawStringStyle,
+                                    bool DryRun);
+
   /// \brief If the current token sticks out over the end of the line, break
   /// it if possible.
   ///
   /// \returns An extra penalty if a token was broken, otherwise 0.
   ///
-  /// The returned penalty will cover the cost of the additional line breaks and
-  /// column limit violation in all lines except for the last one. The penalty
-  /// for the column limit violation in the last line (and in single line
-  /// tokens) is handled in \c addNextStateToQueue.
+  /// The returned penalty will cover the cost of the additional line breaks
+  /// and column limit violation in all lines except for the last one. The
+  /// penalty for the column limit violation in the last line (and in single
+  /// line tokens) is handled in \c addNextStateToQueue.
   unsigned breakProtrudingToken(const FormatToken &Current, LineState &State,
                                 bool DryRun);
 
@@ -143,6 +165,7 @@ private:
   encoding::Encoding Encoding;
   bool BinPackInconclusiveFunctions;
   llvm::Regex CommentPragmasRegex;
+  const RawStringFormatStyleManager RawStringFormats;
 };
 
 struct ParenState {
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index cb0a010512..ecc2bb7b84 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -16,6 +16,7 @@
 #include "clang/Format/Format.h"
 #include "AffectedRangeManager.h"
 #include "ContinuationIndenter.h"
+#include "FormatInternal.h"
 #include "FormatTokenLexer.h"
 #include "NamespaceEndCommentsFixer.h"
 #include "SortJavaScriptImports.h"
@@ -44,7 +45,8 @@
 
 using clang::format::FormatStyle;
 
-LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::IncludeCategory)
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::IncludeCategory);
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::RawStringFormat);
 
 namespace llvm {
 namespace yaml {
@@ -389,6 +391,7 @@ template <> struct MappingTraits {
     IO.mapOptional("PenaltyReturnTypeOnItsOwnLine",
                    Style.PenaltyReturnTypeOnItsOwnLine);
     IO.mapOptional("PointerAlignment", Style.PointerAlignment);
+    IO.mapOptional("RawStringFormats", Style.RawStringFormats);
     IO.mapOptional("ReflowComments", Style.ReflowComments);
     IO.mapOptional("SortIncludes", Style.SortIncludes);
     IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations);
@@ -441,6 +444,14 @@ template <> struct MappingTraits {
   }
 };
 
+template <> struct MappingTraits {
+  static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) {
+    IO.mapOptional("Delimiter", Format.Delimiter);
+    IO.mapOptional("Language", Format.Language);
+    IO.mapOptional("BasedOnStyle", Format.BasedOnStyle);
+  }
+};
+
 // Allows to read vector while keeping default values.
 // IO.getContext() should contain a pointer to the FormatStyle structure, that
 // will be used to get default values for missing keys.
@@ -620,6 +631,7 @@ FormatStyle getLLVMStyle() {
   LLVMStyle.SpacesBeforeTrailingComments = 1;
   LLVMStyle.Standard = FormatStyle::LS_Cpp11;
   LLVMStyle.UseTab = FormatStyle::UT_Never;
+  LLVMStyle.RawStringFormats = {{"pb", FormatStyle::LK_TextProto, "google"}};
   LLVMStyle.ReflowComments = true;
   LLVMStyle.SpacesInParentheses = false;
   LLVMStyle.SpacesInSquareBrackets = false;
@@ -895,7 +907,7 @@ public:
   JavaScriptRequoter(const Environment &Env, const FormatStyle &Style)
       : TokenAnalyzer(Env, Style) {}
 
-  tooling::Replacements
+  std::pair
   analyze(TokenAnnotator &Annotator,
           SmallVectorImpl &AnnotatedLines,
           FormatTokenLexer &Tokens) override {
@@ -903,7 +915,7 @@ public:
                                           AnnotatedLines.end());
     tooling::Replacements Result;
     requoteJSStringLiteral(AnnotatedLines, Result);
-    return Result;
+    return {Result, 0};
   }
 
 private:
@@ -984,7 +996,7 @@ public:
             FormattingAttemptStatus *Status)
       : TokenAnalyzer(Env, Style), Status(Status) {}
 
-  tooling::Replacements
+  std::pair
   analyze(TokenAnnotator &Annotator,
           SmallVectorImpl &AnnotatedLines,
           FormatTokenLexer &Tokens) override {
@@ -1003,13 +1015,20 @@ public:
     ContinuationIndenter Indenter(Style, Tokens.getKeywords(),
                                   Env.getSourceManager(), Whitespaces, Encoding,
                                   BinPackInconclusiveFunctions);
-    UnwrappedLineFormatter(&Indenter, &Whitespaces, Style, Tokens.getKeywords(),
-                           Env.getSourceManager(), Status)
-        .format(AnnotatedLines);
+    unsigned Penalty =
+        UnwrappedLineFormatter(&Indenter, &Whitespaces, Style,
+                               Tokens.getKeywords(), Env.getSourceManager(),
+                               Status)
+            .format(AnnotatedLines, /*DryRun=*/false,
+                    /*AdditionalIndent=*/0,
+                    /*FixBadIndentation=*/false,
+                    /*FirstStartColumn=*/Env.getFirstStartColumn(),
+                    /*NextStartColumn=*/Env.getNextStartColumn(),
+                    /*LastStartColumn=*/Env.getLastStartColumn());
     for (const auto &R : Whitespaces.generateReplacements())
       if (Result.add(R))
-        return Result;
-    return Result;
+        return {Result, 0};
+    return {Result, Penalty};
   }
 
 private:
@@ -1097,7 +1116,7 @@ public:
         DeletedTokens(FormatTokenLess(Env.getSourceManager())) {}
 
   // FIXME: eliminate unused parameters.
-  tooling::Replacements
+  std::pair
   analyze(TokenAnnotator &Annotator,
           SmallVectorImpl &AnnotatedLines,
           FormatTokenLexer &Tokens) override {
@@ -1125,7 +1144,7 @@ public:
       }
     }
 
-    return generateFixes();
+    return {generateFixes(), 0};
   }
 
 private:
@@ -1906,19 +1925,22 @@ cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces,
   return processReplacements(Cleanup, Code, NewReplaces, Style);
 }
 
-tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
-                               ArrayRef Ranges,
-                               StringRef FileName,
-                               FormattingAttemptStatus *Status) {
+namespace internal {
+std::pair
+reformat(const FormatStyle &Style, StringRef Code,
+         ArrayRef Ranges, unsigned FirstStartColumn,
+         unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName,
+         FormattingAttemptStatus *Status) {
   FormatStyle Expanded = expandPresets(Style);
   if (Expanded.DisableFormat)
-    return tooling::Replacements();
+    return {tooling::Replacements(), 0};
   if (isLikelyXml(Code))
-    return tooling::Replacements();
+    return {tooling::Replacements(), 0};
   if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code))
-    return tooling::Replacements();
+    return {tooling::Replacements(), 0};
 
-  typedef std::function
+  typedef std::function(
+      const Environment &)>
       AnalyzerPass;
   SmallVector Passes;
 
@@ -1944,26 +1966,42 @@ tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
     return Formatter(Env, Expanded, Status).process();
   });
 
-  std::unique_ptr Env =
-      Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
+  std::unique_ptr Env = Environment::CreateVirtualEnvironment(
+      Code, FileName, Ranges, FirstStartColumn, NextStartColumn,
+      LastStartColumn);
   llvm::Optional CurrentCode = None;
   tooling::Replacements Fixes;
+  unsigned Penalty = 0;
   for (size_t I = 0, E = Passes.size(); I < E; ++I) {
-    tooling::Replacements PassFixes = Passes[I](*Env);
+    std::pair PassFixes = Passes[I](*Env);
     auto NewCode = applyAllReplacements(
-        CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes);
+        CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first);
     if (NewCode) {
-      Fixes = Fixes.merge(PassFixes);
+      Fixes = Fixes.merge(PassFixes.first);
+      Penalty += PassFixes.second;
       if (I + 1 < E) {
         CurrentCode = std::move(*NewCode);
         Env = Environment::CreateVirtualEnvironment(
             *CurrentCode, FileName,
-            tooling::calculateRangesAfterReplacements(Fixes, Ranges));
+            tooling::calculateRangesAfterReplacements(Fixes, Ranges),
+            FirstStartColumn, NextStartColumn, LastStartColumn);
       }
     }
   }
 
-  return Fixes;
+  return {Fixes, Penalty};
+}
+} // namespace internal
+
+tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
+                               ArrayRef Ranges,
+                               StringRef FileName,
+                               FormattingAttemptStatus *Status) {
+  return internal::reformat(Style, Code, Ranges,
+                            /*FirstStartColumn=*/0,
+                            /*NextStartColumn=*/0,
+                            /*LastStartColumn=*/0, FileName, Status)
+      .first;
 }
 
 tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
@@ -1975,7 +2013,7 @@ tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code,
   std::unique_ptr Env =
       Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
   Cleaner Clean(*Env, Style);
-  return Clean.process();
+  return Clean.process().first;
 }
 
 tooling::Replacements reformat(const FormatStyle &Style, StringRef Code,
@@ -1995,7 +2033,7 @@ tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style,
   std::unique_ptr Env =
       Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
   NamespaceEndCommentsFixer Fix(*Env, Style);
-  return Fix.process();
+  return Fix.process().first;
 }
 
 tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
@@ -2005,7 +2043,7 @@ tooling::Replacements sortUsingDeclarations(const FormatStyle &Style,
   std::unique_ptr Env =
       Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
   UsingDeclarationsSorter Sorter(*Env, Style);
-  return Sorter.process();
+  return Sorter.process().first;
 }
 
 LangOptions getFormattingLangOpts(const FormatStyle &Style) {
diff --git a/lib/Format/FormatInternal.h b/lib/Format/FormatInternal.h
new file mode 100644
index 0000000000..1373e9d2ee
--- /dev/null
+++ b/lib/Format/FormatInternal.h
@@ -0,0 +1,79 @@
+//===--- FormatInternal.h - Format C++ code ---------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file declares Format APIs to be used internally by the
+/// formatting library implementation.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_FORMAT_FORMATINTERNAL_H
+#define LLVM_CLANG_LIB_FORMAT_FORMATINTERNAL_H
+
+namespace clang {
+namespace format {
+namespace internal {
+
+/// \brief Reformats the given \p Ranges in the code fragment \p Code.
+///
+/// A fragment of code could conceptually be surrounded by other code that might
+/// constrain how that fragment is laid out.
+/// For example, consider the fragment of code between 'R"(' and ')"',
+/// exclusive, in the following code:
+///
+/// void outer(int x) {
+///   string inner = R"(name: data
+///                     ^ FirstStartColumn
+///     value: {
+///       x: 1
+///     ^ NextStartColumn
+///     }
+///   )";
+///   ^ LastStartColumn
+/// }
+///
+/// The outer code can influence the inner fragment as follows:
+///   * \p FirstStartColumn specifies the column at which \p Code starts.
+///   * \p NextStartColumn specifies the additional indent dictated by the
+///     surrounding code. It is applied to the rest of the lines of \p Code.
+///   * \p LastStartColumn specifies the column at which the last line of
+///     \p Code should end, in case the last line is an empty line.
+///
+///     In the case where the last line of the fragment contains content,
+///     the fragment ends at the end of that content and \p LastStartColumn is
+///     not taken into account, for example in:
+///
+///     void block() {
+///       string inner = R"(name: value)";
+///     }
+///
+/// Each range is extended on either end to its next bigger logic unit, i.e.
+/// everything that might influence its formatting or might be influenced by its
+/// formatting.
+///
+/// Returns a pair P, where:
+///   * P.first are the ``Replacements`` necessary to make all \p Ranges comply
+///     with \p Style.
+///   * P.second is the penalty induced by formatting the fragment \p Code.
+///     If the formatting of the fragment doesn't have a notion of penalty,
+///     returns 0.
+///
+/// If ``Status`` is non-null, its value will be populated with the status of
+/// this formatting attempt. See \c FormattingAttemptStatus.
+std::pair
+reformat(const FormatStyle &Style, StringRef Code,
+         ArrayRef Ranges, unsigned FirstStartColumn,
+         unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName,
+         FormattingAttemptStatus *Status);
+
+} // namespace internal
+} // namespace format
+} // namespace clang
+
+#endif
diff --git a/lib/Format/FormatTokenLexer.cpp b/lib/Format/FormatTokenLexer.cpp
index 8fb3d84ea5..d37fcec6c5 100644
--- a/lib/Format/FormatTokenLexer.cpp
+++ b/lib/Format/FormatTokenLexer.cpp
@@ -24,10 +24,10 @@ namespace clang {
 namespace format {
 
 FormatTokenLexer::FormatTokenLexer(const SourceManager &SourceMgr, FileID ID,
-                                   const FormatStyle &Style,
+                                   unsigned Column, const FormatStyle &Style,
                                    encoding::Encoding Encoding)
     : FormatTok(nullptr), IsFirstToken(true), StateStack({LexerState::NORMAL}),
-      Column(0), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID),
+      Column(Column), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID),
       Style(Style), IdentTable(getFormattingLangOpts(Style)),
       Keywords(IdentTable), Encoding(Encoding), FirstInLineIndex(0),
       FormattingDisabled(false), MacroBlockBeginRegex(Style.MacroBlockBegin),
diff --git a/lib/Format/FormatTokenLexer.h b/lib/Format/FormatTokenLexer.h
index bf10f09cd1..6605a1c35a 100644
--- a/lib/Format/FormatTokenLexer.h
+++ b/lib/Format/FormatTokenLexer.h
@@ -36,7 +36,7 @@ enum LexerState {
 
 class FormatTokenLexer {
 public:
-  FormatTokenLexer(const SourceManager &SourceMgr, FileID ID,
+  FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, unsigned Column,
                    const FormatStyle &Style, encoding::Encoding Encoding);
 
   ArrayRef lex();
diff --git a/lib/Format/NamespaceEndCommentsFixer.cpp b/lib/Format/NamespaceEndCommentsFixer.cpp
index c660843dca..df99bb2e13 100644
--- a/lib/Format/NamespaceEndCommentsFixer.cpp
+++ b/lib/Format/NamespaceEndCommentsFixer.cpp
@@ -137,7 +137,7 @@ NamespaceEndCommentsFixer::NamespaceEndCommentsFixer(const Environment &Env,
                                                      const FormatStyle &Style)
     : TokenAnalyzer(Env, Style) {}
 
-tooling::Replacements NamespaceEndCommentsFixer::analyze(
+std::pair NamespaceEndCommentsFixer::analyze(
     TokenAnnotator &Annotator, SmallVectorImpl &AnnotatedLines,
     FormatTokenLexer &Tokens) {
   const SourceManager &SourceMgr = Env.getSourceManager();
@@ -206,7 +206,7 @@ tooling::Replacements NamespaceEndCommentsFixer::analyze(
     }
     StartLineIndex = SIZE_MAX;
   }
-  return Fixes;
+  return {Fixes, 0};
 }
 
 } // namespace format
diff --git a/lib/Format/NamespaceEndCommentsFixer.h b/lib/Format/NamespaceEndCommentsFixer.h
index 7790668a2e..4779f0d27c 100644
--- a/lib/Format/NamespaceEndCommentsFixer.h
+++ b/lib/Format/NamespaceEndCommentsFixer.h
@@ -25,7 +25,7 @@ class NamespaceEndCommentsFixer : public TokenAnalyzer {
 public:
   NamespaceEndCommentsFixer(const Environment &Env, const FormatStyle &Style);
 
-  tooling::Replacements
+  std::pair
   analyze(TokenAnnotator &Annotator,
           SmallVectorImpl &AnnotatedLines,
           FormatTokenLexer &Tokens) override;
diff --git a/lib/Format/SortJavaScriptImports.cpp b/lib/Format/SortJavaScriptImports.cpp
index c4db9a6c2f..d0b979e100 100644
--- a/lib/Format/SortJavaScriptImports.cpp
+++ b/lib/Format/SortJavaScriptImports.cpp
@@ -123,7 +123,7 @@ public:
       : TokenAnalyzer(Env, Style),
         FileContents(Env.getSourceManager().getBufferData(Env.getFileID())) {}
 
-  tooling::Replacements
+  std::pair
   analyze(TokenAnnotator &Annotator,
           SmallVectorImpl &AnnotatedLines,
           FormatTokenLexer &Tokens) override {
@@ -138,7 +138,7 @@ public:
         parseModuleReferences(Keywords, AnnotatedLines);
 
     if (References.empty())
-      return Result;
+      return {Result, 0};
 
     SmallVector Indices;
     for (unsigned i = 0, e = References.size(); i != e; ++i)
@@ -168,7 +168,7 @@ public:
     }
 
     if (ReferencesInOrder && SymbolsInOrder)
-      return Result;
+      return {Result, 0};
 
     SourceRange InsertionPoint = References[0].Range;
     InsertionPoint.setEnd(References[References.size() - 1].Range.getEnd());
@@ -202,7 +202,7 @@ public:
       assert(false);
     }
 
-    return Result;
+    return {Result, 0};
   }
 
 private:
@@ -449,7 +449,7 @@ tooling::Replacements sortJavaScriptImports(const FormatStyle &Style,
   std::unique_ptr Env =
       Environment::CreateVirtualEnvironment(Code, FileName, Ranges);
   JavaScriptImportSorter Sorter(*Env, Style);
-  return Sorter.process();
+  return Sorter.process().first;
 }
 
 } // end namespace format
diff --git a/lib/Format/TokenAnalyzer.cpp b/lib/Format/TokenAnalyzer.cpp
index 7a8b70c4ba..d1dfb1fea3 100644
--- a/lib/Format/TokenAnalyzer.cpp
+++ b/lib/Format/TokenAnalyzer.cpp
@@ -38,7 +38,10 @@ namespace format {
 // Code.
 std::unique_ptr
 Environment::CreateVirtualEnvironment(StringRef Code, StringRef FileName,
-                                      ArrayRef Ranges) {
+                                      ArrayRef Ranges,
+                                      unsigned FirstStartColumn,
+                                      unsigned NextStartColumn,
+                                      unsigned LastStartColumn) {
   // This is referenced by `FileMgr` and will be released by `FileMgr` when it
   // is deleted.
   IntrusiveRefCntPtr InMemoryFileSystem(
@@ -70,9 +73,9 @@ Environment::CreateVirtualEnvironment(StringRef Code, StringRef FileName,
     SourceLocation End = Start.getLocWithOffset(Range.getLength());
     CharRanges.push_back(CharSourceRange::getCharRange(Start, End));
   }
-  return llvm::make_unique(ID, std::move(FileMgr),
-                                        std::move(VirtualSM),
-                                        std::move(Diagnostics), CharRanges);
+  return llvm::make_unique(
+      ID, std::move(FileMgr), std::move(VirtualSM), std::move(Diagnostics),
+      CharRanges, FirstStartColumn, NextStartColumn, LastStartColumn);
 }
 
 TokenAnalyzer::TokenAnalyzer(const Environment &Env, const FormatStyle &Style)
@@ -89,14 +92,16 @@ TokenAnalyzer::TokenAnalyzer(const Environment &Env, const FormatStyle &Style)
                      << "\n");
 }
 
-tooling::Replacements TokenAnalyzer::process() {
+std::pair TokenAnalyzer::process() {
   tooling::Replacements Result;
-  FormatTokenLexer Tokens(Env.getSourceManager(), Env.getFileID(), Style,
-                          Encoding);
+  FormatTokenLexer Tokens(Env.getSourceManager(), Env.getFileID(),
+                          Env.getFirstStartColumn(), Style, Encoding);
 
-  UnwrappedLineParser Parser(Style, Tokens.getKeywords(), Tokens.lex(), *this);
+  UnwrappedLineParser Parser(Style, Tokens.getKeywords(),
+                             Env.getFirstStartColumn(), Tokens.lex(), *this);
   Parser.parse();
   assert(UnwrappedLines.rbegin()->empty());
+  unsigned Penalty = 0;
   for (unsigned Run = 0, RunE = UnwrappedLines.size(); Run + 1 != RunE; ++Run) {
     DEBUG(llvm::dbgs() << "Run " << Run << "...\n");
     SmallVector AnnotatedLines;
@@ -107,13 +112,13 @@ tooling::Replacements TokenAnalyzer::process() {
       Annotator.annotate(*AnnotatedLines.back());
     }
 
-    tooling::Replacements RunResult =
+    std::pair RunResult =
         analyze(Annotator, AnnotatedLines, Tokens);
 
     DEBUG({
       llvm::dbgs() << "Replacements for run " << Run << ":\n";
-      for (tooling::Replacements::const_iterator I = RunResult.begin(),
-                                                 E = RunResult.end();
+      for (tooling::Replacements::const_iterator I = RunResult.first.begin(),
+                                                 E = RunResult.first.end();
            I != E; ++I) {
         llvm::dbgs() << I->toString() << "\n";
       }
@@ -121,17 +126,19 @@ tooling::Replacements TokenAnalyzer::process() {
     for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
       delete AnnotatedLines[i];
     }
-    for (const auto &R : RunResult) {
+
+    Penalty += RunResult.second;
+    for (const auto &R : RunResult.first) {
       auto Err = Result.add(R);
       // FIXME: better error handling here. For now, simply return an empty
       // Replacements to indicate failure.
       if (Err) {
         llvm::errs() << llvm::toString(std::move(Err)) << "\n";
-        return tooling::Replacements();
+        return {tooling::Replacements(), 0};
       }
     }
   }
-  return Result;
+  return {Result, Penalty};
 }
 
 void TokenAnalyzer::consumeUnwrappedLine(const UnwrappedLine &TheLine) {
diff --git a/lib/Format/TokenAnalyzer.h b/lib/Format/TokenAnalyzer.h
index 78a3d1bc8d..96ea00b25b 100644
--- a/lib/Format/TokenAnalyzer.h
+++ b/lib/Format/TokenAnalyzer.h
@@ -37,21 +37,37 @@ namespace format {
 class Environment {
 public:
   Environment(SourceManager &SM, FileID ID, ArrayRef Ranges)
-      : ID(ID), CharRanges(Ranges.begin(), Ranges.end()), SM(SM) {}
+      : ID(ID), CharRanges(Ranges.begin(), Ranges.end()), SM(SM),
+      FirstStartColumn(0),
+      NextStartColumn(0),
+      LastStartColumn(0) {}
 
   Environment(FileID ID, std::unique_ptr FileMgr,
               std::unique_ptr VirtualSM,
               std::unique_ptr Diagnostics,
-              const std::vector &CharRanges)
+              const std::vector &CharRanges,
+              unsigned FirstStartColumn,
+              unsigned NextStartColumn,
+              unsigned LastStartColumn)
       : ID(ID), CharRanges(CharRanges.begin(), CharRanges.end()),
-        SM(*VirtualSM), FileMgr(std::move(FileMgr)),
+        SM(*VirtualSM), 
+        FirstStartColumn(FirstStartColumn),
+        NextStartColumn(NextStartColumn),
+        LastStartColumn(LastStartColumn),
+        FileMgr(std::move(FileMgr)),
         VirtualSM(std::move(VirtualSM)), Diagnostics(std::move(Diagnostics)) {}
 
-  // This sets up an virtual file system with file \p FileName containing \p
-  // Code.
+  // This sets up an virtual file system with file \p FileName containing the
+  // fragment \p Code. Assumes that \p Code starts at \p FirstStartColumn,
+  // that the next lines of \p Code should start at \p NextStartColumn, and
+  // that \p Code should end at \p LastStartColumn if it ends in newline.
+  // See also the documentation of clang::format::internal::reformat.
   static std::unique_ptr
   CreateVirtualEnvironment(StringRef Code, StringRef FileName,
-                           ArrayRef Ranges);
+                           ArrayRef Ranges,
+                           unsigned FirstStartColumn = 0,
+                           unsigned NextStartColumn = 0,
+                           unsigned LastStartColumn = 0);
 
   FileID getFileID() const { return ID; }
 
@@ -59,10 +75,25 @@ public:
 
   const SourceManager &getSourceManager() const { return SM; }
 
+  // Returns the column at which the fragment of code managed by this
+  // environment starts.
+  unsigned getFirstStartColumn() const { return FirstStartColumn; }
+
+  // Returns the column at which subsequent lines of the fragment of code
+  // managed by this environment should start.
+  unsigned getNextStartColumn() const { return NextStartColumn; }
+
+  // Returns the column at which the fragment of code managed by this
+  // environment should end if it ends in a newline.
+  unsigned getLastStartColumn() const { return LastStartColumn; }
+
 private:
   FileID ID;
   SmallVector CharRanges;
   SourceManager &SM;
+  unsigned FirstStartColumn;
+  unsigned NextStartColumn;
+  unsigned LastStartColumn;
 
   // The order of these fields are important - they should be in the same order
   // as they are created in `CreateVirtualEnvironment` so that they can be
@@ -76,10 +107,10 @@ class TokenAnalyzer : public UnwrappedLineConsumer {
 public:
   TokenAnalyzer(const Environment &Env, const FormatStyle &Style);
 
-  tooling::Replacements process();
+  std::pair process();
 
 protected:
-  virtual tooling::Replacements
+  virtual std::pair
   analyze(TokenAnnotator &Annotator,
           SmallVectorImpl &AnnotatedLines,
           FormatTokenLexer &Tokens) = 0;
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index a49cbaab5f..1b22e26600 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -1891,7 +1891,8 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
   }
 
   Line.First->TotalLength =
-      Line.First->IsMultiline ? Style.ColumnLimit : Line.First->ColumnWidth;
+      Line.First->IsMultiline ? Style.ColumnLimit
+                              : Line.FirstStartColumn + Line.First->ColumnWidth;
   FormatToken *Current = Line.First->Next;
   bool InFunctionDecl = Line.MightBeFunctionDecl;
   while (Current) {
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
index 805509533b..04a18d45b8 100644
--- a/lib/Format/TokenAnnotator.h
+++ b/lib/Format/TokenAnnotator.h
@@ -43,7 +43,8 @@ public:
         InPPDirective(Line.InPPDirective),
         MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false),
         IsMultiVariableDeclStmt(false), Affected(false),
-        LeadingEmptyLinesAffected(false), ChildrenAffected(false) {
+        LeadingEmptyLinesAffected(false), ChildrenAffected(false),
+        FirstStartColumn(Line.FirstStartColumn) {
     assert(!Line.Tokens.empty());
 
     // Calculate Next and Previous for all tokens. Note that we must overwrite
@@ -127,6 +128,8 @@ public:
   /// \c True if one of this line's children intersects with an input range.
   bool ChildrenAffected;
 
+  unsigned FirstStartColumn;
+
 private:
   // Disallow copying.
   AnnotatedLine(const AnnotatedLine &) = delete;
diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp
index d25f0a1c29..a82cd5abe2 100644
--- a/lib/Format/UnwrappedLineFormatter.cpp
+++ b/lib/Format/UnwrappedLineFormatter.cpp
@@ -659,7 +659,9 @@ public:
   /// \brief Formats an \c AnnotatedLine and returns the penalty.
   ///
   /// If \p DryRun is \c false, directly applies the changes.
-  virtual unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
+  virtual unsigned formatLine(const AnnotatedLine &Line,
+                              unsigned FirstIndent,
+                              unsigned FirstStartColumn,
                               bool DryRun) = 0;
 
 protected:
@@ -730,7 +732,8 @@ protected:
           *Child->First, /*Newlines=*/0, /*Spaces=*/1,
           /*StartOfTokenColumn=*/State.Column, State.Line->InPPDirective);
     }
-    Penalty += formatLine(*Child, State.Column + 1, DryRun);
+    Penalty +=
+        formatLine(*Child, State.Column + 1, /*FirstStartColumn=*/0, DryRun);
 
     State.Column += 1 + Child->Last->TotalLength;
     return true;
@@ -756,10 +759,10 @@ public:
   /// \brief Formats the line, simply keeping all of the input's line breaking
   /// decisions.
   unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
-                      bool DryRun) override {
+                      unsigned FirstStartColumn, bool DryRun) override {
     assert(!DryRun);
-    LineState State =
-        Indenter->getInitialState(FirstIndent, &Line, /*DryRun=*/false);
+    LineState State = Indenter->getInitialState(FirstIndent, FirstStartColumn,
+                                                &Line, /*DryRun=*/false);
     while (State.NextToken) {
       bool Newline =
           Indenter->mustBreak(State) ||
@@ -782,9 +785,10 @@ public:
 
   /// \brief Puts all tokens into a single line.
   unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
-                      bool DryRun) override {
+                      unsigned FirstStartColumn, bool DryRun) override {
     unsigned Penalty = 0;
-    LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);
+    LineState State =
+        Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line, DryRun);
     while (State.NextToken) {
       formatChildren(State, /*Newline=*/false, DryRun, Penalty);
       Indenter->addTokenToState(
@@ -806,8 +810,9 @@ public:
   /// \brief Formats the line by finding the best line breaks with line lengths
   /// below the column limit.
   unsigned formatLine(const AnnotatedLine &Line, unsigned FirstIndent,
-                      bool DryRun) override {
-    LineState State = Indenter->getInitialState(FirstIndent, &Line, DryRun);
+                      unsigned FirstStartColumn, bool DryRun) override {
+    LineState State =
+        Indenter->getInitialState(FirstIndent, FirstStartColumn, &Line, DryRun);
 
     // If the ObjC method declaration does not fit on a line, we should format
     // it with one arg per line.
@@ -974,7 +979,10 @@ private:
 unsigned
 UnwrappedLineFormatter::format(const SmallVectorImpl &Lines,
                                bool DryRun, int AdditionalIndent,
-                               bool FixBadIndentation) {
+                               bool FixBadIndentation,
+                               unsigned FirstStartColumn,
+                               unsigned NextStartColumn,
+                               unsigned LastStartColumn) {
   LineJoiner Joiner(Style, Keywords, Lines);
 
   // Try to look up already computed penalty in DryRun-mode.
@@ -994,9 +1002,10 @@ UnwrappedLineFormatter::format(const SmallVectorImpl &Lines,
   // The minimum level of consecutive lines that have been formatted.
   unsigned RangeMinLevel = UINT_MAX;
 
+  bool FirstLine = true;
   for (const AnnotatedLine *Line =
            Joiner.getNextMergedLine(DryRun, IndentTracker);
-       Line; Line = NextLine) {
+       Line; Line = NextLine, FirstLine = false) {
     const AnnotatedLine &TheLine = *Line;
     unsigned Indent = IndentTracker.getIndent();
 
@@ -1020,8 +1029,12 @@ UnwrappedLineFormatter::format(const SmallVectorImpl &Lines,
     }
 
     if (ShouldFormat && TheLine.Type != LT_Invalid) {
-      if (!DryRun)
-        formatFirstToken(TheLine, PreviousLine, Indent);
+      if (!DryRun) {
+        bool LastLine = Line->First->is(tok::eof);
+        formatFirstToken(TheLine, PreviousLine,
+                         Indent,
+                         LastLine ? LastStartColumn : NextStartColumn + Indent);
+      }
 
       NextLine = Joiner.getNextMergedLine(DryRun, IndentTracker);
       unsigned ColumnLimit = getColumnLimit(TheLine.InPPDirective, NextLine);
@@ -1030,16 +1043,18 @@ UnwrappedLineFormatter::format(const SmallVectorImpl &Lines,
           (TheLine.Type == LT_ImportStatement &&
            (Style.Language != FormatStyle::LK_JavaScript ||
             !Style.JavaScriptWrapImports));
-
       if (Style.ColumnLimit == 0)
         NoColumnLimitLineFormatter(Indenter, Whitespaces, Style, this)
-            .formatLine(TheLine, Indent, DryRun);
+            .formatLine(TheLine, NextStartColumn + Indent,
+                        FirstLine ? FirstStartColumn : 0, DryRun);
       else if (FitsIntoOneLine)
         Penalty += NoLineBreakFormatter(Indenter, Whitespaces, Style, this)
-                       .formatLine(TheLine, Indent, DryRun);
+                       .formatLine(TheLine, NextStartColumn + Indent,
+                                   FirstLine ? FirstStartColumn : 0, DryRun);
       else
         Penalty += OptimizingLineFormatter(Indenter, Whitespaces, Style, this)
-                       .formatLine(TheLine, Indent, DryRun);
+                       .formatLine(TheLine, NextStartColumn + Indent,
+                                   FirstLine ? FirstStartColumn : 0, DryRun);
       RangeMinLevel = std::min(RangeMinLevel, TheLine.Level);
     } else {
       // If no token in the current line is affected, we still need to format
@@ -1062,6 +1077,7 @@ UnwrappedLineFormatter::format(const SmallVectorImpl &Lines,
         // Format the first token.
         if (ReformatLeadingWhitespace)
           formatFirstToken(TheLine, PreviousLine,
+                           TheLine.First->OriginalColumn,
                            TheLine.First->OriginalColumn);
         else
           Whitespaces->addUntouchableToken(*TheLine.First,
@@ -1084,12 +1100,14 @@ UnwrappedLineFormatter::format(const SmallVectorImpl &Lines,
 
 void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line,
                                               const AnnotatedLine *PreviousLine,
-                                              unsigned Indent) {
+                                              unsigned Indent,
+                                              unsigned NewlineIndent) {
   FormatToken &RootToken = *Line.First;
   if (RootToken.is(tok::eof)) {
     unsigned Newlines = std::min(RootToken.NewlinesBefore, 1u);
-    Whitespaces->replaceWhitespace(RootToken, Newlines, /*Spaces=*/0,
-                                   /*StartOfTokenColumn=*/0);
+    unsigned TokenIndent = Newlines ? NewlineIndent : 0;
+    Whitespaces->replaceWhitespace(RootToken, Newlines, TokenIndent,
+                                   TokenIndent);
     return;
   }
   unsigned Newlines =
@@ -1104,10 +1122,6 @@ void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line,
   if (RootToken.IsFirst && !RootToken.HasUnescapedNewline)
     Newlines = 0;
 
-  // Preprocessor directives get indented after the hash, if indented.
-  if (Line.Type == LT_PreprocessorDirective || Line.Type == LT_ImportStatement)
-    Indent = 0;
-
   // Remove empty lines after "{".
   if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
       PreviousLine->Last->is(tok::l_brace) &&
@@ -1125,6 +1139,13 @@ void UnwrappedLineFormatter::formatFirstToken(const AnnotatedLine &Line,
       (!PreviousLine->InPPDirective || !RootToken.HasUnescapedNewline))
     Newlines = std::min(1u, Newlines);
 
+  if (Newlines)
+    Indent = NewlineIndent;
+
+  // Preprocessor directives get indented after the hash, if indented.
+  if (Line.Type == LT_PreprocessorDirective || Line.Type == LT_ImportStatement)
+    Indent = 0;
+
   Whitespaces->replaceWhitespace(RootToken, Newlines, Indent, Indent,
                                  Line.InPPDirective &&
                                      !RootToken.HasUnescapedNewline);
diff --git a/lib/Format/UnwrappedLineFormatter.h b/lib/Format/UnwrappedLineFormatter.h
index 9d7a910b98..6432ca83a4 100644
--- a/lib/Format/UnwrappedLineFormatter.h
+++ b/lib/Format/UnwrappedLineFormatter.h
@@ -40,13 +40,17 @@ public:
   /// \brief Format the current block and return the penalty.
   unsigned format(const SmallVectorImpl &Lines,
                   bool DryRun = false, int AdditionalIndent = 0,
-                  bool FixBadIndentation = false);
+                  bool FixBadIndentation = false,
+                  unsigned FirstStartColumn = 0,
+                  unsigned NextStartColumn = 0,
+                  unsigned LastStartColumn = 0);
 
 private:
   /// \brief Add a new line and the required indent before the first Token
   /// of the \c UnwrappedLine if there was no structural parsing error.
   void formatFirstToken(const AnnotatedLine &Line,
-                        const AnnotatedLine *PreviousLine, unsigned Indent);
+                        const AnnotatedLine *PreviousLine, unsigned Indent,
+                        unsigned NewlineIndent);
 
   /// \brief Returns the column limit for a line, taking into account whether we
   /// need an escaped newline due to a continued preprocessor directive.
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index e210beb20e..9243cd99cb 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -225,6 +225,7 @@ private:
 
 UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
                                          const AdditionalKeywords &Keywords,
+                                         unsigned FirstStartColumn,
                                          ArrayRef Tokens,
                                          UnwrappedLineConsumer &Callback)
     : Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
@@ -232,7 +233,7 @@ UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,
       CommentPragmasRegex(Style.CommentPragmas), Tokens(nullptr),
       Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1),
       IfNdefCondition(nullptr), FoundIncludeGuardStart(false),
-      IncludeGuardRejected(false) {}
+      IncludeGuardRejected(false), FirstStartColumn(FirstStartColumn) {}
 
 void UnwrappedLineParser::reset() {
   PPBranchLevel = -1;
@@ -247,10 +248,12 @@ void UnwrappedLineParser::reset() {
   CurrentLines = &Lines;
   DeclarationScopeStack.clear();
   PPStack.clear();
+  Line->FirstStartColumn = FirstStartColumn;
 }
 
 void UnwrappedLineParser::parse() {
   IndexedTokenSource TokenSource(AllTokens);
+  Line->FirstStartColumn = FirstStartColumn;
   do {
     DEBUG(llvm::dbgs() << "----\n");
     reset();
@@ -2193,7 +2196,8 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() {
 
 LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line,
                                                  StringRef Prefix = "") {
-  llvm::dbgs() << Prefix << "Line(" << Line.Level << ")"
+  llvm::dbgs() << Prefix << "Line(" << Line.Level
+               << ", FSC=" << Line.FirstStartColumn << ")"
                << (Line.InPPDirective ? " MACRO" : "") << ": ";
   for (std::list::const_iterator I = Line.Tokens.begin(),
                                                     E = Line.Tokens.end();
@@ -2226,6 +2230,7 @@ void UnwrappedLineParser::addUnwrappedLine() {
   CurrentLines->push_back(std::move(*Line));
   Line->Tokens.clear();
   Line->MatchingOpeningBlockLineIndex = UnwrappedLine::kInvalidIndex;
+  Line->FirstStartColumn = 0;
   if (CurrentLines == &Lines && !PreprocessorDirectives.empty()) {
     CurrentLines->append(
         std::make_move_iterator(PreprocessorDirectives.begin()),
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
index 4437ccf28d..1d8ccabbd0 100644
--- a/lib/Format/UnwrappedLineParser.h
+++ b/lib/Format/UnwrappedLineParser.h
@@ -56,6 +56,8 @@ struct UnwrappedLine {
   size_t MatchingOpeningBlockLineIndex;
 
   static const size_t kInvalidIndex = -1;
+
+  unsigned FirstStartColumn = 0;
 };
 
 class UnwrappedLineConsumer {
@@ -71,6 +73,7 @@ class UnwrappedLineParser {
 public:
   UnwrappedLineParser(const FormatStyle &Style,
                       const AdditionalKeywords &Keywords,
+                      unsigned FirstStartColumn,
                       ArrayRef Tokens,
                       UnwrappedLineConsumer &Callback);
 
@@ -249,6 +252,10 @@ private:
   FormatToken *IfNdefCondition;
   bool FoundIncludeGuardStart;
   bool IncludeGuardRejected;
+  // Contains the first start column where the source begins. This is zero for
+  // normal source code and may be nonzero when formatting a code fragment that
+  // does not start at the beginning of the file.
+  unsigned FirstStartColumn;
 
   friend class ScopedLineState;
   friend class CompoundStatementIndenter;
diff --git a/lib/Format/UsingDeclarationsSorter.cpp b/lib/Format/UsingDeclarationsSorter.cpp
index 4d60d8fd9a..d6753b545e 100644
--- a/lib/Format/UsingDeclarationsSorter.cpp
+++ b/lib/Format/UsingDeclarationsSorter.cpp
@@ -124,7 +124,7 @@ UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env,
                                                  const FormatStyle &Style)
     : TokenAnalyzer(Env, Style) {}
 
-tooling::Replacements UsingDeclarationsSorter::analyze(
+std::pair UsingDeclarationsSorter::analyze(
     TokenAnnotator &Annotator, SmallVectorImpl &AnnotatedLines,
     FormatTokenLexer &Tokens) {
   const SourceManager &SourceMgr = Env.getSourceManager();
@@ -149,7 +149,7 @@ tooling::Replacements UsingDeclarationsSorter::analyze(
     UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I], Label));
   }
   endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes);
-  return Fixes;
+  return {Fixes, 0};
 }
 
 } // namespace format
diff --git a/lib/Format/UsingDeclarationsSorter.h b/lib/Format/UsingDeclarationsSorter.h
index f7d5f97e3a..6f137712d8 100644
--- a/lib/Format/UsingDeclarationsSorter.h
+++ b/lib/Format/UsingDeclarationsSorter.h
@@ -25,7 +25,7 @@ class UsingDeclarationsSorter : public TokenAnalyzer {
 public:
   UsingDeclarationsSorter(const Environment &Env, const FormatStyle &Style);
 
-  tooling::Replacements
+  std::pair
   analyze(TokenAnnotator &Annotator,
           SmallVectorImpl &AnnotatedLines,
           FormatTokenLexer &Tokens) override;
diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp
index 0f2732c9fc..a5477a9963 100644
--- a/lib/Format/WhitespaceManager.cpp
+++ b/lib/Format/WhitespaceManager.cpp
@@ -67,6 +67,11 @@ void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
                            /*IsInsideToken=*/false));
 }
 
+llvm::Error
+WhitespaceManager::addReplacement(const tooling::Replacement &Replacement) {
+  return Replaces.add(Replacement);
+}
+
 void WhitespaceManager::replaceWhitespaceInToken(
     const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
     StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h
index 98a2071cf4..af20dc5616 100644
--- a/lib/Format/WhitespaceManager.h
+++ b/lib/Format/WhitespaceManager.h
@@ -57,6 +57,8 @@ public:
   /// was not called.
   void addUntouchableToken(const FormatToken &Tok, bool InPPDirective);
 
+  llvm::Error addReplacement(const tooling::Replacement &Replacement);
+
   /// \brief Inserts or replaces whitespace in the middle of a token.
   ///
   /// Inserts \p PreviousPostfix, \p Newlines, \p Spaces and \p CurrentPrefix
diff --git a/unittests/Format/CMakeLists.txt b/unittests/Format/CMakeLists.txt
index fa7e32c33d..992db0e508 100644
--- a/unittests/Format/CMakeLists.txt
+++ b/unittests/Format/CMakeLists.txt
@@ -10,6 +10,7 @@ add_clang_unittest(FormatTests
   FormatTestJava.cpp
   FormatTestObjC.cpp
   FormatTestProto.cpp
+  FormatTestRawStrings.cpp
   FormatTestSelective.cpp
   FormatTestTextProto.cpp
   NamespaceEndCommentsFixerTest.cpp
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index dadc0254c6..3651fa539d 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -10254,6 +10254,20 @@ TEST_F(FormatTest, ParsesConfiguration) {
               "    Priority: 1",
               IncludeCategories, ExpectedCategories);
   CHECK_PARSE("IncludeIsMainRegex: 'abc$'", IncludeIsMainRegex, "abc$");
+
+  Style.RawStringFormats.clear();
+  std::vector ExpectedRawStringFormats = {
+      {"pb", FormatStyle::LK_TextProto, "llvm"},
+      {"cpp", FormatStyle::LK_Cpp, "google"}};
+
+  CHECK_PARSE("RawStringFormats:\n"
+              "  - Delimiter: 'pb'\n"
+              "    Language: TextProto\n"
+              "    BasedOnStyle: llvm\n"
+              "  - Delimiter: 'cpp'\n"
+              "    Language: Cpp\n"
+              "    BasedOnStyle: google",
+              RawStringFormats, ExpectedRawStringFormats);
 }
 
 TEST_F(FormatTest, ParsesConfigurationWithLanguages) {
diff --git a/unittests/Format/FormatTestRawStrings.cpp b/unittests/Format/FormatTestRawStrings.cpp
new file mode 100644
index 0000000000..6e7b706587
--- /dev/null
+++ b/unittests/Format/FormatTestRawStrings.cpp
@@ -0,0 +1,733 @@
+//===- unittest/Format/FormatTestRawStrings.cpp - Formatting unit tests ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Format/Format.h"
+
+#include "../Tooling/ReplacementTest.h"
+#include "FormatTestUtils.h"
+
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "gtest/gtest.h"
+
+#define DEBUG_TYPE "format-test"
+
+using clang::tooling::ReplacementTest;
+using clang::tooling::toReplacements;
+
+namespace clang {
+namespace format {
+namespace {
+
+class FormatTestRawStrings : public ::testing::Test {
+protected:
+  enum StatusCheck { SC_ExpectComplete, SC_ExpectIncomplete, SC_DoNotCheck };
+
+  std::string format(llvm::StringRef Code,
+                     const FormatStyle &Style = getLLVMStyle(),
+                     StatusCheck CheckComplete = SC_ExpectComplete) {
+    DEBUG(llvm::errs() << "---\n");
+    DEBUG(llvm::errs() << Code << "\n\n");
+    std::vector Ranges(1, tooling::Range(0, Code.size()));
+    FormattingAttemptStatus Status;
+    tooling::Replacements Replaces =
+        reformat(Style, Code, Ranges, "", &Status);
+    if (CheckComplete != SC_DoNotCheck) {
+      bool ExpectedCompleteFormat = CheckComplete == SC_ExpectComplete;
+      EXPECT_EQ(ExpectedCompleteFormat, Status.FormatComplete)
+          << Code << "\n\n";
+    }
+    ReplacementCount = Replaces.size();
+    auto Result = applyAllReplacements(Code, Replaces);
+    EXPECT_TRUE(static_cast(Result));
+    DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
+    return *Result;
+  }
+
+  FormatStyle getStyleWithColumns(FormatStyle Style, unsigned ColumnLimit) {
+    Style.ColumnLimit = ColumnLimit;
+    return Style;
+  }
+
+  FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) {
+    return getStyleWithColumns(getLLVMStyle(), ColumnLimit);
+  }
+
+  int ReplacementCount;
+
+  FormatStyle getRawStringPbStyleWithColumns(unsigned ColumnLimit) {
+    FormatStyle Style = getLLVMStyle();
+    Style.ColumnLimit = ColumnLimit;
+    Style.RawStringFormats = {{/*Delimiter=*/"pb",
+                               /*Kind=*/FormatStyle::LK_TextProto,
+                               /*BasedOnStyle=*/"google"}};
+    return Style;
+  }
+
+  FormatStyle getRawStringLLVMCppStyleBasedOn(std::string BasedOnStyle) {
+    FormatStyle Style = getLLVMStyle();
+    Style.RawStringFormats = {{/*Delimiter=*/"cpp",
+                               /*Kind=*/FormatStyle::LK_Cpp, BasedOnStyle}};
+    return Style;
+  }
+
+  FormatStyle getRawStringGoogleCppStyleBasedOn(std::string BasedOnStyle) {
+    FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp);
+    Style.RawStringFormats = {{/*Delimiter=*/"cpp",
+                               /*Kind=*/FormatStyle::LK_Cpp, BasedOnStyle}};
+    return Style;
+  }
+
+  // Gcc 4.8 doesn't support raw string literals in macros, which breaks some
+  // build bots. We use this function instead.
+  void expect_eq(const std::string Expected, const std::string Actual) {
+    EXPECT_EQ(Expected, Actual);
+  }
+};
+
+TEST_F(FormatTestRawStrings, ReformatsAccordingToBaseStyle) {
+  // llvm style puts '*' on the right.
+  // google style puts '*' on the left.
+
+  // Use the llvm style if the raw string style has no BasedOnStyle.
+  expect_eq(R"test(int *i = R"cpp(int *p = nullptr;)cpp")test",
+            format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test",
+                   getRawStringLLVMCppStyleBasedOn("")));
+
+  // Use the google style if the raw string style has BasedOnStyle=google.
+  expect_eq(R"test(int *i = R"cpp(int* p = nullptr;)cpp")test",
+            format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test",
+                   getRawStringLLVMCppStyleBasedOn("google")));
+
+  // Use the llvm style if the raw string style has no BasedOnStyle=llvm.
+  expect_eq(R"test(int* i = R"cpp(int *p = nullptr;)cpp")test",
+            format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test",
+                   getRawStringGoogleCppStyleBasedOn("llvm")));
+}
+
+TEST_F(FormatTestRawStrings, MatchesDelimitersCaseSensitively) {
+  // Don't touch the 'PB' raw string, format the 'pb' raw string.
+  expect_eq(R"test(
+s = R"PB(item:1)PB";
+t = R"pb(item: 1)pb";)test",
+            format(R"test(
+s = R"PB(item:1)PB";
+t = R"pb(item:1)pb";)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  FormatStyle MixedStyle = getLLVMStyle();
+  MixedStyle.RawStringFormats = {
+      {/*Delimiter=*/"cpp", /*Kind=*/FormatStyle::LK_Cpp,
+       /*BasedOnStyle=*/"llvm"},
+      {/*Delimiter=*/"CPP", /*Kind=*/FormatStyle::LK_Cpp,
+       /*BasedOnStyle=*/"google"}};
+
+  // Format the 'cpp' raw string with '*' on the right.
+  // Format the 'CPP' raw string with '*' on the left.
+  // Do not format the 'Cpp' raw string.
+  // Do not format non-raw strings.
+  expect_eq(R"test(
+a = R"cpp(int *i = 0;)cpp";
+b = R"CPP(int* j = 0;)CPP";
+c = R"Cpp(int * k = 0;)Cpp";
+d = R"cpp(int * k = 0;)Cpp";)test",
+            format(R"test(
+a = R"cpp(int * i = 0;)cpp";
+b = R"CPP(int * j = 0;)CPP";
+c = R"Cpp(int * k = 0;)Cpp";
+d = R"cpp(int * k = 0;)Cpp";)test",
+                   MixedStyle));
+}
+
+TEST_F(FormatTestRawStrings, ReformatsShortRawStringsOnSingleLine) {
+  expect_eq(
+      R"test(P p = TP(R"pb()pb");)test",
+      format(
+          R"test(P p = TP(R"pb( )pb");)test",
+          getRawStringPbStyleWithColumns(40)));
+  expect_eq(
+      R"test(P p = TP(R"pb(item_1: 1)pb");)test",
+      format(
+          R"test(P p = TP(R"pb(item_1:1)pb");)test",
+          getRawStringPbStyleWithColumns(40)));
+  expect_eq(
+      R"test(P p = TP(R"pb(item_1: 1)pb");)test",
+      format(
+          R"test(P p = TP(R"pb(  item_1 :  1   )pb");)test",
+          getRawStringPbStyleWithColumns(40)));
+  expect_eq(
+      R"test(P p = TP(R"pb(item_1: 1 item_2: 2)pb");)test",
+      format(
+          R"test(P p = TP(R"pb(item_1:1 item_2:2)pb");)test",
+          getRawStringPbStyleWithColumns(40)));
+  expect_eq(
+      R"test(P p = TP(R"pb(item_1 <1> item_2: {2})pb");)test",
+      format(
+          R"test(P p = TP(R"pb(item_1<1> item_2:{2})pb");)test",
+          getRawStringPbStyleWithColumns(40)));
+
+  // Merge two short lines into one.
+  expect_eq(R"test(
+std::string s = R"pb(
+  item_1: 1 item_2: 2
+)pb";
+)test",
+            format(R"test(
+std::string s = R"pb(
+  item_1:1
+  item_2:2
+)pb";
+)test",
+                   getRawStringPbStyleWithColumns(40)));
+}
+
+TEST_F(FormatTestRawStrings, BreaksRawStringsExceedingColumnLimit) {
+  expect_eq(R"test(
+P p = TPPPPPPPPPPPPPPP(
+    R"pb(item_1: 1, item_2: 2)pb");)test",
+            format(R"test(
+P p = TPPPPPPPPPPPPPPP(R"pb(item_1: 1, item_2: 2)pb");)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+P p =
+    TPPPPPPPPPPPPPPP(
+        R"pb(item_1: 1,
+             item_2: 2,
+             item_3: 3)pb");)test",
+            format(R"test(
+P p = TPPPPPPPPPPPPPPP(R"pb(item_1: 1, item_2: 2, item_3: 3)pb");)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+P p = TP(R"pb(item_1 <1>
+              item_2: <2>
+              item_3 {})pb");)test",
+      format(R"test(
+P p = TP(R"pb(item_1<1> item_2:<2> item_3{ })pb");)test",
+          getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(
+      R"test(
+P p = TP(R"pb(item_1: 1,
+              item_2: 2,
+              item_3: 3,
+              item_4: 4)pb");)test",
+      format(
+          R"test(
+P p = TP(R"pb(item_1: 1, item_2: 2, item_3: 3, item_4: 4)pb");)test",
+          getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+P p = TPPPPPPPPPPPPPPP(
+    R"pb(item_1 <1>,
+         item_2: {2},
+         item_3: <3>,
+         item_4: {4})pb");)test",
+            format(R"test(
+P p = TPPPPPPPPPPPPPPP(R"pb(item_1<1>, item_2: {2}, item_3: <3>, item_4:{4})pb");)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  // Breaks before a short raw string exceeding the column limit.
+  expect_eq(R"test(
+FFFFFFFFFFFFFFFFFFFFFFFFFFF(
+    R"pb(key: 1)pb");
+P p = TPPPPPPPPPPPPPPPPPPPP(
+    R"pb(key: 2)pb");
+auto TPPPPPPPPPPPPPPPPPPPP =
+    R"pb(key: 3)pb";
+P p = TPPPPPPPPPPPPPPPPPPPP(
+    R"pb(i: 1, j: 2)pb");
+
+int f(string s) {
+  FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF(
+      R"pb(key: 1)pb");
+  P p = TPPPPPPPPPPPPPPPPPPPP(
+      R"pb(key: 2)pb");
+  auto TPPPPPPPPPPPPPPPPPPPP =
+      R"pb(key: 3)pb";
+  if (s.empty())
+    P p = TPPPPPPPPPPPPPPPPPPPP(
+        R"pb(i: 1, j: 2)pb");
+}
+)test",
+            format(R"test(
+FFFFFFFFFFFFFFFFFFFFFFFFFFF(R"pb(key:1)pb");
+P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(key:2)pb");
+auto TPPPPPPPPPPPPPPPPPPPP = R"pb(key:3)pb";
+P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(i: 1, j:2)pb");
+
+int f(string s) {
+  FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF(R"pb(key:1)pb");
+  P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(key:2)pb");
+  auto TPPPPPPPPPPPPPPPPPPPP = R"pb(key:3)pb";
+  if (s.empty())
+    P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(i: 1, j:2)pb");
+}
+)test",
+                   getRawStringPbStyleWithColumns(40)));
+}
+
+TEST_F(FormatTestRawStrings, FormatsRawStringArguments) {
+  expect_eq(R"test(
+P p = TP(R"pb(key {1})pb", param_2);)test",
+            format(R"test(
+P p = TP(R"pb(key{1})pb",param_2);)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+PPPPPPPPPPPPP(R"pb(keykeyk)pb",
+              param_2);)test",
+            format(R"test(
+PPPPPPPPPPPPP(R"pb(keykeyk)pb", param_2);)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+P p =
+    TP(R"pb(item: {i: 1, s: 's'}
+            item: {i: 2, s: 't'})pb");)test",
+            format(R"test(
+P p = TP(R"pb(item: {i: 1, s: 's'} item: {i: 2, s: 't'})pb");)test",
+                   getRawStringPbStyleWithColumns(40)));
+  expect_eq(R"test(
+FFFFFFFFFFFFFFFFFFF(
+    R"pb(key: "value")pb",
+    R"pb(key2: "value")pb");)test",
+            format(R"test(
+FFFFFFFFFFFFFFFFFFF(R"pb(key: "value")pb", R"pb(key2: "value")pb");)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  // Formats the first out of two arguments.
+  expect_eq(R"test(
+FFFFFFFF(R"pb(key: 1)pb", argument2);
+struct S {
+  const s =
+      f(R"pb(key: 1)pb", argument2);
+  void f() {
+    if (gol)
+      return g(R"pb(key: 1)pb",
+               132789237);
+    return g(R"pb(key: 1)pb", "172893");
+  }
+};)test",
+            format(R"test(
+FFFFFFFF(R"pb(key:1)pb", argument2);
+struct S {
+const s = f(R"pb(key:1)pb", argument2);
+void f() {
+  if (gol)
+    return g(R"pb(key:1)pb", 132789237);
+  return g(R"pb(key:1)pb", "172893");
+}
+};)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  // Formats the second out of two arguments.
+  expect_eq(R"test(
+FFFFFFFF(argument1, R"pb(key: 2)pb");
+struct S {
+  const s =
+      f(argument1, R"pb(key: 2)pb");
+  void f() {
+    if (gol)
+      return g(12784137,
+               R"pb(key: 2)pb");
+    return g(17283122, R"pb(key: 2)pb");
+  }
+};)test",
+            format(R"test(
+FFFFFFFF(argument1, R"pb(key:2)pb");
+struct S {
+const s = f(argument1, R"pb(key:2)pb");
+void f() {
+  if (gol)
+    return g(12784137, R"pb(key:2)pb");
+  return g(17283122, R"pb(key:2)pb");
+}
+};)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  // Formats two short raw string arguments.
+  expect_eq(R"test(
+FFFFF(R"pb(key: 1)pb", R"pb(key: 2)pb");)test",
+            format(R"test(
+FFFFF(R"pb(key:1)pb", R"pb(key:2)pb");)test",
+                   getRawStringPbStyleWithColumns(40)));
+  // TODO(krasimir): The original source code fits on one line, so the
+  // non-optimizing formatter is chosen. But after the formatting in protos is
+  // made, the code doesn't fit on one line anymore and further formatting
+  // splits it.
+  //
+  // Should we disable raw string formatting for the non-optimizing formatter?
+  expect_eq(R"test(
+FFFFFFF(R"pb(key: 1)pb", R"pb(key: 2)pb");)test",
+            format(R"test(
+FFFFFFF(R"pb(key:1)pb", R"pb(key:2)pb");)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  // Formats two short raw string arguments, puts second on newline.
+  expect_eq(R"test(
+FFFFFFFF(R"pb(key: 1)pb",
+         R"pb(key: 2)pb");)test",
+            format(R"test(
+FFFFFFFF(R"pb(key:1)pb", R"pb(key:2)pb");)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  // Formats both arguments.
+  expect_eq(R"test(
+FFFFFFFF(R"pb(key: 1)pb",
+         R"pb(key: 2)pb");
+struct S {
+  const s = f(R"pb(key: 1)pb",
+              R"pb(key: 2)pb");
+  void f() {
+    if (gol)
+      return g(R"pb(key: 1)pb",
+               R"pb(key: 2)pb");
+    return g(R"pb(k1)pb", R"pb(k2)pb");
+  }
+};)test",
+            format(R"test(
+FFFFFFFF(R"pb(key:1)pb", R"pb(key:2)pb");
+struct S {
+const s = f(R"pb(key:1)pb", R"pb(key:2)pb");
+void f() {
+  if (gol)
+    return g(R"pb(key:1)pb", R"pb(key:2)pb");
+  return g(R"pb( k1 )pb", R"pb( k2 )pb");
+}
+};)test",
+                   getRawStringPbStyleWithColumns(40)));
+}
+
+TEST_F(FormatTestRawStrings, RawStringStartingWithNewlines) {
+  expect_eq(R"test(
+std::string s = R"pb(
+  item_1: 1
+)pb";
+)test",
+            format(R"test(
+std::string s = R"pb(
+    item_1:1
+)pb";
+)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+std::string s = R"pb(
+
+  item_1: 1
+)pb";
+)test",
+            format(R"test(
+std::string s = R"pb(
+
+    item_1:1
+)pb";
+)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+std::string s = R"pb(
+  item_1: 1
+)pb";
+)test",
+            format(R"test(
+std::string s = R"pb(
+    item_1:1
+
+)pb";
+)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+std::string s = R"pb(
+  item_1: 1,
+  item_2: 2
+)pb";
+)test",
+            format(R"test(
+std::string s = R"pb(
+  item_1:1, item_2:2
+)pb";
+)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+std::string s = R"pb(
+  book {
+    title: "Alice's Adventures"
+    author: "Lewis Caroll"
+  }
+  book {
+    title: "Peter Pan"
+    author: "J. M. Barrie"
+  }
+)pb";
+)test",
+            format(R"test(
+std::string s = R"pb(
+    book { title: "Alice's Adventures" author: "Lewis Caroll" }
+    book { title: "Peter Pan" author: "J. M. Barrie" }
+)pb";
+)test",
+                   getRawStringPbStyleWithColumns(40)));
+}
+
+TEST_F(FormatTestRawStrings, BreaksBeforeRawStrings) {
+  expect_eq(R"test(
+ASSERT_TRUE(
+    ParseFromString(R"pb(item_1: 1)pb"),
+    ptr);)test",
+            format(R"test(
+ASSERT_TRUE(ParseFromString(R"pb(item_1: 1)pb"), ptr);)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+ASSERT_TRUE(toolong::ParseFromString(
+                R"pb(item_1: 1)pb"),
+            ptr);)test",
+            format(R"test(
+ASSERT_TRUE(toolong::ParseFromString(R"pb(item_1: 1)pb"), ptr);)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+ASSERT_TRUE(ParseFromString(
+                R"pb(item_1: 1,
+                     item_2: 2)pb"),
+            ptr);)test",
+            format(R"test(
+ASSERT_TRUE(ParseFromString(R"pb(item_1: 1, item_2: 2)pb"), ptr);)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+ASSERT_TRUE(
+    ParseFromString(
+        R"pb(item_1: 1 item_2: 2)pb"),
+    ptr);)test",
+            format(R"test(
+ASSERT_TRUE(ParseFromString(R"pb(item_1: 1 item_2: 2)pb"), ptr);)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+}
+
+TEST_F(FormatTestRawStrings, RawStringsInOperands) {
+  // Formats the raw string first operand of a binary operator expression.
+  expect_eq(R"test(auto S = R"pb(item_1: 1)pb" + rest;)test",
+            format(R"test(auto S = R"pb(item_1:1)pb" + rest;)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+auto S = R"pb(item_1: 1, item_2: 2)pb" +
+         rest;)test",
+            format(R"test(
+auto S = R"pb(item_1:1,item_2:2)pb"+rest;)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+auto S =
+    R"pb(item_1: 1 item_2: 2)pb" + rest;)test",
+            format(R"test(
+auto S = R"pb(item_1:1 item_2:2)pb"+rest;)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+auto S = R"pb(item_1: 1,
+              item_2: 2,
+              item_3: 3)pb" + rest;)test",
+            format(R"test(
+auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+rest;)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+auto S = R"pb(item_1: 1,
+              item_2: 2,
+              item_3: 3)pb" +
+         longlongrest;)test",
+            format(R"test(
+auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+longlongrest;)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  // Formats the raw string second operand of a binary operator expression.
+  expect_eq(R"test(auto S = first + R"pb(item_1: 1)pb";)test",
+            format(R"test(auto S = first + R"pb(item_1:1)pb";)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+auto S = first + R"pb(item_1: 1,
+                      item_2: 2)pb";)test",
+            format(R"test(
+auto S = first+R"pb(item_1:1,item_2:2)pb";)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+auto S = first + R"pb(item_1: 1
+                      item_2: 2)pb";)test",
+            format(R"test(
+auto S = first+R"pb(item_1:1 item_2:2)pb";)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+auto S = R"pb(item_1: 1,
+              item_2: 2,
+              item_3: 3)pb" + rest;)test",
+            format(R"test(
+auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+rest;)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+auto S = R"pb(item_1: 1,
+              item_2: 2,
+              item_3: 3)pb" +
+         longlongrest;)test",
+            format(R"test(
+auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+longlongrest;)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  // Formats the raw string operands in expressions.
+  expect_eq(R"test(
+auto S = R"pb(item_1: 1)pb" +
+         R"pb(item_2: 2)pb";
+)test",
+            format(R"test(
+auto S=R"pb(item_1:1)pb"+R"pb(item_2:2)pb";
+)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+auto S = R"pb(item_1: 1)pb" +
+         R"pb(item_2: 2)pb" +
+         R"pb(item_3: 3)pb";
+)test",
+            format(R"test(
+auto S=R"pb(item_1:1)pb"+R"pb(item_2:2)pb"+R"pb(item_3:3)pb";
+)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+auto S = (count < 3)
+             ? R"pb(item_1: 1)pb"
+             : R"pb(item_2: 2)pb";
+)test",
+            format(R"test(
+auto S=(count<3)?R"pb(item_1:1)pb":R"pb(item_2:2)pb";
+)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+auto S =
+    (count < 3)
+        ? R"pb(item_1: 1, item_2: 2)pb"
+        : R"pb(item_3: 3)pb";
+)test",
+            format(R"test(
+auto S=(count<3)?R"pb(item_1:1,item_2:2)pb":R"pb(item_3:3)pb";
+)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+  expect_eq(R"test(
+auto S =
+    (count < 3)
+        ? R"pb(item_1: 1)pb"
+        : R"pb(item_2: 2, item_3: 3)pb";
+)test",
+            format(R"test(
+auto S=(count<3)?R"pb(item_1:1)pb":R"pb(item_2:2,item_3:3)pb";
+)test",
+                   getRawStringPbStyleWithColumns(40)));
+
+}
+
+TEST_F(FormatTestRawStrings, PrefixAndSuffixAlignment) {
+  // Keep the suffix at the end of line if not on newline.
+  expect_eq(R"test(
+int s() {
+  auto S = PTP(
+      R"pb(
+        item_1: 1,
+        item_2: 2)pb");
+})test",
+            format(R"test(
+int s() {
+  auto S = PTP(
+      R"pb(
+      item_1: 1,
+      item_2: 2)pb");
+})test",
+                   getRawStringPbStyleWithColumns(20)));
+
+  // Align the suffix with the surrounding FirstIndent if the prefix is not on
+  // a line of its own.
+  expect_eq(R"test(
+int s() {
+  auto S = PTP(
+      R"pb(
+        item_1: 1,
+        item_2: 2
+      )pb");
+})test",
+            format(R"test(
+int s() {
+  auto S = PTP(R"pb(
+      item_1: 1,
+      item_2: 2
+      )pb");
+})test",
+                   getRawStringPbStyleWithColumns(20)));
+
+  // Align the prefix with the suffix if both the prefix and suffix are on a
+  // line of their own.
+  expect_eq(R"test(
+int s() {
+  auto S = PTP(
+      R"pb(
+        item_1: 1,
+        item_2: 2,
+      )pb");
+})test",
+            format(R"test(
+int s() {
+  auto S = PTP(
+      R"pb(
+      item_1: 1,
+      item_2: 2,
+      )pb");
+})test",
+                   getRawStringPbStyleWithColumns(20)));
+}
+
+TEST_F(FormatTestRawStrings, EstimatesPenalty) {
+  // The penalty for characters exceeding the column limit in the raw string
+  // forces 'hh' to be put on a newline.
+  expect_eq(R"test(
+ff(gggggg,
+   hh(R"pb(key {
+             i1: k1
+             i2: k2
+           })pb"));
+)test",
+            format(R"test(
+ff(gggggg, hh(R"pb(key {
+    i1: k1
+    i2: k2
+    })pb"));
+)test",
+                   getRawStringPbStyleWithColumns(20)));
+}
+
+TEST_F(FormatTestRawStrings, DontFormatNonRawStrings) {
+  expect_eq(R"test(a = R"pb(key:value)";)test",
+            format(R"test(a = R"pb(key:value)";)test",
+                   getRawStringPbStyleWithColumns(20)));
+}
+
+} // end namespace
+} // end namespace format
+} // end namespace clang
-- 
GitLab


From 1f7d6d2a2190730170a0d55d58cdc87aaffa7cb9 Mon Sep 17 00:00:00 2001
From: Krasimir Georgiev 
Date: Mon, 30 Oct 2017 14:30:14 +0000
Subject: [PATCH 0136/1682] Keep MSVC2015 happy after r316903

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316906 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Format/Format.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index ecc2bb7b84..0cd5398751 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -1027,8 +1027,8 @@ public:
                     /*LastStartColumn=*/Env.getLastStartColumn());
     for (const auto &R : Whitespaces.generateReplacements())
       if (Result.add(R))
-        return {Result, 0};
-    return {Result, Penalty};
+        return std::make_pair(Result, 0);
+    return std::make_pair(Result, Penalty);
   }
 
 private:
-- 
GitLab


From 5aa4dd9f9d3038556d897395f07c1ea40ab7a28b Mon Sep 17 00:00:00 2001
From: Yaxun Liu 
Date: Mon, 30 Oct 2017 14:38:30 +0000
Subject: [PATCH 0137/1682] CodeGen: Fix insertion position of addrspace cast
 for alloca

For non-zero alloca addr space, alloca is usually casted to default addr
space immediately.

For non-vla, alloca is inserted at AllocaInsertPt, therefore the addr
space cast should also be insterted at AllocaInsertPt. However,
for vla, alloca is inserted at the current insertion point of IRBuilder,
therefore the addr space cast should also inserted at the current
insertion point of IRBuilder.

Currently clang always insert addr space cast at AllocaInsertPt, which
causes invalid IR.

This patch fixes that.

Differential Revision: https://reviews.llvm.org/D39374


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316909 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/CodeGen/CGExpr.cpp  |  6 +++++-
 test/CodeGenCXX/vla.cpp | 31 +++++++++++++++++++++++--------
 2 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 431ffa55d1..d3c2f47093 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -75,7 +75,11 @@ Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align,
   if (CastToDefaultAddrSpace && getASTAllocaAddressSpace() != LangAS::Default) {
     auto DestAddrSpace = getContext().getTargetAddressSpace(LangAS::Default);
     llvm::IRBuilderBase::InsertPointGuard IPG(Builder);
-    Builder.SetInsertPoint(AllocaInsertPt);
+    // When ArraySize is nullptr, alloca is inserted at AllocaInsertPt,
+    // otherwise alloca is inserted at the current insertion point of the
+    // builder.
+    if (!ArraySize)
+      Builder.SetInsertPoint(AllocaInsertPt);
     V = getTargetHooks().performAddrSpaceCast(
         *this, V, getASTAllocaAddressSpace(), LangAS::Default,
         Ty->getPointerTo(DestAddrSpace), /*non-null*/ true);
diff --git a/test/CodeGenCXX/vla.cpp b/test/CodeGenCXX/vla.cpp
index 957a9f9568..b8652f8329 100644
--- a/test/CodeGenCXX/vla.cpp
+++ b/test/CodeGenCXX/vla.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck -check-prefixes=X64,CHECK %s
+// RUN: %clang_cc1 -std=c++11 -triple amdgcn---amdgiz %s -emit-llvm -o - | FileCheck -check-prefixes=AMD,CHECK %s
 
 template
 struct S {
@@ -9,7 +10,7 @@ template int S::n = 5;
 int f() {
   // Make sure that the reference here is enough to trigger the instantiation of
   // the static data member.
-  // CHECK: @_ZN1SIiE1nE = linkonce_odr global i32 5
+  // CHECK: @_ZN1SIiE1nE = linkonce_odr{{.*}} global i32 5
   int a[S::n];
   return sizeof a;
 }
@@ -17,10 +18,18 @@ int f() {
 // rdar://problem/9506377
 void test0(void *array, int n) {
   // CHECK-LABEL: define void @_Z5test0Pvi(
-  // CHECK:      [[ARRAY:%.*]] = alloca i8*, align 8
-  // CHECK-NEXT: [[N:%.*]] = alloca i32, align 4
-  // CHECK-NEXT: [[REF:%.*]] = alloca i16*, align 8
-  // CHECK-NEXT: [[S:%.*]] = alloca i16, align 2
+  // X64:        [[ARRAY:%.*]] = alloca i8*, align 8
+  // AMD:        [[ARRAY0:%.*]] = alloca i8*, align 8, addrspace(5)
+  // AMD-NEXT:   [[ARRAY:%.*]] = addrspacecast i8* addrspace(5)* [[ARRAY0]] to i8**
+  // X64-NEXT:   [[N:%.*]] = alloca i32, align 4
+  // AMD:        [[N0:%.*]] = alloca i32, align 4, addrspace(5)
+  // AMD-NEXT:   [[N:%.*]] = addrspacecast i32 addrspace(5)* [[N0]] to i32*
+  // X64-NEXT:   [[REF:%.*]] = alloca i16*, align 8
+  // AMD:        [[REF0:%.*]] = alloca i16*, align 8, addrspace(5)
+  // AMD-NEXT:   [[REF:%.*]] = addrspacecast i16* addrspace(5)* [[REF0]] to i16**
+  // X64-NEXT:   [[S:%.*]] = alloca i16, align 2
+  // AMD:        [[S0:%.*]] = alloca i16, align 2, addrspace(5)
+  // AMD-NEXT:   [[S:%.*]] = addrspacecast i16 addrspace(5)* [[S0]] to i16*
   // CHECK-NEXT: store i8* 
   // CHECK-NEXT: store i32
 
@@ -59,6 +68,8 @@ void test0(void *array, int n) {
 void test2(int b) {
   // CHECK-LABEL: define void {{.*}}test2{{.*}}(i32 %b)
   int varr[b];
+  // AMD: %__end = alloca i32*, align 8, addrspace(5)
+  // AMD: [[END:%.*]] = addrspacecast i32* addrspace(5)* %__end to i32**
   // get the address of %b by checking the first store that stores it 
   //CHECK: store i32 %b, i32* [[PTR_B:%.*]]
 
@@ -75,13 +86,16 @@ void test2(int b) {
   //CHECK: [[VLA_SIZEOF:%.*]] = mul nuw i64 4, [[VLA_NUM_ELEMENTS_PRE]]
   //CHECK-NEXT: [[VLA_NUM_ELEMENTS_POST:%.*]] = udiv i64 [[VLA_SIZEOF]], 4
   //CHECK-NEXT: [[VLA_END_PTR:%.*]] = getelementptr inbounds i32, i32* {{%.*}}, i64 [[VLA_NUM_ELEMENTS_POST]]
-  //CHECK-NEXT: store i32* [[VLA_END_PTR]], i32** %__end
+  //X64-NEXT: store i32* [[VLA_END_PTR]], i32** %__end
+  //AMD-NEXT: store i32* [[VLA_END_PTR]], i32** [[END]]
   for (int d : varr) 0;
 }
 
 void test3(int b, int c) {
   // CHECK-LABEL: define void {{.*}}test3{{.*}}(i32 %b, i32 %c)
   int varr[b][c];
+  // AMD: %__end = alloca i32*, align 8, addrspace(5)
+  // AMD: [[END:%.*]] = addrspacecast i32* addrspace(5)* %__end to i32**
   // get the address of %b by checking the first store that stores it 
   //CHECK: store i32 %b, i32* [[PTR_B:%.*]]
   //CHECK-NEXT: store i32 %c, i32* [[PTR_C:%.*]]
@@ -105,7 +119,8 @@ void test3(int b, int c) {
   //CHECK-NEXT: [[VLA_NUM_ELEMENTS:%.*]] = udiv i64 [[VLA_SIZEOF]], [[VLA_SIZEOF_DIM2]]
   //CHECK-NEXT: [[VLA_END_INDEX:%.*]] = mul nsw i64 [[VLA_NUM_ELEMENTS]], [[VLA_DIM2_PRE]]
   //CHECK-NEXT: [[VLA_END_PTR:%.*]] = getelementptr inbounds i32, i32* {{%.*}}, i64 [[VLA_END_INDEX]]
-  //CHECK-NEXT: store i32* [[VLA_END_PTR]], i32** %__end
+  //X64-NEXT: store i32* [[VLA_END_PTR]], i32** %__end
+  //AMD-NEXT: store i32* [[VLA_END_PTR]], i32** [[END]]
  
   for (auto &d : varr) 0;
 }
-- 
GitLab


From f822d3299b46ebefc293d06360e47a6bd731b4bd Mon Sep 17 00:00:00 2001
From: Krasimir Georgiev 
Date: Mon, 30 Oct 2017 14:41:34 +0000
Subject: [PATCH 0138/1682] [clang-format] Handle CRLF correctly when
 formatting escaped newlines

Subscribers: klimek

Differential Revision: https://reviews.llvm.org/D39420

Contributed by @peterbudai!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316910 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Format/FormatTokenLexer.cpp | 18 ++++++++++++-----
 unittests/Format/FormatTest.cpp | 34 +++++++++++++++++++++++++++++----
 2 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/lib/Format/FormatTokenLexer.cpp b/lib/Format/FormatTokenLexer.cpp
index d37fcec6c5..727437a2a5 100644
--- a/lib/Format/FormatTokenLexer.cpp
+++ b/lib/Format/FormatTokenLexer.cpp
@@ -554,13 +554,21 @@ FormatToken *FormatTokenLexer::getNextToken() {
   // take them into account as whitespace - this pattern is quite frequent
   // in macro definitions.
   // FIXME: Add a more explicit test.
-  while (FormatTok->TokenText.size() > 1 && FormatTok->TokenText[0] == '\\' &&
-         FormatTok->TokenText[1] == '\n') {
+  while (FormatTok->TokenText.size() > 1 && FormatTok->TokenText[0] == '\\') {
+    unsigned SkippedWhitespace = 0;
+    if (FormatTok->TokenText.size() > 2 &&
+        (FormatTok->TokenText[1] == '\r' && FormatTok->TokenText[2] == '\n'))
+      SkippedWhitespace = 3;
+    else if (FormatTok->TokenText[1] == '\n')
+      SkippedWhitespace = 2;
+    else
+      break;
+
     ++FormatTok->NewlinesBefore;
-    WhitespaceLength += 2;
-    FormatTok->LastNewlineOffset = 2;
+    WhitespaceLength += SkippedWhitespace;
+    FormatTok->LastNewlineOffset = SkippedWhitespace;
     Column = 0;
-    FormatTok->TokenText = FormatTok->TokenText.substr(2);
+    FormatTok->TokenText = FormatTok->TokenText.substr(SkippedWhitespace);
   }
 
   FormatTok->WhitespaceRange = SourceRange(
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 3651fa539d..82530c0376 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -2629,14 +2629,39 @@ TEST_F(FormatTest, FormatUnbalancedStructuralElements) {
 }
 
 TEST_F(FormatTest, EscapedNewlines) {
-  EXPECT_EQ(
-      "#define A \\\n  int i;  \\\n  int j;",
-      format("#define A \\\nint i;\\\n  int j;", getLLVMStyleWithColumns(11)));
+  FormatStyle Narrow = getLLVMStyleWithColumns(11);
+  EXPECT_EQ("#define A \\\n  int i;  \\\n  int j;",
+            format("#define A \\\nint i;\\\n  int j;", Narrow));
   EXPECT_EQ("#define A\n\nint i;", format("#define A \\\n\n int i;"));
   EXPECT_EQ("template  f();", format("\\\ntemplate  f();"));
   EXPECT_EQ("/* \\  \\  \\\n */", format("\\\n/* \\  \\  \\\n */"));
   EXPECT_EQ("", format(""));
 
+  FormatStyle AlignLeft = getLLVMStyle();
+  AlignLeft.AlignEscapedNewlines = FormatStyle::ENAS_Left;
+  EXPECT_EQ("#define MACRO(x) \\\n"
+            "private:         \\\n"
+            "  int x(int a);\n",
+            format("#define MACRO(x) \\\n"
+                   "private:         \\\n"
+                   "  int x(int a);\n",
+                   AlignLeft));
+
+  // CRLF line endings
+  EXPECT_EQ("#define A \\\r\n  int i;  \\\r\n  int j;",
+            format("#define A \\\r\nint i;\\\r\n  int j;", Narrow));
+  EXPECT_EQ("#define A\r\n\r\nint i;", format("#define A \\\r\n\r\n int i;"));
+  EXPECT_EQ("template  f();", format("\\\ntemplate  f();"));
+  EXPECT_EQ("/* \\  \\  \\\r\n */", format("\\\r\n/* \\  \\  \\\r\n */"));
+  EXPECT_EQ("", format(""));
+  EXPECT_EQ("#define MACRO(x) \\\r\n"
+            "private:         \\\r\n"
+            "  int x(int a);\r\n",
+            format("#define MACRO(x) \\\r\n"
+                   "private:         \\\r\n"
+                   "  int x(int a);\r\n",
+                   AlignLeft));
+
   FormatStyle DontAlign = getLLVMStyle();
   DontAlign.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign;
   DontAlign.MaxEmptyLinesToKeep = 3;
@@ -2659,7 +2684,8 @@ TEST_F(FormatTest, EscapedNewlines) {
                    "\\\n"
                    "  public: \\\n"
                    "    void baz(); \\\n"
-                   "  };", DontAlign));
+                   "  };",
+                   DontAlign));
 }
 
 TEST_F(FormatTest, CalculateSpaceOnConsecutiveLinesInMacro) {
-- 
GitLab


From 1416d5328a4350d5514ac8ec793acd461e6a38c5 Mon Sep 17 00:00:00 2001
From: Gabor Horvath 
Date: Mon, 30 Oct 2017 17:06:42 +0000
Subject: [PATCH 0139/1682] [analyzer] Left shifting a negative value is
 undefined

The analyzer did not return an UndefVal in case a negative value was left
shifted. I also altered the UndefResultChecker to emit a clear warning in this
case.

Differential Revision: https://reviews.llvm.org/D39423


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316924 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp | 4 ++++
 lib/StaticAnalyzer/Core/BasicValueFactory.cpp      | 2 ++
 test/Analysis/bitwise-ops.c                        | 7 +++++++
 3 files changed, 13 insertions(+)

diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index 21e8b107c9..172ce346f1 100644
--- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
@@ -137,6 +137,10 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
 
         OS << " greater or equal to the width of type '"
            << B->getLHS()->getType().getAsString() << "'.";
+      } else if (B->getOpcode() == BinaryOperatorKind::BO_Shl &&
+                 C.isNegative(B->getLHS())) {
+        OS << "The result of the left shift is undefined because the left "
+              "operand is negative";
       } else {
         OS << "The result of the '"
            << BinaryOperator::getOpcodeStr(B->getOpcode())
diff --git a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
index ebbace4e33..ec7a7e9e4b 100644
--- a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -225,6 +225,8 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op,
       // test these conditions symbolically.
 
       // FIXME: Expand these checks to include all undefined behavior.
+      if (V1.isSigned() && V1.isNegative())
+        return nullptr;
 
       if (V2.isSigned() && V2.isNegative())
         return nullptr;
diff --git a/test/Analysis/bitwise-ops.c b/test/Analysis/bitwise-ops.c
index acef6681d8..fe546580be 100644
--- a/test/Analysis/bitwise-ops.c
+++ b/test/Analysis/bitwise-ops.c
@@ -44,3 +44,10 @@ int testNegativeShift(int a) {
   }
   return 0;
 }
+
+int testNegativeLeftShift(int a) {
+  if (a == -3) {
+    return a << 1; // expected-warning{{The result of the left shift is undefined because the left operand is negative}}
+  }
+  return 0;
+}
-- 
GitLab


From 1c7bbb9e3c20aac63ad2056f54ab8be32253c2af Mon Sep 17 00:00:00 2001
From: Richard Smith 
Date: Mon, 30 Oct 2017 18:05:10 +0000
Subject: [PATCH 0140/1682] Add a test to make sure that -Wdeprecated doesn't
 warn on use of 'throw()' in system headers (deprecated in C++17).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316935 91177308-0d34-0410-b5e6-96231b3b80d8
---
 test/SemaCXX/cxx1z-noexcept-function-type.cpp | 4 ++--
 test/SemaCXX/deprecated.cpp                   | 3 +++
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/test/SemaCXX/cxx1z-noexcept-function-type.cpp b/test/SemaCXX/cxx1z-noexcept-function-type.cpp
index 6578eb89b0..bd3d031f58 100644
--- a/test/SemaCXX/cxx1z-noexcept-function-type.cpp
+++ b/test/SemaCXX/cxx1z-noexcept-function-type.cpp
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions %s
-// RUN: %clang_cc1 -std=c++1z -verify -fexceptions -fcxx-exceptions %s -Wno-dynamic-exception-spec
+// RUN: %clang_cc1 -std=c++17 -verify -fexceptions -fcxx-exceptions %s -Wno-dynamic-exception-spec
 // RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions -Wno-c++1z-compat-mangling -DNO_COMPAT_MANGLING %s
-// RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions -Wno-noexcept-type -DNO_COMPAT_MANGLING %s
+// RUN: %clang_cc1 -std=c++17 -verify -fexceptions -fcxx-exceptions -Wno-noexcept-type -DNO_COMPAT_MANGLING %s
 
 #if __cplusplus > 201402L
 
diff --git a/test/SemaCXX/deprecated.cpp b/test/SemaCXX/deprecated.cpp
index 26f30c91b0..a838cda7c4 100644
--- a/test/SemaCXX/deprecated.cpp
+++ b/test/SemaCXX/deprecated.cpp
@@ -93,3 +93,6 @@ namespace DeprecatedCopy {
   void g() { c1 = c2; } // expected-note {{implicit copy assignment operator for 'DeprecatedCopy::Dtor' first required here}}
 }
 #endif
+
+# 1 "/usr/include/system-header.h" 1 3
+void system_header_function(void) throw();
-- 
GitLab


From df09bf11928579bf2d1c55b21ab0f92f8903eb38 Mon Sep 17 00:00:00 2001
From: Richard Smith 
Date: Mon, 30 Oct 2017 18:06:18 +0000
Subject: [PATCH 0141/1682] Undo accidental language mode change in this test.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316936 91177308-0d34-0410-b5e6-96231b3b80d8
---
 test/SemaCXX/cxx1z-noexcept-function-type.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/SemaCXX/cxx1z-noexcept-function-type.cpp b/test/SemaCXX/cxx1z-noexcept-function-type.cpp
index bd3d031f58..814b04c6e4 100644
--- a/test/SemaCXX/cxx1z-noexcept-function-type.cpp
+++ b/test/SemaCXX/cxx1z-noexcept-function-type.cpp
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions %s
 // RUN: %clang_cc1 -std=c++17 -verify -fexceptions -fcxx-exceptions %s -Wno-dynamic-exception-spec
 // RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions -Wno-c++1z-compat-mangling -DNO_COMPAT_MANGLING %s
-// RUN: %clang_cc1 -std=c++17 -verify -fexceptions -fcxx-exceptions -Wno-noexcept-type -DNO_COMPAT_MANGLING %s
+// RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions -Wno-noexcept-type -DNO_COMPAT_MANGLING %s
 
 #if __cplusplus > 201402L
 
-- 
GitLab


From 13cb2b777469657b202e5ad4afc12695f5e811af Mon Sep 17 00:00:00 2001
From: George Karpenkov 
Date: Mon, 30 Oct 2017 19:40:33 +0000
Subject: [PATCH 0142/1682] [analyzer] [tests] Remove empty folders in
 reference results, do not store diffs.txt

Storing diffs.txt is now redundant, as we simply dump the CmpRuns output
to stdout (it is saved in CI and tends to be small).
Not generating those files enables us to remove empty folders, which
confuse git, as it would not add them with reference results.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316948 91177308-0d34-0410-b5e6-96231b3b80d8
---
 utils/analyzer/SATestBuild.py       | 16 ++++++++++++----
 utils/analyzer/SATestUpdateDiffs.py | 13 -------------
 2 files changed, 12 insertions(+), 17 deletions(-)

diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py
index 3c694fb038..60c8796e33 100755
--- a/utils/analyzer/SATestBuild.py
+++ b/utils/analyzer/SATestBuild.py
@@ -120,8 +120,6 @@ BuildLogName = "run_static_analyzer.log"
 # displayed when buildbot detects a build failure.
 NumOfFailuresInSummary = 10
 FailuresSummaryFileName = "failures.txt"
-# Summary of the result diffs.
-DiffsSummaryFileName = "diffs.txt"
 
 # The scan-build result directory.
 SBOutputDirName = "ScanBuildResults"
@@ -434,6 +432,16 @@ def CleanUpEmptyPlists(SBOutputDir):
             continue
 
 
+def CleanUpEmptyFolders(SBOutputDir):
+    """
+    Remove empty folders from results, as git would not store them.
+    """
+    Subfolders = glob.glob(SBOutputDir + "/*")
+    for Folder in Subfolders:
+        if not os.listdir(Folder):
+            os.removedirs(Folder)
+
+
 def checkBuild(SBOutputDir):
     """
     Given the scan-build output directory, checks if the build failed
@@ -446,6 +454,7 @@ def checkBuild(SBOutputDir):
     TotalFailed = len(Failures)
     if TotalFailed == 0:
         CleanUpEmptyPlists(SBOutputDir)
+        CleanUpEmptyFolders(SBOutputDir)
         Plists = glob.glob(SBOutputDir + "/*/*.plist")
         print "Number of bug reports (non-empty plist files) produced: %d" %\
             len(Plists)
@@ -519,9 +528,8 @@ def runCmpResults(Dir, Strictness=0):
         if Verbose == 1:
             print "  Comparing Results: %s %s" % (RefDir, NewDir)
 
-        DiffsPath = os.path.join(NewDir, DiffsSummaryFileName)
         PatchedSourceDirPath = os.path.join(Dir, PatchedSourceDirName)
-        Opts = CmpRuns.CmpOptions(DiffsPath, "", PatchedSourceDirPath)
+        Opts = CmpRuns.CmpOptions(rootA="", rootB=PatchedSourceDirPath)
         # Scan the results, delete empty plist files.
         NumDiffs, ReportsInRef, ReportsInNew = \
             CmpRuns.dumpScanBuildResultsDiff(RefDir, NewDir, Opts, False)
diff --git a/utils/analyzer/SATestUpdateDiffs.py b/utils/analyzer/SATestUpdateDiffs.py
index c1c3a25cf5..2282af15a5 100755
--- a/utils/analyzer/SATestUpdateDiffs.py
+++ b/utils/analyzer/SATestUpdateDiffs.py
@@ -54,22 +54,9 @@ def updateReferenceResults(ProjName, ProjBuildMode):
     # Clean up the generated difference results.
     SATestBuild.cleanupReferenceResults(RefResultsPath)
 
-    # Remove the created .diffs file before adding.
-    removeDiffsSummaryFiles(RefResultsPath)
-
     runCmd('git add "%s"' % (RefResultsPath,))
 
 
-def removeDiffsSummaryFiles(RefResultsPath):
-    """
-    Remove all auto-generated .diffs files in reference data.
-    """
-    for (Dirpath, Dirnames, Filenames) in os.walk(RefResultsPath):
-        if SATestBuild.DiffsSummaryFileName in Filenames:
-            runCmd("rm '%s'" % os.path.join(
-                Dirpath, SATestBuild.DiffsSummaryFileName))
-
-
 def main(argv):
     if len(argv) == 2 and argv[1] in ('-h', '--help'):
         print >> sys.stderr, "Update static analyzer reference results based "\
-- 
GitLab


From 56a61ff5cc594f52cc895851f8a12873f165e051 Mon Sep 17 00:00:00 2001
From: George Karpenkov 
Date: Mon, 30 Oct 2017 22:31:57 +0000
Subject: [PATCH 0143/1682] [analyzer] Use the same filename for the header and
 the implementation of BugReporterVisitor

Differential Revision: https://reviews.llvm.org/D37935

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316963 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h | 2 +-
 .../{BugReporterVisitor.h => BugReporterVisitors.h}         | 6 +++---
 lib/StaticAnalyzer/Core/BugReporterVisitors.cpp             | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)
 rename include/clang/StaticAnalyzer/Core/BugReporter/{BugReporterVisitor.h => BugReporterVisitors.h} (99%)

diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 0f1eb096c4..cd1355d03b 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -17,7 +17,7 @@
 
 #include "clang/Basic/SourceLocation.h"
 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
similarity index 99%
rename from include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
rename to include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
index b72bce5fc9..2043896fd2 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h
@@ -1,4 +1,4 @@
-//===---  BugReporterVisitor.h - Generate PathDiagnostics -------*- C++ -*-===//
+//===---  BugReporterVisitors.h - Generate PathDiagnostics -------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -12,8 +12,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITOR_H
-#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITOR_H
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
+#define LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H
 
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
 #include "llvm/ADT/FoldingSet.h"
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 5f00b516fe..f651596006 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -11,7 +11,7 @@
 //  enhance the diagnostics reported for a bug.
 //
 //===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/Analysis/CFGStmtMap.h"
-- 
GitLab


From 8e62a65f20ac33af4e9608cd9ff2343c4380cc46 Mon Sep 17 00:00:00 2001
From: Richard Smith 
Date: Mon, 30 Oct 2017 22:38:20 +0000
Subject: [PATCH 0144/1682] [modules] Retain multiple using-directives in the
 same scope even if they name the same namespace.

They might have different visibility, and thus discarding all but one of them
can result in rejecting valid code. Also fix name lookup to cope with multiple
using-directives being found that denote the same namespace, where some are not
visible -- don't cache an "already visited" state for a using-directive that we
didn't visit because it was hidden.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316965 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/AST/Decl.cpp                        |  8 ------
 lib/Sema/SemaLookup.cpp                 |  6 ++--
 test/Modules/using-directive-redecl.cpp | 37 +++++++++++++++++++++++++
 3 files changed, 40 insertions(+), 11 deletions(-)
 create mode 100644 test/Modules/using-directive-redecl.cpp

diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index f27df1de81..32a4907251 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1597,14 +1597,6 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD, bool IsKnownNewer) const {
                         cast(OldD)->getQualifier());
   }
 
-  // UsingDirectiveDecl's are not really NamedDecl's, and all have same name.
-  // They can be replaced if they nominate the same namespace.
-  // FIXME: Is this true even if they have different module visibility?
-  if (auto *UD = dyn_cast(this))
-    return UD->getNominatedNamespace()->getOriginalNamespace() ==
-           cast(OldD)->getNominatedNamespace()
-               ->getOriginalNamespace();
-
   if (isRedeclarable(getKind())) {
     if (getCanonicalDecl() != OldD->getCanonicalDecl())
       return false;
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 73aceaaf94..d3f91a4e27 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -155,7 +155,7 @@ namespace {
       while (true) {
         for (auto UD : DC->using_directives()) {
           DeclContext *NS = UD->getNominatedNamespace();
-          if (visited.insert(NS).second && SemaRef.isVisible(UD)) {
+          if (SemaRef.isVisible(UD) && visited.insert(NS).second) {
             addUsingDirective(UD, EffectiveDC);
             queue.push_back(NS);
           }
@@ -1883,7 +1883,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
   // with its using-children.
   for (auto *I : StartDC->using_directives()) {
     NamespaceDecl *ND = I->getNominatedNamespace()->getOriginalNamespace();
-    if (Visited.insert(ND).second && S.isVisible(I))
+    if (S.isVisible(I) && Visited.insert(ND).second)
       Queue.push_back(ND);
   }
 
@@ -1931,7 +1931,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R,
 
     for (auto I : ND->using_directives()) {
       NamespaceDecl *Nom = I->getNominatedNamespace();
-      if (Visited.insert(Nom).second && S.isVisible(I))
+      if (S.isVisible(I) && Visited.insert(Nom).second)
         Queue.push_back(Nom);
     }
   }
diff --git a/test/Modules/using-directive-redecl.cpp b/test/Modules/using-directive-redecl.cpp
new file mode 100644
index 0000000000..94772f30a3
--- /dev/null
+++ b/test/Modules/using-directive-redecl.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -verify %s
+// expected-no-diagnostics
+#pragma clang module build M
+module M { module TDFNodes {} module TDFInterface {} }
+#pragma clang module contents
+  // TDFNodes
+  #pragma clang module begin M.TDFNodes
+  namespace Detail {
+     namespace TDF {
+        class TLoopManager {};
+     }
+  }
+  namespace Internal {
+     namespace TDF {
+        using namespace Detail::TDF;
+     }
+  }
+  #pragma clang module end
+
+  // TDFInterface
+  #pragma clang module begin M.TDFInterface
+    #pragma clang module import M.TDFNodes
+      namespace Internal {
+        namespace TDF {
+          using namespace Detail::TDF;
+        }
+      }
+  #pragma clang module end
+
+#pragma clang module endbuild
+
+#pragma clang module import M.TDFNodes
+namespace Internal {
+  namespace TDF {
+    TLoopManager * use;
+  }
+}
-- 
GitLab


From 597fe911c137f5d3ccd6678925a0848d2cc1455e Mon Sep 17 00:00:00 2001
From: Alex Lorenz 
Date: Mon, 30 Oct 2017 22:55:11 +0000
Subject: [PATCH 0145/1682] Typo correct the condition of 'do-while' before
 exiting its scope

rdar://35172419


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316966 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Parse/ParseStmt.cpp            |  3 +++
 test/SemaObjCXX/typo-correction.mm | 34 +++++++++++++++++++++++++++++-
 2 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 65c3f21f2d..e8cf7d5fa4 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -1479,6 +1479,9 @@ StmtResult Parser::ParseDoStatement() {
   DiagnoseAndSkipCXX11Attributes();
 
   ExprResult Cond = ParseExpression();
+  // Correct the typos in condition before closing the scope.
+  if (Cond.isUsable())
+    Cond = Actions.CorrectDelayedTyposInExpr(Cond);
   T.consumeClose();
   DoScope.Exit();
 
diff --git a/test/SemaObjCXX/typo-correction.mm b/test/SemaObjCXX/typo-correction.mm
index 8dcda7921f..3f8a082a84 100644
--- a/test/SemaObjCXX/typo-correction.mm
+++ b/test/SemaObjCXX/typo-correction.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only
+// RUN: %clang_cc1 %s -verify -fsyntax-only -Wno-objc-root-class
 
 class ClassA {};
 
@@ -55,3 +55,35 @@ void invalidNameInIvarAndPropertyBase() {
   typoCandidate.x = 0; // expected-error {{use of undeclared identifier 'typoCandidate'; did you mean '_typoCandidate'?}}
 }
 @end
+
+// rdar://35172419
+// The scope of 'do-while' ends before typo-correction takes place.
+
+struct Mat2 { int rows; };
+
+@implementation ImplNoInt // expected-warning {{cannot find interface declaration for 'ImplNoInt'}}
+
+- (void)typoCorrentInDoWhile {
+  Mat2 tlMat1; // expected-note {{'tlMat1' declared here}}
+  // Create many scopes to exhaust the cache.
+  do {
+    for (int index = 0; index < 2; index++) {
+      if (true) {
+        for (int specialTileType = 1; specialTileType < 5; specialTileType++) {
+          for (int i = 0; i < 10; i++) {
+            for (double scale = 0.95; scale <= 1.055; scale += 0.05) {
+              for (int j = 0; j < 10; j++) {
+                if (1 > 0.9) {
+                    for (int sptile = 1; sptile < 5; sptile++) {
+                    }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  } while (tlMat.rows); // expected-error {{use of undeclared identifier 'tlMat'; did you mean 'tlMat1'}}
+}
+
+@end
-- 
GitLab


From ed8a16203bd96d50875a9ce3dff6ada8daa50cff Mon Sep 17 00:00:00 2001
From: Alex Lorenz 
Date: Tue, 31 Oct 2017 01:28:17 +0000
Subject: [PATCH 0146/1682] [refactor] select the entire DeclStmt if one ifs
 decls is selected

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316971 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Tooling/Refactoring/ASTSelection.cpp | 22 +++++++---
 unittests/Tooling/ASTSelectionTest.cpp   | 56 ++++++++++++++++++++++++
 2 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/lib/Tooling/Refactoring/ASTSelection.cpp b/lib/Tooling/Refactoring/ASTSelection.cpp
index 9d0683a285..6ac432622c 100644
--- a/lib/Tooling/Refactoring/ASTSelection.cpp
+++ b/lib/Tooling/Refactoring/ASTSelection.cpp
@@ -279,11 +279,23 @@ static void findDeepestWithKind(
     llvm::SmallVectorImpl &MatchingNodes,
     SourceSelectionKind Kind,
     llvm::SmallVectorImpl &ParentStack) {
-  if (!hasAnyDirectChildrenWithKind(ASTSelection, Kind)) {
-    // This node is the bottom-most.
-    MatchingNodes.push_back(SelectedNodeWithParents{
-        std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}});
-    return;
+  if (ASTSelection.Node.get()) {
+    // Select the entire decl stmt when any of its child declarations is the
+    // bottom-most.
+    for (const auto &Child : ASTSelection.Children) {
+      if (!hasAnyDirectChildrenWithKind(Child, Kind)) {
+        MatchingNodes.push_back(SelectedNodeWithParents{
+            std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}});
+        return;
+      }
+    }
+  } else {
+    if (!hasAnyDirectChildrenWithKind(ASTSelection, Kind)) {
+      // This node is the bottom-most.
+      MatchingNodes.push_back(SelectedNodeWithParents{
+          std::cref(ASTSelection), {ParentStack.begin(), ParentStack.end()}});
+      return;
+    }
   }
   // Search in the children.
   ParentStack.push_back(std::cref(ASTSelection));
diff --git a/unittests/Tooling/ASTSelectionTest.cpp b/unittests/Tooling/ASTSelectionTest.cpp
index 79e89f90f4..94435d49a8 100644
--- a/unittests/Tooling/ASTSelectionTest.cpp
+++ b/unittests/Tooling/ASTSelectionTest.cpp
@@ -840,4 +840,60 @@ void f() {
       });
 }
 
+TEST(ASTSelectionFinder, SelectEntireDeclStmtRange) {
+  StringRef Source = R"(
+void f(int x, int y) {
+   int a = x * y;
+}
+)";
+  // 'int a = x * y'
+  findSelectedASTNodesWithRange(
+      Source, {3, 4}, FileRange{{3, 4}, {3, 17}},
+      [](SourceRange SelectionRange, Optional Node) {
+        EXPECT_TRUE(Node);
+        Optional SelectedCode =
+            CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+        EXPECT_TRUE(SelectedCode);
+        EXPECT_EQ(SelectedCode->size(), 1u);
+        EXPECT_TRUE(isa((*SelectedCode)[0]));
+        ArrayRef Parents =
+            SelectedCode->getParents();
+        EXPECT_EQ(Parents.size(), 3u);
+        EXPECT_TRUE(
+            isa(Parents[0].get().Node.get()));
+        // Function 'f' definition.
+        EXPECT_TRUE(isa(Parents[1].get().Node.get()));
+        // Function body of function 'F'.
+        EXPECT_TRUE(isa(Parents[2].get().Node.get()));
+      });
+}
+
+TEST(ASTSelectionFinder, SelectEntireDeclStmtRangeWithMultipleDecls) {
+  StringRef Source = R"(
+void f(int x, int y) {
+   int a = x * y, b = x - y;
+}
+)";
+  // 'b = x - y'
+  findSelectedASTNodesWithRange(
+      Source, {3, 19}, FileRange{{3, 19}, {3, 28}},
+      [](SourceRange SelectionRange, Optional Node) {
+        EXPECT_TRUE(Node);
+        Optional SelectedCode =
+            CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+        EXPECT_TRUE(SelectedCode);
+        EXPECT_EQ(SelectedCode->size(), 1u);
+        EXPECT_TRUE(isa((*SelectedCode)[0]));
+        ArrayRef Parents =
+            SelectedCode->getParents();
+        EXPECT_EQ(Parents.size(), 3u);
+        EXPECT_TRUE(
+            isa(Parents[0].get().Node.get()));
+        // Function 'f' definition.
+        EXPECT_TRUE(isa(Parents[1].get().Node.get()));
+        // Function body of function 'F'.
+        EXPECT_TRUE(isa(Parents[2].get().Node.get()));
+      });
+}
+
 } // end anonymous namespace
-- 
GitLab


From 210431c8134fdeff30834467022ce8c306a4c1dd Mon Sep 17 00:00:00 2001
From: "Ivan A. Kosarev" 
Date: Tue, 31 Oct 2017 11:05:34 +0000
Subject: [PATCH 0147/1682] [CodeGen] Propagate may-alias'ness of lvalues with
 TBAA info

This patch fixes various places in clang to propagate may-alias
TBAA access descriptors during construction of lvalues, thus
eliminating the need for the LValueBaseInfo::MayAlias flag.

This is part of D38126 reworked to be a separate patch to
simplify review.

Differential Revision: https://reviews.llvm.org/D39008


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316988 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/CodeGen/CGExpr.cpp          | 90 ++++++++++++++++-----------------
 lib/CodeGen/CGObjCRuntime.cpp   |  2 +-
 lib/CodeGen/CGOpenMPRuntime.cpp |  9 ++--
 lib/CodeGen/CGValue.h           | 12 ++---
 lib/CodeGen/CodeGenFunction.cpp |  4 +-
 lib/CodeGen/CodeGenFunction.h   | 11 ++--
 lib/CodeGen/CodeGenModule.cpp   | 12 +++--
 lib/CodeGen/CodeGenModule.h     | 17 +++++--
 lib/CodeGen/CodeGenTBAA.cpp     | 73 ++++++++++++++++++--------
 lib/CodeGen/CodeGenTBAA.h       | 55 ++++++++++++++++----
 10 files changed, 173 insertions(+), 112 deletions(-)

diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index d3c2f47093..d3b03e556f 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -1538,8 +1538,6 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
     Load->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node);
   }
 
-  if (BaseInfo.getMayAlias())
-    TBAAInfo = CGM.getTBAAMayAliasAccessInfo();
   CGM.DecorateInstructionWithTBAA(Load, TBAAInfo);
 
   if (EmitScalarRangeCheck(Load, Ty, Loc)) {
@@ -1622,8 +1620,6 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr,
     Store->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node);
   }
 
-  if (BaseInfo.getMayAlias())
-    TBAAInfo = CGM.getTBAAMayAliasAccessInfo();
   CGM.DecorateInstructionWithTBAA(Store, TBAAInfo);
 }
 
@@ -2170,10 +2166,7 @@ CodeGenFunction::EmitLoadOfReference(LValue RefLVal,
                                      TBAAAccessInfo *PointeeTBAAInfo) {
   llvm::LoadInst *Load = Builder.CreateLoad(RefLVal.getAddress(),
                                             RefLVal.isVolatile());
-  TBAAAccessInfo RefTBAAInfo = RefLVal.getTBAAInfo();
-  if (RefLVal.getBaseInfo().getMayAlias())
-    RefTBAAInfo = CGM.getTBAAMayAliasAccessInfo();
-  CGM.DecorateInstructionWithTBAA(Load, RefTBAAInfo);
+  CGM.DecorateInstructionWithTBAA(Load, RefLVal.getTBAAInfo());
 
   CharUnits Align = getNaturalTypeAlignment(RefLVal.getType()->getPointeeType(),
                                             PointeeBaseInfo, PointeeTBAAInfo,
@@ -2356,11 +2349,10 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
         LValue CapLVal =
             EmitCapturedFieldLValue(*this, CapturedStmtInfo->lookup(VD),
                                     CapturedStmtInfo->getContextValue());
-        bool MayAlias = CapLVal.getBaseInfo().getMayAlias();
         return MakeAddrLValue(
             Address(CapLVal.getPointer(), getContext().getDeclAlign(VD)),
-            CapLVal.getType(), LValueBaseInfo(AlignmentSource::Decl, MayAlias),
-            CGM.getTBAAAccessInfo(CapLVal.getType()));
+            CapLVal.getType(), LValueBaseInfo(AlignmentSource::Decl),
+            CapLVal.getTBAAInfo());
       }
 
       assert(isa(CurCodeDecl));
@@ -2504,7 +2496,7 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
          ? emitAddrOfRealComponent(LV.getAddress(), LV.getType())
          : emitAddrOfImagComponent(LV.getAddress(), LV.getType()));
     LValue ElemLV = MakeAddrLValue(Component, T, LV.getBaseInfo(),
-                                   CGM.getTBAAAccessInfo(T));
+                                   CGM.getTBAAInfoForSubobject(LV, T));
     ElemLV.getQuals().addQualifiers(LV.getQuals());
     return ElemLV;
   }
@@ -3242,18 +3234,18 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
     Addr = emitArraySubscriptGEP(*this, Addr, Idx, EltType, /*inbounds*/ true,
                                  SignedIndices, E->getExprLoc());
     return MakeAddrLValue(Addr, EltType, LV.getBaseInfo(),
-                          CGM.getTBAAAccessInfo(EltType));
+                          CGM.getTBAAInfoForSubobject(LV, EltType));
   }
 
-  LValueBaseInfo BaseInfo;
-  TBAAAccessInfo TBAAInfo;
+  LValueBaseInfo EltBaseInfo;
+  TBAAAccessInfo EltTBAAInfo;
   Address Addr = Address::invalid();
   if (const VariableArrayType *vla =
            getContext().getAsVariableArrayType(E->getType())) {
     // The base must be a pointer, which is not an aggregate.  Emit
     // it.  It needs to be emitted first in case it's what captures
     // the VLA bounds.
-    Addr = EmitPointerWithAlignment(E->getBase(), &BaseInfo, &TBAAInfo);
+    Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
     auto *Idx = EmitIdxAfterBase(/*Promote*/true);
 
     // The element count here is the total number of non-VLA elements.
@@ -3277,7 +3269,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
     // Indexing over an interface, as in "NSString *P; P[4];"
 
     // Emit the base pointer.
-    Addr = EmitPointerWithAlignment(E->getBase(), &BaseInfo, &TBAAInfo);
+    Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
     auto *Idx = EmitIdxAfterBase(/*Promote*/true);
 
     CharUnits InterfaceSize = getContext().getTypeSizeInChars(OIT);
@@ -3324,18 +3316,18 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
         *this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
         E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices,
         E->getExprLoc());
-    BaseInfo = ArrayLV.getBaseInfo();
-    TBAAInfo = CGM.getTBAAAccessInfo(E->getType());
+    EltBaseInfo = ArrayLV.getBaseInfo();
+    EltTBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, E->getType());
   } else {
     // The base must be a pointer; emit it with an estimate of its alignment.
-    Addr = EmitPointerWithAlignment(E->getBase(), &BaseInfo, &TBAAInfo);
+    Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
     auto *Idx = EmitIdxAfterBase(/*Promote*/true);
     Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(),
                                  !getLangOpts().isSignedOverflowDefined(),
                                  SignedIndices, E->getExprLoc());
   }
 
-  LValue LV = MakeAddrLValue(Addr, E->getType(), BaseInfo, TBAAInfo);
+  LValue LV = MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
 
   if (getLangOpts().ObjC1 &&
       getLangOpts().getGC() != LangOptions::NonGC) {
@@ -3374,9 +3366,12 @@ static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base,
       return CGF.Builder.CreateElementBitCast(Addr,
                                               CGF.ConvertTypeForMem(ElTy));
     }
-    LValueBaseInfo TypeInfo;
-    CharUnits Align = CGF.getNaturalTypeAlignment(ElTy, &TypeInfo);
-    BaseInfo.mergeForCast(TypeInfo);
+    LValueBaseInfo TypeBaseInfo;
+    TBAAAccessInfo TypeTBAAInfo;
+    CharUnits Align = CGF.getNaturalTypeAlignment(ElTy, &TypeBaseInfo,
+                                                  &TypeTBAAInfo);
+    BaseInfo.mergeForCast(TypeBaseInfo);
+    TBAAInfo = CGF.CGM.mergeTBAAInfoForCast(TBAAInfo, TypeTBAAInfo);
     return Address(CGF.Builder.CreateLoad(BaseLVal.getAddress()), Align);
   }
   return CGF.EmitPointerWithAlignment(Base, &BaseInfo, &TBAAInfo);
@@ -3522,7 +3517,7 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E,
         ResultExprTy, !getLangOpts().isSignedOverflowDefined(),
         /*SignedIndices=*/false, E->getExprLoc());
     BaseInfo = ArrayLV.getBaseInfo();
-    TBAAInfo = CGM.getTBAAAccessInfo(ResultExprTy);
+    TBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, ResultExprTy);
   } else {
     Address Base = emitOMPArraySectionBase(*this, E->getBase(), BaseInfo,
                                            TBAAInfo, BaseTy, ResultExprTy,
@@ -3712,7 +3707,7 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
     QualType fieldType =
       field->getType().withCVRQualifiers(base.getVRQualifiers());
     // TODO: Support TBAA for bit fields.
-    LValueBaseInfo FieldBaseInfo(BaseInfo.getAlignmentSource(), false);
+    LValueBaseInfo FieldBaseInfo(BaseInfo.getAlignmentSource());
     return LValue::MakeBitfield(Addr, Info, fieldType, FieldBaseInfo,
                                 TBAAAccessInfo());
   }
@@ -3723,16 +3718,14 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
   QualType FieldType = field->getType();
   const RecordDecl *rec = field->getParent();
   AlignmentSource BaseAlignSource = BaseInfo.getAlignmentSource();
-  LValueBaseInfo FieldBaseInfo(getFieldAlignmentSource(BaseAlignSource), false);
+  LValueBaseInfo FieldBaseInfo(getFieldAlignmentSource(BaseAlignSource));
   TBAAAccessInfo FieldTBAAInfo;
-  if (BaseInfo.getMayAlias() || rec->hasAttr() ||
-          FieldType->isVectorType()) {
-    FieldBaseInfo.setMayAlias(true);
-    FieldTBAAInfo = CGM.getTBAAMayAliasAccessInfo();
+  if (base.getTBAAInfo().isMayAlias() ||
+          rec->hasAttr() || FieldType->isVectorType()) {
+    FieldTBAAInfo = TBAAAccessInfo::getMayAliasInfo();
   } else if (rec->isUnion()) {
     // TODO: Support TBAA for unions.
-    FieldBaseInfo.setMayAlias(true);
-    FieldTBAAInfo = CGM.getTBAAMayAliasAccessInfo();
+    FieldTBAAInfo = TBAAAccessInfo::getMayAliasInfo();
   } else {
     // If no base type been assigned for the base access, then try to generate
     // one for this base lvalue.
@@ -3818,13 +3811,14 @@ CodeGenFunction::EmitLValueForFieldInitialization(LValue Base,
   llvm::Type *llvmType = ConvertTypeForMem(FieldType);
   V = Builder.CreateElementBitCast(V, llvmType, Field->getName());
 
-  // TODO: access-path TBAA?
+  // TODO: Generate TBAA information that describes this access as a structure
+  // member access and not just an access to an object of the field's type. This
+  // should be similar to what we do in EmitLValueForField().
   LValueBaseInfo BaseInfo = Base.getBaseInfo();
-  LValueBaseInfo FieldBaseInfo(
-      getFieldAlignmentSource(BaseInfo.getAlignmentSource()),
-      BaseInfo.getMayAlias());
+  AlignmentSource FieldAlignSource = BaseInfo.getAlignmentSource();
+  LValueBaseInfo FieldBaseInfo(getFieldAlignmentSource(FieldAlignSource));
   return MakeAddrLValue(V, FieldType, FieldBaseInfo,
-                        CGM.getTBAAAccessInfo(FieldType));
+                        CGM.getTBAAInfoForSubobject(Base, FieldType));
 }
 
 LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){
@@ -3937,11 +3931,10 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
     AlignmentSource alignSource =
       std::max(lhs->getBaseInfo().getAlignmentSource(),
                rhs->getBaseInfo().getAlignmentSource());
-    bool MayAlias = lhs->getBaseInfo().getMayAlias() ||
-                    rhs->getBaseInfo().getMayAlias();
-    return MakeAddrLValue(result, expr->getType(),
-                          LValueBaseInfo(alignSource, MayAlias),
-                          CGM.getTBAAAccessInfo(expr->getType()));
+    TBAAAccessInfo TBAAInfo = CGM.mergeTBAAInfoForConditionalOperator(
+        lhs->getTBAAInfo(), rhs->getTBAAInfo());
+    return MakeAddrLValue(result, expr->getType(), LValueBaseInfo(alignSource),
+                          TBAAInfo);
   } else {
     assert((lhs || rhs) &&
            "both operands of glvalue conditional are throw-expressions?");
@@ -4039,8 +4032,11 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
         This, DerivedClassDecl, E->path_begin(), E->path_end(),
         /*NullCheckValue=*/false, E->getExprLoc());
 
+    // TODO: Support accesses to members of base classes in TBAA. For now, we
+    // conservatively pretend that the complete object is of the base class
+    // type.
     return MakeAddrLValue(Base, E->getType(), LV.getBaseInfo(),
-                          CGM.getTBAAAccessInfo(E->getType()));
+                          CGM.getTBAAInfoForSubobject(LV, E->getType()));
   }
   case CK_ToUnion:
     return EmitAggExprToLValue(E);
@@ -4068,7 +4064,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
                                 CFITCK_DerivedCast, E->getLocStart());
 
     return MakeAddrLValue(Derived, E->getType(), LV.getBaseInfo(),
-                          CGM.getTBAAAccessInfo(E->getType()));
+                          CGM.getTBAAInfoForSubobject(LV, E->getType()));
   }
   case CK_LValueBitCast: {
     // This must be a reinterpret_cast (or c-style equivalent).
@@ -4085,14 +4081,14 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
                                 CFITCK_UnrelatedCast, E->getLocStart());
 
     return MakeAddrLValue(V, E->getType(), LV.getBaseInfo(),
-                          CGM.getTBAAAccessInfo(E->getType()));
+                          CGM.getTBAAInfoForSubobject(LV, E->getType()));
   }
   case CK_ObjCObjectLValueCast: {
     LValue LV = EmitLValue(E->getSubExpr());
     Address V = Builder.CreateElementBitCast(LV.getAddress(),
                                              ConvertType(E->getType()));
     return MakeAddrLValue(V, E->getType(), LV.getBaseInfo(),
-                          CGM.getTBAAAccessInfo(E->getType()));
+                          CGM.getTBAAInfoForSubobject(LV, E->getType()));
   }
   case CK_ZeroToOCLQueue:
     llvm_unreachable("NULL to OpenCL queue lvalue cast is not valid");
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index 74b8698b6d..2f886fd82c 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -110,7 +110,7 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
                                    llvm::Type::getIntNTy(CGF.getLLVMContext(),
                                                          Info->StorageSize));
   return LValue::MakeBitfield(Addr, *Info, IvarTy,
-                              LValueBaseInfo(AlignmentSource::Decl, false),
+                              LValueBaseInfo(AlignmentSource::Decl),
                               TBAAAccessInfo());
 }
 
diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp
index 0a798b8903..35929af95e 100644
--- a/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -993,7 +993,7 @@ void ReductionCodeGen::emitInitialization(
       CGF.Builder.CreateElementBitCast(SharedLVal.getAddress(),
                                        CGF.ConvertTypeForMem(SharedType)),
       SharedType, SharedAddresses[N].first.getBaseInfo(),
-      CGF.CGM.getTBAAAccessInfo(SharedType));
+      CGF.CGM.getTBAAInfoForSubobject(SharedAddresses[N].first, SharedType));
   if (CGF.getContext().getAsArrayType(PrivateVD->getType())) {
     emitAggregateInitialization(CGF, N, PrivateAddr, SharedLVal, DRD);
   } else if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) {
@@ -1046,7 +1046,7 @@ static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
       CGF.Builder.CreateElementBitCast(BaseLV.getAddress(),
                                        CGF.ConvertTypeForMem(ElTy)),
       BaseLV.getType(), BaseLV.getBaseInfo(),
-      CGF.CGM.getTBAAAccessInfo(BaseLV.getType()));
+      CGF.CGM.getTBAAInfoForSubobject(BaseLV, BaseLV.getType()));
 }
 
 static Address castToBase(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy,
@@ -4084,9 +4084,8 @@ static void emitPrivatesInit(CodeGenFunction &CGF,
         SharedRefLValue = CGF.MakeAddrLValue(
             Address(SharedRefLValue.getPointer(), C.getDeclAlign(OriginalVD)),
             SharedRefLValue.getType(),
-            LValueBaseInfo(AlignmentSource::Decl,
-                           SharedRefLValue.getBaseInfo().getMayAlias()),
-            CGF.CGM.getTBAAAccessInfo(SharedRefLValue.getType()));
+            LValueBaseInfo(AlignmentSource::Decl),
+            SharedRefLValue.getTBAAInfo());
         QualType Type = OriginalVD->getType();
         if (Type->isArrayType()) {
           // Initialize firstprivate array.
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index a823ef65b6..7d07ea4516 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -149,20 +149,15 @@ static inline AlignmentSource getFieldAlignmentSource(AlignmentSource Source) {
 
 class LValueBaseInfo {
   AlignmentSource AlignSource;
-  bool MayAlias;
 
 public:
-  explicit LValueBaseInfo(AlignmentSource Source = AlignmentSource::Type,
-                 bool Alias = false)
-    : AlignSource(Source), MayAlias(Alias) {}
+  explicit LValueBaseInfo(AlignmentSource Source = AlignmentSource::Type)
+    : AlignSource(Source) {}
   AlignmentSource getAlignmentSource() const { return AlignSource; }
   void setAlignmentSource(AlignmentSource Source) { AlignSource = Source; }
-  bool getMayAlias() const { return MayAlias; }
-  void setMayAlias(bool Alias) { MayAlias = Alias; }
 
   void mergeForCast(const LValueBaseInfo &Info) {
     setAlignmentSource(Info.getAlignmentSource());
-    setMayAlias(getMayAlias() || Info.getMayAlias());
   }
 };
 
@@ -426,8 +421,7 @@ public:
     R.LVType = GlobalReg;
     R.V = Reg.getPointer();
     R.Initialize(type, type.getQualifiers(), Reg.getAlignment(),
-                 LValueBaseInfo(AlignmentSource::Decl, false),
-                 TBAAAccessInfo());
+                 LValueBaseInfo(AlignmentSource::Decl), TBAAAccessInfo());
     return R;
   }
 
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index b6f8770f51..234d1a2849 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -137,13 +137,13 @@ CharUnits CodeGenFunction::getNaturalTypeAlignment(QualType T,
   if (auto TT = T->getAs()) {
     if (auto Align = TT->getDecl()->getMaxAlignment()) {
       if (BaseInfo)
-        *BaseInfo = LValueBaseInfo(AlignmentSource::AttributedType, false);
+        *BaseInfo = LValueBaseInfo(AlignmentSource::AttributedType);
       return getContext().toCharUnitsFromBits(Align);
     }
   }
 
   if (BaseInfo)
-    *BaseInfo = LValueBaseInfo(AlignmentSource::Type, false);
+    *BaseInfo = LValueBaseInfo(AlignmentSource::Type);
 
   CharUnits Alignment;
   if (T->isIncompleteType()) {
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 2d919876e2..e1034c129d 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1919,8 +1919,7 @@ public:
 
   LValue MakeAddrLValue(Address Addr, QualType T,
                         AlignmentSource Source = AlignmentSource::Type) {
-    return LValue::MakeAddr(Addr, T, getContext(),
-                            LValueBaseInfo(Source, false),
+    return LValue::MakeAddr(Addr, T, getContext(), LValueBaseInfo(Source),
                             CGM.getTBAAAccessInfo(T));
   }
 
@@ -1932,8 +1931,7 @@ public:
   LValue MakeAddrLValue(llvm::Value *V, QualType T, CharUnits Alignment,
                         AlignmentSource Source = AlignmentSource::Type) {
     return LValue::MakeAddr(Address(V, Alignment), T, getContext(),
-                            LValueBaseInfo(Source, false),
-                            CGM.getTBAAAccessInfo(T));
+                            LValueBaseInfo(Source), CGM.getTBAAAccessInfo(T));
   }
 
   LValue MakeAddrLValue(llvm::Value *V, QualType T, CharUnits Alignment,
@@ -3092,8 +3090,7 @@ public:
                                 SourceLocation Loc,
                                 AlignmentSource Source = AlignmentSource::Type,
                                 bool isNontemporal = false) {
-    return EmitLoadOfScalar(Addr, Volatile, Ty, Loc,
-                            LValueBaseInfo(Source, false),
+    return EmitLoadOfScalar(Addr, Volatile, Ty, Loc, LValueBaseInfo(Source),
                             CGM.getTBAAAccessInfo(Ty), isNontemporal);
   }
 
@@ -3115,7 +3112,7 @@ public:
                          bool Volatile, QualType Ty,
                          AlignmentSource Source = AlignmentSource::Type,
                          bool isInit = false, bool isNontemporal = false) {
-    EmitStoreOfScalar(Value, Addr, Volatile, Ty, LValueBaseInfo(Source, false),
+    EmitStoreOfScalar(Value, Addr, Volatile, Ty, LValueBaseInfo(Source),
                       CGM.getTBAAAccessInfo(Ty), isInit, isNontemporal);
   }
 
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 4f7d6eaed6..2254f3e70d 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -606,17 +606,19 @@ llvm::MDNode *CodeGenModule::getTBAAAccessTagInfo(TBAAAccessInfo Info) {
   return TBAA->getAccessTagInfo(Info);
 }
 
-TBAAAccessInfo CodeGenModule::getTBAAMayAliasAccessInfo() {
+TBAAAccessInfo CodeGenModule::mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo,
+                                                   TBAAAccessInfo TargetInfo) {
   if (!TBAA)
     return TBAAAccessInfo();
-  return TBAA->getMayAliasAccessInfo();
+  return TBAA->mergeTBAAInfoForCast(SourceInfo, TargetInfo);
 }
 
-TBAAAccessInfo CodeGenModule::mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo,
-                                                   TBAAAccessInfo TargetInfo) {
+TBAAAccessInfo
+CodeGenModule::mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA,
+                                                   TBAAAccessInfo InfoB) {
   if (!TBAA)
     return TBAAAccessInfo();
-  return TBAA->mergeTBAAInfoForCast(SourceInfo, TargetInfo);
+  return TBAA->mergeTBAAInfoForConditionalOperator(InfoA, InfoB);
 }
 
 void CodeGenModule::DecorateInstructionWithTBAA(llvm::Instruction *Inst,
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index ebc1ec65cf..21bab6cfa0 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -673,15 +673,24 @@ public:
   /// getTBAAAccessTagInfo - Get TBAA tag for a given memory access.
   llvm::MDNode *getTBAAAccessTagInfo(TBAAAccessInfo Info);
 
-  /// getTBAAMayAliasAccessInfo - Get TBAA information that represents
-  /// may-alias accesses.
-  TBAAAccessInfo getTBAAMayAliasAccessInfo();
-
   /// mergeTBAAInfoForCast - Get merged TBAA information for the purposes of
   /// type casts.
   TBAAAccessInfo mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo,
                                       TBAAAccessInfo TargetInfo);
 
+  /// mergeTBAAInfoForConditionalOperator - Get merged TBAA information for the
+  /// purposes of conditional operator.
+  TBAAAccessInfo mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA,
+                                                     TBAAAccessInfo InfoB);
+
+  /// getTBAAInfoForSubobject - Get TBAA information for an access with a given
+  /// base lvalue.
+  TBAAAccessInfo getTBAAInfoForSubobject(LValue Base, QualType AccessType) {
+    if (Base.getTBAAInfo().isMayAlias())
+      return TBAAAccessInfo::getMayAliasInfo();
+    return getTBAAAccessInfo(AccessType);
+  }
+
   bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor);
 
   bool isPaddedAtomicType(QualType type);
diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp
index 6f9747e2f0..66fdb5f799 100644
--- a/lib/CodeGen/CodeGenTBAA.cpp
+++ b/lib/CodeGen/CodeGenTBAA.cpp
@@ -88,6 +88,25 @@ static bool TypeHasMayAlias(QualType QTy) {
   return false;
 }
 
+/// Check if the given type is a valid base type to be used in access tags.
+static bool isValidBaseType(QualType QTy) {
+  if (QTy->isReferenceType())
+    return false;
+  if (const RecordType *TTy = QTy->getAs()) {
+    const RecordDecl *RD = TTy->getDecl()->getDefinition();
+    // Incomplete types are not valid base access types.
+    if (!RD)
+      return false;
+    if (RD->hasFlexibleArrayMember())
+      return false;
+    // RD can be struct, union, class, interface or enum.
+    // For now, we only handle struct and class.
+    if (RD->isStruct() || RD->isClass())
+      return true;
+  }
+  return false;
+}
+
 llvm::MDNode *CodeGenTBAA::getTypeInfo(QualType QTy) {
   // At -O0 or relaxed aliasing, TBAA is not emitted for regular types.
   if (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing)
@@ -98,8 +117,16 @@ llvm::MDNode *CodeGenTBAA::getTypeInfo(QualType QTy) {
   if (TypeHasMayAlias(QTy))
     return getChar();
 
-  const Type *Ty = Context.getCanonicalType(QTy).getTypePtr();
+  // We need this function to not fall back to returning the "omnipotent char"
+  // type node for aggregate and union types. Otherwise, any dereference of an
+  // aggregate will result into the may-alias access descriptor, meaning all
+  // subsequent accesses to direct and indirect members of that aggregate will
+  // be considered may-alias too.
+  // TODO: Combine getTypeInfo() and getBaseTypeInfo() into a single function.
+  if (isValidBaseType(QTy))
+    return getBaseTypeInfo(QTy);
 
+  const Type *Ty = Context.getCanonicalType(QTy).getTypePtr();
   if (llvm::MDNode *N = MetadataCache[Ty])
     return N;
 
@@ -232,20 +259,6 @@ CodeGenTBAA::getTBAAStructInfo(QualType QTy) {
   return StructMetadataCache[Ty] = nullptr;
 }
 
-/// Check if the given type is a valid base type to be used in access tags.
-static bool isValidBaseType(QualType QTy) {
-  if (const RecordType *TTy = QTy->getAs()) {
-    const RecordDecl *RD = TTy->getDecl()->getDefinition();
-    if (RD->hasFlexibleArrayMember())
-      return false;
-    // RD can be struct, union, class, interface or enum.
-    // For now, we only handle struct and class.
-    if (RD->isStruct() || RD->isClass())
-      return true;
-  }
-  return false;
-}
-
 llvm::MDNode *CodeGenTBAA::getBaseTypeInfo(QualType QTy) {
   if (!isValidBaseType(QTy))
     return nullptr;
@@ -288,6 +301,9 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfo(QualType QTy) {
 }
 
 llvm::MDNode *CodeGenTBAA::getAccessTagInfo(TBAAAccessInfo Info) {
+  if (Info.isMayAlias())
+    Info = TBAAAccessInfo(getChar());
+
   if (!Info.AccessType)
     return nullptr;
 
@@ -306,14 +322,27 @@ llvm::MDNode *CodeGenTBAA::getAccessTagInfo(TBAAAccessInfo Info) {
                                               Info.Offset);
 }
 
-TBAAAccessInfo CodeGenTBAA::getMayAliasAccessInfo() {
-  return TBAAAccessInfo(getChar());
-}
-
 TBAAAccessInfo CodeGenTBAA::mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo,
                                                  TBAAAccessInfo TargetInfo) {
-  TBAAAccessInfo MayAliasInfo = getMayAliasAccessInfo();
-  if (SourceInfo == MayAliasInfo || TargetInfo == MayAliasInfo)
-    return MayAliasInfo;
+  if (SourceInfo.isMayAlias() || TargetInfo.isMayAlias())
+    return TBAAAccessInfo::getMayAliasInfo();
   return TargetInfo;
 }
+
+TBAAAccessInfo
+CodeGenTBAA::mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA,
+                                                 TBAAAccessInfo InfoB) {
+  if (InfoA == InfoB)
+    return InfoA;
+
+  if (!InfoA || !InfoB)
+    return TBAAAccessInfo();
+
+  if (InfoA.isMayAlias() || InfoB.isMayAlias())
+    return TBAAAccessInfo::getMayAliasInfo();
+
+  // TODO: Implement the rest of the logic here. For example, two accesses
+  // with same final access types result in an access to an object of that final
+  // access type regardless of their base types.
+  return TBAAAccessInfo::getMayAliasInfo();
+}
diff --git a/lib/CodeGen/CodeGenTBAA.h b/lib/CodeGen/CodeGenTBAA.h
index 7f499daf9d..e4f459ce93 100644
--- a/lib/CodeGen/CodeGenTBAA.h
+++ b/lib/CodeGen/CodeGenTBAA.h
@@ -32,11 +32,22 @@ namespace clang {
 namespace CodeGen {
 class CGRecordLayout;
 
+// TBAAAccessKind - A kind of TBAA memory access descriptor.
+enum class TBAAAccessKind : unsigned {
+  Ordinary,
+  MayAlias,
+};
+
 // TBAAAccessInfo - Describes a memory access in terms of TBAA.
 struct TBAAAccessInfo {
+  TBAAAccessInfo(TBAAAccessKind Kind, llvm::MDNode *BaseType,
+                 llvm::MDNode *AccessType, uint64_t Offset)
+    : Kind(Kind), BaseType(BaseType), AccessType(AccessType), Offset(Offset)
+  {}
+
   TBAAAccessInfo(llvm::MDNode *BaseType, llvm::MDNode *AccessType,
                  uint64_t Offset)
-    : BaseType(BaseType), AccessType(AccessType), Offset(Offset)
+    : TBAAAccessInfo(TBAAAccessKind::Ordinary, BaseType, AccessType, Offset)
   {}
 
   explicit TBAAAccessInfo(llvm::MDNode *AccessType)
@@ -47,12 +58,31 @@ struct TBAAAccessInfo {
     : TBAAAccessInfo(/* AccessType= */ nullptr)
   {}
 
+  static TBAAAccessInfo getMayAliasInfo() {
+    return TBAAAccessInfo(TBAAAccessKind::MayAlias, /* BaseType= */ nullptr,
+                          /* AccessType= */ nullptr, /* Offset= */ 0);
+  }
+
+  bool isMayAlias() const { return Kind == TBAAAccessKind::MayAlias; }
+
   bool operator==(const TBAAAccessInfo &Other) const {
-    return BaseType == Other.BaseType &&
+    return Kind == Other.Kind &&
+           BaseType == Other.BaseType &&
            AccessType == Other.AccessType &&
            Offset == Other.Offset;
   }
 
+  bool operator!=(const TBAAAccessInfo &Other) const {
+    return !(*this == Other);
+  }
+
+  explicit operator bool() const {
+    return *this != TBAAAccessInfo();
+  }
+
+  /// Kind - The kind of the access descriptor.
+  TBAAAccessKind Kind;
+
   /// BaseType - The base/leading access type. May be null if this access
   /// descriptor represents an access that is not considered to be an access
   /// to an aggregate or union member.
@@ -139,14 +169,15 @@ public:
   /// getAccessTagInfo - Get TBAA tag for a given memory access.
   llvm::MDNode *getAccessTagInfo(TBAAAccessInfo Info);
 
-  /// getMayAliasAccessInfo - Get TBAA information that represents may-alias
-  /// accesses.
-  TBAAAccessInfo getMayAliasAccessInfo();
-
   /// mergeTBAAInfoForCast - Get merged TBAA information for the purpose of
   /// type casts.
   TBAAAccessInfo mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo,
                                       TBAAAccessInfo TargetInfo);
+
+  /// mergeTBAAInfoForConditionalOperator - Get merged TBAA information for the
+  /// purpose of conditional operator.
+  TBAAAccessInfo mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA,
+                                                     TBAAAccessInfo InfoB);
 };
 
 }  // end namespace CodeGen
@@ -156,30 +187,34 @@ namespace llvm {
 
 template<> struct DenseMapInfo {
   static clang::CodeGen::TBAAAccessInfo getEmptyKey() {
+    unsigned UnsignedKey = DenseMapInfo::getEmptyKey();
     return clang::CodeGen::TBAAAccessInfo(
+      static_cast(UnsignedKey),
       DenseMapInfo::getEmptyKey(),
       DenseMapInfo::getEmptyKey(),
       DenseMapInfo::getEmptyKey());
   }
 
   static clang::CodeGen::TBAAAccessInfo getTombstoneKey() {
+    unsigned UnsignedKey = DenseMapInfo::getTombstoneKey();
     return clang::CodeGen::TBAAAccessInfo(
+      static_cast(UnsignedKey),
       DenseMapInfo::getTombstoneKey(),
       DenseMapInfo::getTombstoneKey(),
       DenseMapInfo::getTombstoneKey());
   }
 
   static unsigned getHashValue(const clang::CodeGen::TBAAAccessInfo &Val) {
-    return DenseMapInfo::getHashValue(Val.BaseType) ^
+    auto KindValue = static_cast(Val.Kind);
+    return DenseMapInfo::getHashValue(KindValue) ^
+           DenseMapInfo::getHashValue(Val.BaseType) ^
            DenseMapInfo::getHashValue(Val.AccessType) ^
            DenseMapInfo::getHashValue(Val.Offset);
   }
 
   static bool isEqual(const clang::CodeGen::TBAAAccessInfo &LHS,
                       const clang::CodeGen::TBAAAccessInfo &RHS) {
-    return LHS.BaseType == RHS.BaseType &&
-           LHS.AccessType == RHS.AccessType &&
-           LHS.Offset == RHS.Offset;
+    return LHS == RHS;
   }
 };
 
-- 
GitLab


From 7f519c8361480c7e2951b82e666eb5ccd316da01 Mon Sep 17 00:00:00 2001
From: Sanjay Patel 
Date: Tue, 31 Oct 2017 20:19:39 +0000
Subject: [PATCH 0148/1682] [CodeGen] map sqrt libcalls to llvm.sqrt when errno
 is not set

The LLVM sqrt intrinsic definition changed with:
D28797
...so we don't have to use any relaxed FP settings other than errno handling.

This patch sidesteps a question raised in PR27435:
https://bugs.llvm.org/show_bug.cgi?id=27435

Is a programmer using __builtin_sqrt() invoking the compiler's intrinsic definition of sqrt or the mathlib definition of sqrt?

But we have an answer now: the builtin should match the behavior of the libm function including errno handling.

Differential Revision: https://reviews.llvm.org/D39204


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317031 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/CodeGen/CGBuiltin.cpp             | 29 ++++++++++++---------------
 test/CodeGen/2005-07-20-SqrtNoErrno.c | 10 ---------
 test/CodeGen/builtin-sqrt.c           | 19 ++++++++++++++++++
 test/CodeGen/libcalls.c               | 25 +++++++++++------------
 4 files changed, 44 insertions(+), 39 deletions(-)
 delete mode 100644 test/CodeGen/2005-07-20-SqrtNoErrno.c
 create mode 100644 test/CodeGen/builtin-sqrt.c

diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 1de7c6e17d..bc37afa284 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -2072,24 +2072,21 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
     return RValue::get(nullptr);
   }
 
-    // Library functions with special handling.
   case Builtin::BIsqrt:
   case Builtin::BIsqrtf:
-  case Builtin::BIsqrtl: {
-    // Transform a call to sqrt* into a @llvm.sqrt.* intrinsic call, but only
-    // in finite- or unsafe-math mode (the intrinsic has different semantics
-    // for handling negative numbers compared to the library function, so
-    // -fmath-errno=0 is not enough).
-    if (!FD->hasAttr())
-      break;
-    if (!(CGM.getCodeGenOpts().UnsafeFPMath ||
-          CGM.getCodeGenOpts().NoNaNsFPMath))
-      break;
-    Value *Arg0 = EmitScalarExpr(E->getArg(0));
-    llvm::Type *ArgType = Arg0->getType();
-    Value *F = CGM.getIntrinsic(Intrinsic::sqrt, ArgType);
-    return RValue::get(Builder.CreateCall(F, Arg0));
-  }
+  case Builtin::BIsqrtl:
+    // Builtins have the same semantics as library functions. The LLVM intrinsic
+    // has the same semantics as the library function except it does not set
+    // errno. Thus, we can transform either sqrt or __builtin_sqrt to @llvm.sqrt
+    // if the call is 'const' (the call must not set errno).
+    //
+    // FIXME: The builtin cases are not here because they are marked 'const' in
+    // Builtins.def. So that means they are wrongly defined to have different
+    // semantics than the library functions. If we included them here, we would
+    // turn them into LLVM intrinsics regardless of whether -fmath-errno was on.
+    if (FD->hasAttr())
+      return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sqrt));
+    break;
 
   case Builtin::BI__builtin_pow:
   case Builtin::BI__builtin_powf:
diff --git a/test/CodeGen/2005-07-20-SqrtNoErrno.c b/test/CodeGen/2005-07-20-SqrtNoErrno.c
deleted file mode 100644
index 96761e4cfb..0000000000
--- a/test/CodeGen/2005-07-20-SqrtNoErrno.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s
-// llvm.sqrt has undefined behavior on negative inputs, so it is
-// inappropriate to translate C/C++ sqrt to this.
-float sqrtf(float x);
-float foo(float X) {
-  // CHECK: foo
-  // CHECK: call float @sqrtf(float %
-  // Check that this is marked readonly when errno is ignored.
-  return sqrtf(X);
-}
diff --git a/test/CodeGen/builtin-sqrt.c b/test/CodeGen/builtin-sqrt.c
new file mode 100644
index 0000000000..f93c5926d5
--- /dev/null
+++ b/test/CodeGen/builtin-sqrt.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fmath-errno -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s --check-prefix=HAS_ERRNO
+// RUN: %clang_cc1              -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s --check-prefix=NO_ERRNO
+
+// FIXME: If a builtin is supposed to have identical semantics to its libm twin, then it
+// should not be marked "constant" in Builtins.def because that means it can't set errno.
+// Note that both runs have 'readnone' on the libcall here.
+
+float foo(float X) {
+  // HAS_ERRNO: call float @sqrtf(float
+  // NO_ERRNO: call float @sqrtf(float
+  return __builtin_sqrtf(X);
+}
+
+// HAS_ERRNO: declare float @sqrtf(float) [[ATTR:#[0-9]+]]
+// HAS_ERRNO: attributes [[ATTR]] = { nounwind readnone {{.*}}}
+
+// NO_ERRNO: declare float @sqrtf(float) [[ATTR:#[0-9]+]]
+// NO_ERRNO: attributes [[ATTR]] = { nounwind readnone {{.*}}}
+
diff --git a/test/CodeGen/libcalls.c b/test/CodeGen/libcalls.c
index 3a8207b2be..0a1bcc605c 100644
--- a/test/CodeGen/libcalls.c
+++ b/test/CodeGen/libcalls.c
@@ -6,29 +6,28 @@
 // CHECK-NO-LABEL: define void @test_sqrt
 // CHECK-FAST-LABEL: define void @test_sqrt
 void test_sqrt(float a0, double a1, long double a2) {
-  // Following llvm-gcc's lead, we never emit these as intrinsics;
-  // no-math-errno isn't good enough.  We could probably use intrinsics
-  // with appropriate guards if it proves worthwhile.
-
   // CHECK-YES: call float @sqrtf
-  // CHECK-NO: call float @sqrtf
+  // CHECK-NO: call float @llvm.sqrt.f32(float
+  // CHECK-FAST: call float @llvm.sqrt.f32(float
   float l0 = sqrtf(a0);
 
   // CHECK-YES: call double @sqrt
-  // CHECK-NO: call double @sqrt
+  // CHECK-NO: call double @llvm.sqrt.f64(double
+  // CHECK-FAST: call double @llvm.sqrt.f64(double
   double l1 = sqrt(a1);
 
   // CHECK-YES: call x86_fp80 @sqrtl
-  // CHECK-NO: call x86_fp80 @sqrtl
+  // CHECK-NO: call x86_fp80 @llvm.sqrt.f80(x86_fp80
+  // CHECK-FAST: call x86_fp80 @llvm.sqrt.f80(x86_fp80
   long double l2 = sqrtl(a2);
 }
 
 // CHECK-YES: declare float @sqrtf(float)
 // CHECK-YES: declare double @sqrt(double)
 // CHECK-YES: declare x86_fp80 @sqrtl(x86_fp80)
-// CHECK-NO: declare float @sqrtf(float) [[NUW_RN:#[0-9]+]]
-// CHECK-NO: declare double @sqrt(double) [[NUW_RN]]
-// CHECK-NO: declare x86_fp80 @sqrtl(x86_fp80) [[NUW_RN]]
+// CHECK-NO: declare float @llvm.sqrt.f32(float)
+// CHECK-NO: declare double @llvm.sqrt.f64(double)
+// CHECK-NO: declare x86_fp80 @llvm.sqrt.f80(x86_fp80)
 // CHECK-FAST: declare float @llvm.sqrt.f32(float)
 // CHECK-FAST: declare double @llvm.sqrt.f64(double)
 // CHECK-FAST: declare x86_fp80 @llvm.sqrt.f80(x86_fp80)
@@ -86,7 +85,7 @@ void test_builtins(double d, float f, long double ld) {
   double atan_ = atan(d);
   long double atanl_ = atanl(ld);
   float atanf_ = atanf(f);
-// CHECK-NO: declare double @atan(double) [[NUW_RN]]
+// CHECK-NO: declare double @atan(double) [[NUW_RN:#[0-9]+]]
 // CHECK-NO: declare x86_fp80 @atanl(x86_fp80) [[NUW_RN]]
 // CHECK-NO: declare float @atanf(float) [[NUW_RN]]
 // CHECK-YES-NOT: declare double @atan(double) [[NUW_RN]]
@@ -126,5 +125,5 @@ void test_builtins(double d, float f, long double ld) {
 
 // CHECK-YES: attributes [[NUW_RN]] = { nounwind readnone speculatable }
 
-// CHECK-NO: attributes [[NUW_RN]] = { nounwind readnone{{.*}} }
-// CHECK-NO: attributes [[NUW_RNI]] = { nounwind readnone speculatable }
+// CHECK-NO-DAG: attributes [[NUW_RN]] = { nounwind readnone{{.*}} }
+// CHECK-NO-DAG: attributes [[NUW_RNI]] = { nounwind readnone speculatable }
-- 
GitLab


From daf2537d16dfc1b82c1f183182f4363c410d9d8e Mon Sep 17 00:00:00 2001
From: Richard Smith 
Date: Tue, 31 Oct 2017 20:29:22 +0000
Subject: [PATCH 0149/1682] Fix usage of right shift operator in fold
 expressions

The right shift operator was not seen as a valid operator in a fold expression, which is PR32563.

Patch by Nicolas Lesser ("Blitz Rakete")!


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317032 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Parse/Parser.h           |  6 ++++++
 lib/Parse/ParseExpr.cpp                |  7 ++++---
 test/Parser/cxx1z-fold-expressions.cpp | 17 +++++++++++++++++
 3 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index a2eef247de..ce60cbb431 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -506,6 +506,12 @@ private:
            Kind == tok::annot_module_end || Kind == tok::annot_module_include;
   }
 
+  /// \brief Checks if the \p Level is valid for use in a fold expression.
+  bool isFoldOperator(prec::Level Level) const;
+
+  /// \brief Checks if the \p Kind is a valid operator for fold expressions.
+  bool isFoldOperator(tok::TokenKind Kind) const;
+
   /// \brief Initialize all pragma handlers.
   void initializePragmaHandlers();
 
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index bff6d9cc19..0f2ec6b1c1 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -266,11 +266,12 @@ bool Parser::diagnoseUnknownTemplateId(ExprResult LHS, SourceLocation Less) {
   return false;
 }
 
-static bool isFoldOperator(prec::Level Level) {
+bool Parser::isFoldOperator(prec::Level Level) const {
   return Level > prec::Unknown && Level != prec::Conditional;
 }
-static bool isFoldOperator(tok::TokenKind Kind) {
-  return isFoldOperator(getBinOpPrecedence(Kind, false, true));
+
+bool Parser::isFoldOperator(tok::TokenKind Kind) const {
+  return isFoldOperator(getBinOpPrecedence(Kind, GreaterThanIsOperator, true));
 }
 
 /// \brief Parse a binary expression that starts with \p LHS and has a
diff --git a/test/Parser/cxx1z-fold-expressions.cpp b/test/Parser/cxx1z-fold-expressions.cpp
index b1f7318e41..342f11555f 100644
--- a/test/Parser/cxx1z-fold-expressions.cpp
+++ b/test/Parser/cxx1z-fold-expressions.cpp
@@ -43,3 +43,20 @@ template void as_operand_of_cast(int a, T ...t) {
     (int)(undeclared_junk + ...) + // expected-error {{undeclared}}
     (int)(a + ...); // expected-error {{does not contain any unexpanded}}
 }
+
+// fold-operator can be '>' or '>>'.
+template  constexpr bool greaterThan() { return (N > ...); }
+template  constexpr int rightShift() { return (N >> ...); }
+
+static_assert(greaterThan<2, 1>());
+static_assert(rightShift<10, 1>() == 5);
+
+template  constexpr auto Identity = V;
+
+// Support fold operators within templates.
+template  constexpr int nestedFoldOperator() {
+  return Identity<(Identity<0> >> ... >> N)> +
+    Identity<(N >> ... >> Identity<0>)>;
+}
+
+static_assert(nestedFoldOperator<3, 1>() == 1);
-- 
GitLab


From a934273b7cd28c48745e4c5a122ca3a505ab2028 Mon Sep 17 00:00:00 2001
From: Vitaly Buka 
Date: Tue, 31 Oct 2017 20:49:57 +0000
Subject: [PATCH 0150/1682] [clang-fuzzer] Fix incremental builds of the fuzzer

Summary:
Don't use BUILD_IN_SOURCE keep git checkout clean
Don't forward CMAKE_GENERATOR as ExternalProject_Add should do it already
Reset UPDATE_COMMAND to avoid git checkout updates on each build

Reviewers: kcc, morehouse

Subscribers: cfe-commits, mgorny

Differential Revision: https://reviews.llvm.org/D39445

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317035 91177308-0d34-0410-b5e6-96231b3b80d8
---
 cmake/modules/ProtobufMutator.cmake | 17 ++++++-----------
 1 file changed, 6 insertions(+), 11 deletions(-)

diff --git a/cmake/modules/ProtobufMutator.cmake b/cmake/modules/ProtobufMutator.cmake
index be457b5d3a..5f23f33f4c 100644
--- a/cmake/modules/ProtobufMutator.cmake
+++ b/cmake/modules/ProtobufMutator.cmake
@@ -1,23 +1,18 @@
 set(PBM_PREFIX protobuf_mutator)
 set(PBM_PATH ${CMAKE_CURRENT_BINARY_DIR}/${PBM_PREFIX}/src/${PBM_PREFIX})
-set(PBM_LIB_PATH ${PBM_PATH}/src/libprotobuf-mutator.a)
-set(PBM_FUZZ_LIB_PATH ${PBM_PATH}/src/libfuzzer/libprotobuf-mutator-libfuzzer.a)
+set(PBM_LIB_PATH ${PBM_PATH}-build/src/libprotobuf-mutator.a)
+set(PBM_FUZZ_LIB_PATH ${PBM_PATH}-build/src/libfuzzer/libprotobuf-mutator-libfuzzer.a)
 
 ExternalProject_Add(${PBM_PREFIX}
   PREFIX ${PBM_PREFIX}
   GIT_REPOSITORY https://github.com/google/libprotobuf-mutator.git
   GIT_TAG master
-  CONFIGURE_COMMAND ${CMAKE_COMMAND} -G${CMAKE_GENERATOR}
-    -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
-    -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-    -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-  BUILD_COMMAND ${CMAKE_MAKE_PROGRAM}
+  CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+  CMAKE_CACHE_ARGS -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}
+                   -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}
   BUILD_BYPRODUCTS ${PBM_LIB_PATH} ${PBM_FUZZ_LIB_PATH}
-  BUILD_IN_SOURCE 1
+  UPDATE_COMMAND ""
   INSTALL_COMMAND ""
-  LOG_DOWNLOAD 1
-  LOG_CONFIGURE 1
-  LOG_BUILD 1
   )
 
 set(ProtobufMutator_INCLUDE_DIRS ${PBM_PATH})
-- 
GitLab


From 746fd88cc65883572b7602dc7b1f9e74462fd451 Mon Sep 17 00:00:00 2001
From: Vlad Tsyrklevich 
Date: Tue, 31 Oct 2017 22:39:44 +0000
Subject: [PATCH 0151/1682] [CFI] Add CFI-icall pointer type generalization

Summary:
This change allows generalizing pointers in type signatures used for
cfi-icall by enabling the -fsanitize-cfi-icall-generalize-pointers flag.
This works by 1) emitting an additional generalized type signature
metadata node for functions and 2) llvm.type.test()ing for the
generalized type for translation units with the flag specified.

This flag is incompatible with -fsanitize-cfi-cross-dso because it would
require emitting twice as many type hashes which would increase artifact
size.

Reviewers: pcc, eugenis

Reviewed By: pcc

Subscribers: kcc

Differential Revision: https://reviews.llvm.org/D39358

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317044 91177308-0d34-0410-b5e6-96231b3b80d8
---
 docs/ClangCommandLineReference.rst        |  4 ++
 docs/ControlFlowIntegrity.rst             | 17 +++++++
 docs/UsersManual.rst                      |  5 +++
 include/clang/Driver/Options.td           |  3 ++
 include/clang/Driver/SanitizerArgs.h      |  1 +
 include/clang/Frontend/CodeGenOptions.def |  2 +
 lib/CodeGen/CGExpr.cpp                    |  7 ++-
 lib/CodeGen/CodeGenModule.cpp             | 55 +++++++++++++++++++++++
 lib/CodeGen/CodeGenModule.h               |  9 +++-
 lib/Driver/SanitizerArgs.cpp              | 10 +++++
 lib/Frontend/CompilerInvocation.cpp       |  2 +
 test/CodeGen/cfi-icall-cross-dso.c        | 10 +++--
 test/CodeGen/cfi-icall-generalize.c       | 19 ++++++++
 test/CodeGen/cfi-icall.c                  | 10 +++--
 test/CodeGenCXX/cfi-icall.cpp             | 19 ++++----
 test/Driver/fsanitize.c                   |  8 ++++
 16 files changed, 165 insertions(+), 16 deletions(-)
 create mode 100644 test/CodeGen/cfi-icall-generalize.c

diff --git a/docs/ClangCommandLineReference.rst b/docs/ClangCommandLineReference.rst
index 0cc9c71ebe..0a0fce9190 100644
--- a/docs/ClangCommandLineReference.rst
+++ b/docs/ClangCommandLineReference.rst
@@ -740,6 +740,10 @@ Path to blacklist file for sanitizers
 
 Enable control flow integrity (CFI) checks for cross-DSO calls.
 
+.. option:: -fsanitize-cfi-icall-generalize-pointers
+
+Generalize pointers in function type signatures used for Control Flow Integrity (CFI) indirect call checking
+
 .. option:: -fsanitize-coverage=,..., -fno-sanitize-coverage=,...
 
 Specify the type of coverage instrumentation for Sanitizers
diff --git a/docs/ControlFlowIntegrity.rst b/docs/ControlFlowIntegrity.rst
index 04fb43a70f..12b4610f8a 100644
--- a/docs/ControlFlowIntegrity.rst
+++ b/docs/ControlFlowIntegrity.rst
@@ -215,6 +215,23 @@ shared library boundaries are handled as if the callee was not compiled with
 
 This scheme is currently only supported on the x86 and x86_64 architectures.
 
+``-fsanitize-cfi-icall-generalize-pointers``
+--------------------------------------------
+
+Mismatched pointer types are a common cause of cfi-icall check failures.
+Translation units compiled with the ``-fsanitize-cfi-icall-generalize-pointers``
+flag relax pointer type checking for call sites in that translation unit,
+applied across all functions compiled with ``-fsanitize=cfi-icall``.
+
+Specifically, pointers in return and argument types are treated as equivalent as
+long as the qualifiers for the type they point to match. For example, ``char*``
+``char**`, and ``int*`` are considered equivalent types. However, ``char*`` and
+``const char*`` are considered separate types.
+
+``-fsanitize-cfi-icall-generalize-pointers`` is not compatible with
+``-fsanitize-cfi-cross-dso``.
+
+
 ``-fsanitize=cfi-icall`` and ``-fsanitize=function``
 ----------------------------------------------------
 
diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst
index 2757ced1c2..023f9f5528 100644
--- a/docs/UsersManual.rst
+++ b/docs/UsersManual.rst
@@ -1147,6 +1147,11 @@ are listed below.
    the behavior of sanitizers in the ``cfi`` group to allow checking
    of cross-DSO virtual and indirect calls.
 
+.. option:: -fsanitize-cfi-icall-generalize-pointers
+
+   Generalize pointers in return and argument types in function type signatures
+   checked by Control Flow Integrity indirect call checking. See
+   :doc:`ControlFlowIntegrity` for more details.
 
 .. option:: -fstrict-vtable-pointers
 
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index eef0eca713..e3476c721a 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -914,6 +914,9 @@ def fno_sanitize_cfi_cross_dso : Flag<["-"], "fno-sanitize-cfi-cross-dso">,
                                  Flags<[CoreOption, DriverOption]>,
                                  Group,
                                  HelpText<"Disable control flow integrity (CFI) checks for cross-DSO calls.">;
+def fsanitize_cfi_icall_generalize_pointers : Flag<["-"], "fsanitize-cfi-icall-generalize-pointers">,
+                                              Group,
+                                              HelpText<"Generalize pointers in CFI indirect call type signature checks">;
 def fsanitize_stats : Flag<["-"], "fsanitize-stats">,
                               Group,
                               HelpText<"Enable sanitizer statistics gathering.">;
diff --git a/include/clang/Driver/SanitizerArgs.h b/include/clang/Driver/SanitizerArgs.h
index 52b6698857..19309c3f3b 100644
--- a/include/clang/Driver/SanitizerArgs.h
+++ b/include/clang/Driver/SanitizerArgs.h
@@ -32,6 +32,7 @@ class SanitizerArgs {
   int MsanTrackOrigins = 0;
   bool MsanUseAfterDtor = false;
   bool CfiCrossDso = false;
+  bool CfiICallGeneralizePointers = false;
   int AsanFieldPadding = 0;
   bool SharedRuntime = false;
   bool AsanUseAfterScope = true;
diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def
index 8cac8e45c8..8f2aae2f14 100644
--- a/include/clang/Frontend/CodeGenOptions.def
+++ b/include/clang/Frontend/CodeGenOptions.def
@@ -154,6 +154,8 @@ CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0) ///< Enable use-after-delete detect
 CODEGENOPT(SanitizeCfiCrossDso, 1, 0) ///< Enable cross-dso support in CFI.
 CODEGENOPT(SanitizeMinimalRuntime, 1, 0) ///< Use "_minimal" sanitizer runtime for
                                          ///< diagnostics.
+CODEGENOPT(SanitizeCfiICallGeneralizePointers, 1, 0) ///< Generalize pointer types in
+                                                     ///< CFI icall function signatures
 CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage
                                        ///< instrumentation.
 CODEGENOPT(SanitizeCoverageIndirectCalls, 1, 0) ///< Enable sanitizer coverage
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index d3b03e556f..88116f7d81 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -4475,7 +4475,12 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee
     SanitizerScope SanScope(this);
     EmitSanitizerStatReport(llvm::SanStat_CFI_ICall);
 
-    llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(QualType(FnType, 0));
+    llvm::Metadata *MD;
+    if (CGM.getCodeGenOpts().SanitizeCfiICallGeneralizePointers)
+      MD = CGM.CreateMetadataIdentifierGeneralized(QualType(FnType, 0));
+    else
+      MD = CGM.CreateMetadataIdentifierForType(QualType(FnType, 0));
+
     llvm::Value *TypeId = llvm::MetadataAsValue::get(getLLVMContext(), MD);
 
     llvm::Value *CalleePtr = Callee.getFunctionPointer();
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 2254f3e70d..b2a18a03f2 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -1152,6 +1152,7 @@ void CodeGenModule::CreateFunctionTypeMetadata(const FunctionDecl *FD,
 
   llvm::Metadata *MD = CreateMetadataIdentifierForType(FD->getType());
   F->addTypeMetadata(0, MD);
+  F->addTypeMetadata(0, CreateMetadataIdentifierGeneralized(FD->getType()));
 
   // Emit a hash-based bit set entry for cross-DSO calls.
   if (CodeGenOpts.SanitizeCfiCrossDso)
@@ -4543,6 +4544,60 @@ llvm::Metadata *CodeGenModule::CreateMetadataIdentifierForType(QualType T) {
   return InternalId;
 }
 
+// Generalize pointer types to a void pointer with the qualifiers of the
+// originally pointed-to type, e.g. 'const char *' and 'char * const *'
+// generalize to 'const void *' while 'char *' and 'const char **' generalize to
+// 'void *'.
+static QualType GeneralizeType(ASTContext &Ctx, QualType Ty) {
+  if (!Ty->isPointerType())
+    return Ty;
+
+  return Ctx.getPointerType(
+      QualType(Ctx.VoidTy).withCVRQualifiers(
+          Ty->getPointeeType().getCVRQualifiers()));
+}
+
+// Apply type generalization to a FunctionType's return and argument types
+static QualType GeneralizeFunctionType(ASTContext &Ctx, QualType Ty) {
+  if (auto *FnType = Ty->getAs()) {
+    SmallVector GeneralizedParams;
+    for (auto &Param : FnType->param_types())
+      GeneralizedParams.push_back(GeneralizeType(Ctx, Param));
+
+    return Ctx.getFunctionType(
+        GeneralizeType(Ctx, FnType->getReturnType()),
+        GeneralizedParams, FnType->getExtProtoInfo());
+  }
+
+  if (auto *FnType = Ty->getAs())
+    return Ctx.getFunctionNoProtoType(
+        GeneralizeType(Ctx, FnType->getReturnType()));
+
+  llvm_unreachable("Encountered unknown FunctionType");
+}
+
+llvm::Metadata *CodeGenModule::CreateMetadataIdentifierGeneralized(QualType T) {
+  T = GeneralizeFunctionType(getContext(), T);
+
+  llvm::Metadata *&InternalId = GeneralizedMetadataIdMap[T.getCanonicalType()];
+  if (InternalId)
+    return InternalId;
+
+  if (isExternallyVisible(T->getLinkage())) {
+    std::string OutName;
+    llvm::raw_string_ostream Out(OutName);
+    getCXXABI().getMangleContext().mangleTypeName(T, Out);
+    Out << ".generalized";
+
+    InternalId = llvm::MDString::get(getLLVMContext(), Out.str());
+  } else {
+    InternalId = llvm::MDNode::getDistinct(getLLVMContext(),
+                                           llvm::ArrayRef());
+  }
+
+  return InternalId;
+}
+
 /// Returns whether this module needs the "all-vtables" type identifier.
 bool CodeGenModule::NeedAllVtablesTypeId() const {
   // Returns true if at least one of vtable-based CFI checkers is enabled and
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 21bab6cfa0..7a47c576c0 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -497,7 +497,9 @@ private:
   /// Mapping from canonical types to their metadata identifiers. We need to
   /// maintain this mapping because identifiers may be formed from distinct
   /// MDNodes.
-  llvm::DenseMap MetadataIdMap;
+  typedef llvm::DenseMap MetadataTypeMap;
+  MetadataTypeMap MetadataIdMap;
+  MetadataTypeMap GeneralizedMetadataIdMap;
 
 public:
   CodeGenModule(ASTContext &C, const HeaderSearchOptions &headersearchopts,
@@ -1209,6 +1211,11 @@ public:
   /// internal identifiers).
   llvm::Metadata *CreateMetadataIdentifierForType(QualType T);
 
+  /// Create a metadata identifier for the generalization of the given type.
+  /// This may either be an MDString (for external identifiers) or a distinct
+  /// unnamed MDNode (for internal identifiers).
+  llvm::Metadata *CreateMetadataIdentifierGeneralized(QualType T);
+
   /// Create and attach type metadata to the given function.
   void CreateFunctionTypeMetadata(const FunctionDecl *FD, llvm::Function *F);
 
diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp
index 037989680f..32c1c43a5b 100644
--- a/lib/Driver/SanitizerArgs.cpp
+++ b/lib/Driver/SanitizerArgs.cpp
@@ -520,6 +520,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
     // Without PIE, external function address may resolve to a PLT record, which
     // can not be verified by the target module.
     NeedPIE |= CfiCrossDso;
+    CfiICallGeneralizePointers =
+        Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers);
+
+    if (CfiCrossDso && CfiICallGeneralizePointers)
+      D.Diag(diag::err_drv_argument_not_allowed_with)
+          << "-fsanitize-cfi-cross-dso"
+          << "-fsanitize-cfi-icall-generalize-pointers";
   }
 
   Stats = Args.hasFlag(options::OPT_fsanitize_stats,
@@ -807,6 +814,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
   if (CfiCrossDso)
     CmdArgs.push_back("-fsanitize-cfi-cross-dso");
 
+  if (CfiICallGeneralizePointers)
+    CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers");
+
   if (Stats)
     CmdArgs.push_back("-fsanitize-stats");
 
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 19e26c18bf..2c0d99b4be 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -839,6 +839,8 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
                    false);
   Opts.SanitizeMinimalRuntime = Args.hasArg(OPT_fsanitize_minimal_runtime);
   Opts.SanitizeCfiCrossDso = Args.hasArg(OPT_fsanitize_cfi_cross_dso);
+  Opts.SanitizeCfiICallGeneralizePointers =
+      Args.hasArg(OPT_fsanitize_cfi_icall_generalize_pointers);
   Opts.SanitizeStats = Args.hasArg(OPT_fsanitize_stats);
   if (Arg *A = Args.getLastArg(OPT_fsanitize_address_use_after_scope,
                                OPT_fno_sanitize_address_use_after_scope)) {
diff --git a/test/CodeGen/cfi-icall-cross-dso.c b/test/CodeGen/cfi-icall-cross-dso.c
index 636a9e4aed..43ab0e73b1 100644
--- a/test/CodeGen/cfi-icall-cross-dso.c
+++ b/test/CodeGen/cfi-icall-cross-dso.c
@@ -46,7 +46,7 @@ void caller(void (*f)()) {
 // Check that we emit both string and hash based type entries for static void g(),
 // and don't emit them for the declaration of h().
 
-// CHECK: define internal void @g({{.*}} !type [[TVOID:![0-9]+]] !type [[TVOID_ID:![0-9]+]]
+// CHECK: define internal void @g({{.*}} !type [[TVOID:![0-9]+]] !type [[TVOID_GENERALIZED:![0-9]+]] !type [[TVOID_ID:![0-9]+]]
 static void g(void) {}
 
 // CHECK: declare void @h({{[^!]*$}}
@@ -60,9 +60,9 @@ Fn h1() {
   return &h;
 }
 
-// CHECK: define void @bar({{.*}} !type [[TNOPROTO:![0-9]+]] !type [[TNOPROTO_ID:![0-9]+]]
+// CHECK: define void @bar({{.*}} !type [[TNOPROTO:![0-9]+]] !type [[TNOPROTO_GENERALIZED:![0-9]+]] !type [[TNOPROTO_ID:![0-9]+]]
 // ITANIUM: define available_externally void @foo({{[^!]*$}}
-// MS: define linkonce_odr void @foo({{.*}} !type [[TNOPROTO]] !type [[TNOPROTO_ID]]
+// MS: define linkonce_odr void @foo({{.*}} !type [[TNOPROTO]] !type [[TNOPROTO_GENERALIZED:![0-9]+]] !type [[TNOPROTO_ID]]
 inline void foo() {}
 void bar() { foo(); }
 
@@ -71,11 +71,15 @@ void bar() { foo(); }
 // Check that the type entries are correct.
 
 // ITANIUM: [[TVOID]] = !{i64 0, !"_ZTSFvvE"}
+// ITANIUM: [[TVOID_GENERALIZED]] = !{i64 0, !"_ZTSFvvE.generalized"}
 // ITANIUM: [[TVOID_ID]] = !{i64 0, i64 9080559750644022485}
 // ITANIUM: [[TNOPROTO]] = !{i64 0, !"_ZTSFvE"}
+// ITANIUM: [[TNOPROTO_GENERALIZED]] = !{i64 0, !"_ZTSFvE.generalized"}
 // ITANIUM: [[TNOPROTO_ID]] = !{i64 0, i64 6588678392271548388}
 
 // MS: [[TVOID]] = !{i64 0, !"?6AXXZ"}
+// MS: [[TVOID_GENERALIZED]] = !{i64 0, !"?6AXXZ.generalized"}
 // MS: [[TVOID_ID]] = !{i64 0, i64 5113650790573562461}
 // MS: [[TNOPROTO]] = !{i64 0, !"?6AX@Z"}
+// MS: [[TNOPROTO_GENERALIZED]] = !{i64 0, !"?6AX@Z.generalized"}
 // MS: [[TNOPROTO_ID]] = !{i64 0, i64 4195979634929632483}
diff --git a/test/CodeGen/cfi-icall-generalize.c b/test/CodeGen/cfi-icall-generalize.c
new file mode 100644
index 0000000000..c7c7b30a7a
--- /dev/null
+++ b/test/CodeGen/cfi-icall-generalize.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=UNGENERALIZED %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -fsanitize-cfi-icall-generalize-pointers -emit-llvm -o - %s | FileCheck --check-prefix=CHECK --check-prefix=GENERALIZED %s
+
+// Test that const char* is generalized to const void* and that const char** is
+// generalized to void*
+
+// CHECK: define i32** @f({{.*}} !type [[TYPE:![0-9]+]] !type [[TYPE_GENERALIZED:![0-9]+]]
+int** f(const char *a, const char **b) {
+  return (int**)0;
+}
+
+void g(int** (*fp)(const char *, const char **)) {
+  // UNGENERALIZED: call i1 @llvm.type.test(i8* {{.*}}, metadata !"_ZTSFPPiPKcPS2_E")
+  // GENERALIZED: call i1 @llvm.type.test(i8* {{.*}}, metadata !"_ZTSFPvPKvS_E.generalized")
+  fp(0, 0);
+}
+
+// CHECK: [[TYPE]] = !{i64 0, !"_ZTSFPPiPKcPS2_E"}
+// CHECK: [[TYPE_GENERALIZED]] = !{i64 0, !"_ZTSFPvPKvS_E.generalized"}
diff --git a/test/CodeGen/cfi-icall.c b/test/CodeGen/cfi-icall.c
index ed34f4f44b..5f346b66e8 100644
--- a/test/CodeGen/cfi-icall.c
+++ b/test/CodeGen/cfi-icall.c
@@ -3,22 +3,26 @@
 
 // Tests that we assign appropriate identifiers to unprototyped functions.
 
-// CHECK: define void @f({{.*}} !type [[TVOID:![0-9]+]]
+// CHECK: define void @f({{.*}} !type [[TVOID:![0-9]+]] !type [[TVOID_GENERALIZED:![0-9]+]]
 void f() {
 }
 
 void xf();
 
-// CHECK: define void @g({{.*}} !type [[TINT:![0-9]+]]
+// CHECK: define void @g({{.*}} !type [[TINT:![0-9]+]] !type [[TINT_GENERALIZED:![0-9]+]]
 void g(int b) {
   void (*fp)() = b ? f : xf;
   // ITANIUM: call i1 @llvm.type.test(i8* {{.*}}, metadata !"_ZTSFvE")
   fp();
 }
 
-// CHECK: declare !type [[TVOID:![0-9]+]] void @xf({{.*}}
+// CHECK: declare !type [[TVOID]] !type [[TVOID_GENERALIZED]] void @xf({{.*}}
 
 // ITANIUM-DAG: [[TVOID]] = !{i64 0, !"_ZTSFvE"}
+// ITANIUM-DAG: [[TVOID_GENERALIZED]] = !{i64 0, !"_ZTSFvE.generalized"}
 // ITANIUM-DAG: [[TINT]] = !{i64 0, !"_ZTSFviE"}
+// ITANIUM-DAG: [[TINT_GENERALIZED]] = !{i64 0, !"_ZTSFviE.generalized"}
 // MS-DAG: [[TVOID]] = !{i64 0, !"?6AX@Z"}
+// MS-DAG: [[TVOID_GENERALIZED]] = !{i64 0, !"?6AX@Z.generalized"}
 // MS-DAG: [[TINT]] = !{i64 0, !"?6AXH@Z"}
+// MS-DAG: [[TINT_GENERALIZED]] = !{i64 0, !"?6AXH@Z.generalized"}
diff --git a/test/CodeGenCXX/cfi-icall.cpp b/test/CodeGenCXX/cfi-icall.cpp
index c3c6ed309c..5f5778fc1f 100644
--- a/test/CodeGenCXX/cfi-icall.cpp
+++ b/test/CodeGenCXX/cfi-icall.cpp
@@ -8,19 +8,22 @@ namespace {
 
 struct S {};
 
-void f(S *s) {
+void f(S s) {
 }
 
 }
 
 void g() {
-  void (*fp)(S *) = f;
-  // CHECK: call i1 @llvm.type.test(i8* {{.*}}, metadata [[VOIDS:![0-9]+]])
-  fp(0);
+  struct S s;
+  void (*fp)(S) = f;
+  // CHECK: call i1 @llvm.type.test(i8* {{.*}}, metadata [[VOIDS1:![0-9]+]])
+  fp(s);
 }
 
-// ITANIUM: define internal void @_ZN12_GLOBAL__N_11fEPNS_1SE({{.*}} !type [[TS:![0-9]+]]
-// MS: define internal void @"\01?f@?A@@YAXPEAUS@?A@@@Z"({{.*}} !type [[TS:![0-9]+]]
+// ITANIUM: define internal void @_ZN12_GLOBAL__N_11fENS_1SE({{.*}} !type [[TS1:![0-9]+]] !type [[TS2:![0-9]+]]
+// MS: define internal void @"\01?f@?A@@YAXUS@?A@@@Z"({{.*}} !type [[TS1:![0-9]+]] !type [[TS2:![0-9]+]]
 
-// CHECK: [[VOIDS]] = distinct !{}
-// CHECK: [[TS]] = !{i64 0, [[VOIDS]]}
+// CHECK: [[VOIDS1]] = distinct !{}
+// CHECK: [[TS1]] = !{i64 0, [[VOIDS1]]}
+// CHECK: [[TS2]] = !{i64 0, [[VOIDS2:![0-9]+]]}
+// CHECK: [[VOIDS2]] = distinct !{}
diff --git a/test/Driver/fsanitize.c b/test/Driver/fsanitize.c
index 92d5c5da72..dcca96ff3a 100644
--- a/test/Driver/fsanitize.c
+++ b/test/Driver/fsanitize.c
@@ -480,6 +480,14 @@
 // CHECK-CFI-NO-CROSS-DSO: -emit-llvm-bc
 // CHECK-CFI-NO-CROSS-DSO-NOT: -fsanitize-cfi-cross-dso
 
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-icall -fsanitize-cfi-icall-generalize-pointers -fvisibility=hidden -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-GENERALIZE-POINTERS
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-icall -fvisibility=hidden -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-CFI-GENERALIZE-POINTERS
+// CHECK-CFI-GENERALIZE-POINTERS: -fsanitize-cfi-icall-generalize-pointers
+// CHECK-NO-CFI-GENERALIZE-POINTERS-NOT: -fsanitize-cfi-icall-generalize-pointers
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi-icall -fsanitize-cfi-icall-generalize-pointers -fsanitize-cfi-cross-dso -fvisibility=hidden -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-GENERALIZE-AND-CROSS-DSO
+// CHECK-CFI-GENERALIZE-AND-CROSS-DSO: error: invalid argument '-fsanitize-cfi-cross-dso' not allowed with '-fsanitize-cfi-icall-generalize-pointers'
+
 // RUN: %clang -target x86_64-linux-gnu -fsanitize=cfi -fsanitize-stats -flto -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CFI-STATS
 // CHECK-CFI-STATS: -fsanitize-stats
 
-- 
GitLab


From a9fba7b0ec1b2384f171950089021fadec7da08b Mon Sep 17 00:00:00 2001
From: Wolfgang Pieb 
Date: Tue, 31 Oct 2017 22:49:48 +0000
Subject: [PATCH 0152/1682] Fix for PR33930. Short-circuit metadata mapping
 when cloning a varargs thunk. The cloning happens before all metadata nodes
 are resolved. Prevent the value mapper from running into unresolved or
 temporary MD nodes.

Differential Revision: https://reviews.llvm.org/D39396


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317047 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/CodeGen/CGVTables.cpp         | 34 ++++++++++++++++++++++++++++++-
 test/CodeGenCXX/tmp-md-nodes1.cpp | 18 ++++++++++++++++
 test/CodeGenCXX/tmp-md-nodes2.cpp | 33 ++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+), 1 deletion(-)
 create mode 100644 test/CodeGenCXX/tmp-md-nodes1.cpp
 create mode 100644 test/CodeGenCXX/tmp-md-nodes2.cpp

diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 64b6d0d3fe..67388ee208 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -14,11 +14,12 @@
 #include "CGCXXABI.h"
 #include "CodeGenFunction.h"
 #include "CodeGenModule.h"
-#include "clang/CodeGen/ConstantInitBuilder.h"
 #include "clang/AST/CXXInheritance.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/CodeGen/CGFunctionInfo.h"
+#include "clang/CodeGen/ConstantInitBuilder.h"
 #include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/IR/IntrinsicInst.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Transforms/Utils/Cloning.h"
 #include 
@@ -122,6 +123,33 @@ static RValue PerformReturnAdjustment(CodeGenFunction &CGF,
   return RValue::get(ReturnValue);
 }
 
+/// This function clones a function's DISubprogram node and enters it into 
+/// a value map with the intent that the map can be utilized by the cloner
+/// to short-circuit Metadata node mapping.
+/// Furthermore, the function resolves any DILocalVariable nodes referenced
+/// by dbg.value intrinsics so they can be properly mapped during cloning.
+static void resolveTopLevelMetadata(llvm::Function *Fn,
+                                    llvm::ValueToValueMapTy &VMap) {
+  // Clone the DISubprogram node and put it into the Value map.
+  auto *DIS = Fn->getSubprogram();
+  if (!DIS)
+    return;
+  auto *NewDIS = DIS->replaceWithDistinct(DIS->clone());
+  VMap.MD()[DIS].reset(NewDIS);
+
+  // Find all llvm.dbg.declare intrinsics and resolve the DILocalVariable nodes
+  // they are referencing.
+  for (auto &BB : Fn->getBasicBlockList()) {
+    for (auto &I : BB) {
+      if (auto *DII = dyn_cast(&I)) {
+        auto *DILocal = DII->getVariable();
+        if (!DILocal->isResolved())
+          DILocal->resolve();
+      }
+    }
+  }
+}
+
 // This function does roughly the same thing as GenerateThunk, but in a
 // very different way, so that va_start and va_end work correctly.
 // FIXME: This function assumes "this" is the first non-sret LLVM argument of
@@ -154,6 +182,10 @@ CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn,
 
   // Clone to thunk.
   llvm::ValueToValueMapTy VMap;
+
+  // We are cloning a function while some Metadata nodes are still unresolved.
+  // Ensure that the value mapper does not encounter any of them.
+  resolveTopLevelMetadata(BaseFn, VMap);
   llvm::Function *NewFn = llvm::CloneFunction(BaseFn, VMap);
   Fn->replaceAllUsesWith(NewFn);
   NewFn->takeName(Fn);
diff --git a/test/CodeGenCXX/tmp-md-nodes1.cpp b/test/CodeGenCXX/tmp-md-nodes1.cpp
new file mode 100644
index 0000000000..3957f60bc6
--- /dev/null
+++ b/test/CodeGenCXX/tmp-md-nodes1.cpp
@@ -0,0 +1,18 @@
+// REQUIRES: asserts
+// RUN: %clang_cc1 -O0 -triple %itanium_abi_triple -debug-info-kind=limited -S -emit-llvm %s -o - | \
+// RUN: FileCheck %s
+
+// This test simply checks that the varargs thunk is created. The failing test
+// case asserts.
+
+struct Alpha {
+  virtual void bravo(...);
+};
+struct Charlie {
+  virtual ~Charlie() {}
+};
+struct CharlieImpl : Charlie, Alpha {
+  void bravo(...) {}
+} delta;
+
+// CHECK: define {{.*}} void @_ZThn8_N11CharlieImpl5bravoEz(
diff --git a/test/CodeGenCXX/tmp-md-nodes2.cpp b/test/CodeGenCXX/tmp-md-nodes2.cpp
new file mode 100644
index 0000000000..00827f5914
--- /dev/null
+++ b/test/CodeGenCXX/tmp-md-nodes2.cpp
@@ -0,0 +1,33 @@
+// REQUIRES: asserts
+// RUN: %clang_cc1 -O0 -triple %itanium_abi_triple -debug-info-kind=limited -S -emit-llvm %s -o - | \
+// RUN: FileCheck %s
+
+// This test simply checks that the varargs thunk is created. The failing test
+// case asserts.
+
+typedef signed char __int8_t;
+typedef int BOOL;
+class CMsgAgent;
+
+class CFs {
+public:
+  typedef enum {} CACHE_HINT;
+  virtual BOOL ReqCacheHint( CMsgAgent* p_ma, CACHE_HINT hint, ... ) ;
+};
+
+typedef struct {} _Lldiv_t;
+
+class CBdVfs {
+public:
+  virtual ~CBdVfs( ) {}
+};
+
+class CBdVfsImpl : public CBdVfs, public CFs {
+  BOOL ReqCacheHint( CMsgAgent* p_ma, CACHE_HINT hint, ... );
+};
+
+BOOL CBdVfsImpl::ReqCacheHint( CMsgAgent* p_ma, CACHE_HINT hint, ... ) {
+  return true;
+}
+
+// CHECK: define {{.*}} @_ZThn8_N10CBdVfsImpl12ReqCacheHintEP9CMsgAgentN3CFs10CACHE_HINTEz(
-- 
GitLab


From 9f13e3eb1bc8ce6c27ab73790fb29dddcd841d37 Mon Sep 17 00:00:00 2001
From: Benjamin Kramer 
Date: Tue, 31 Oct 2017 23:23:36 +0000
Subject: [PATCH 0153/1682] Make helper function static. NFC.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317052 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/AST/Type.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 5e7cf34704..d0707a4a73 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -2182,7 +2182,7 @@ bool QualType::unionHasUniqueObjectRepresentations(
   return true;
 }
 
-bool isStructEmpty(QualType Ty) {
+static bool isStructEmpty(QualType Ty) {
   assert(Ty.getTypePtr()->isStructureOrClassType() &&
          "Must be struct or class");
   const RecordDecl *RD = Ty.getTypePtr()->getAs()->getDecl();
-- 
GitLab


From 8f5bfda4bc94a60372086d755198224a5497d87f Mon Sep 17 00:00:00 2001
From: Wolfgang Pieb 
Date: Wed, 1 Nov 2017 00:01:20 +0000
Subject: [PATCH 0154/1682] Making a couple of tests a bit more flexible wrt
 thunk mangling. Fixes checkin for r317047.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317053 91177308-0d34-0410-b5e6-96231b3b80d8
---
 test/CodeGenCXX/tmp-md-nodes1.cpp | 2 +-
 test/CodeGenCXX/tmp-md-nodes2.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/CodeGenCXX/tmp-md-nodes1.cpp b/test/CodeGenCXX/tmp-md-nodes1.cpp
index 3957f60bc6..41a0159b0f 100644
--- a/test/CodeGenCXX/tmp-md-nodes1.cpp
+++ b/test/CodeGenCXX/tmp-md-nodes1.cpp
@@ -15,4 +15,4 @@ struct CharlieImpl : Charlie, Alpha {
   void bravo(...) {}
 } delta;
 
-// CHECK: define {{.*}} void @_ZThn8_N11CharlieImpl5bravoEz(
+// CHECK: define {{.*}} void @_ZThn{{[48]}}_N11CharlieImpl5bravoEz(
diff --git a/test/CodeGenCXX/tmp-md-nodes2.cpp b/test/CodeGenCXX/tmp-md-nodes2.cpp
index 00827f5914..e50220cfb7 100644
--- a/test/CodeGenCXX/tmp-md-nodes2.cpp
+++ b/test/CodeGenCXX/tmp-md-nodes2.cpp
@@ -30,4 +30,4 @@ BOOL CBdVfsImpl::ReqCacheHint( CMsgAgent* p_ma, CACHE_HINT hint, ... ) {
   return true;
 }
 
-// CHECK: define {{.*}} @_ZThn8_N10CBdVfsImpl12ReqCacheHintEP9CMsgAgentN3CFs10CACHE_HINTEz(
+// CHECK: define {{.*}} @_ZThn{{[48]}}_N10CBdVfsImpl12ReqCacheHintEP9CMsgAgentN3CFs10CACHE_HINTEz(
-- 
GitLab


From 3d102c8ddd12ab268a8484ee21f828ef5cd8f2c9 Mon Sep 17 00:00:00 2001
From: Alex Lorenz 
Date: Wed, 1 Nov 2017 00:07:12 +0000
Subject: [PATCH 0155/1682] [refactor][selection] code ranges can be selected
 in objc methods

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317054 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Tooling/Refactoring/ASTSelection.cpp | 11 ++--
 unittests/Tooling/ASTSelectionTest.cpp   | 76 ++++++++++++++++++++++++
 2 files changed, 83 insertions(+), 4 deletions(-)

diff --git a/lib/Tooling/Refactoring/ASTSelection.cpp b/lib/Tooling/Refactoring/ASTSelection.cpp
index 6ac432622c..71a0d44be1 100644
--- a/lib/Tooling/Refactoring/ASTSelection.cpp
+++ b/lib/Tooling/Refactoring/ASTSelection.cpp
@@ -347,6 +347,11 @@ CodeRangeASTSelection::create(SourceRange SelectionRange,
                                /*AreChildrenSelected=*/true);
 }
 
+static bool isFunctionLikeDeclaration(const Decl *D) {
+  // FIXME (Alex L): Test for BlockDecl.
+  return isa(D) || isa(D);
+}
+
 bool CodeRangeASTSelection::isInFunctionLikeBodyOfCode() const {
   bool IsPrevCompound = false;
   // Scan through the parents (bottom-to-top) and check if the selection is
@@ -355,8 +360,7 @@ bool CodeRangeASTSelection::isInFunctionLikeBodyOfCode() const {
   for (const auto &Parent : llvm::reverse(Parents)) {
     const DynTypedNode &Node = Parent.get().Node;
     if (const auto *D = Node.get()) {
-      // FIXME (Alex L): Test for BlockDecl && ObjCMethodDecl.
-      if (isa(D))
+      if (isFunctionLikeDeclaration(D))
         return IsPrevCompound;
       // FIXME (Alex L): We should return false on top-level decls in functions
       // e.g. we don't want to extract:
@@ -372,8 +376,7 @@ const Decl *CodeRangeASTSelection::getFunctionLikeNearestParent() const {
   for (const auto &Parent : llvm::reverse(Parents)) {
     const DynTypedNode &Node = Parent.get().Node;
     if (const auto *D = Node.get()) {
-      // FIXME (Alex L): Test for BlockDecl && ObjCMethodDecl.
-      if (isa(D))
+      if (isFunctionLikeDeclaration(D))
         return D;
     }
   }
diff --git a/unittests/Tooling/ASTSelectionTest.cpp b/unittests/Tooling/ASTSelectionTest.cpp
index 94435d49a8..1435334d6c 100644
--- a/unittests/Tooling/ASTSelectionTest.cpp
+++ b/unittests/Tooling/ASTSelectionTest.cpp
@@ -896,4 +896,80 @@ void f(int x, int y) {
       });
 }
 
+TEST(ASTSelectionFinder, SimpleCodeRangeASTSelectionInObjCMethod) {
+  StringRef Source = R"(@interface I @end
+@implementation I
+- (void) f:(int)x with:(int) y {
+  int z = x;
+  [self f: 2 with: 3];
+  if (x == 0) {
+    return;
+  }
+  x = 1;
+  return;
+}
+- (void)f2 {
+  int m = 0;
+}
+@end
+)";
+  // Range that spans multiple methods is an invalid code range.
+  findSelectedASTNodesWithRange(
+      Source, {9, 2}, FileRange{{9, 2}, {13, 1}},
+      [](SourceRange SelectionRange, Optional Node) {
+        EXPECT_TRUE(Node);
+        Optional SelectedCode =
+            CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+        EXPECT_FALSE(SelectedCode);
+      },
+      SelectionFinderVisitor::Lang_OBJC);
+  // Just 'z = x;':
+  findSelectedASTNodesWithRange(
+      Source, {4, 2}, FileRange{{4, 2}, {4, 13}},
+      [](SourceRange SelectionRange, Optional Node) {
+        EXPECT_TRUE(Node);
+        Optional SelectedCode =
+            CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+        EXPECT_TRUE(SelectedCode);
+        EXPECT_EQ(SelectedCode->size(), 1u);
+        EXPECT_TRUE(isa((*SelectedCode)[0]));
+        ArrayRef Parents =
+            SelectedCode->getParents();
+        EXPECT_EQ(Parents.size(), 4u);
+        EXPECT_TRUE(
+            isa(Parents[0].get().Node.get()));
+        // 'I' @implementation.
+        EXPECT_TRUE(isa(Parents[1].get().Node.get()));
+        // Function 'f' definition.
+        EXPECT_TRUE(isa(Parents[2].get().Node.get()));
+        // Function body of function 'F'.
+        EXPECT_TRUE(isa(Parents[3].get().Node.get()));
+      },
+      SelectionFinderVisitor::Lang_OBJC);
+  // From '[self f: 2 with: 3]' until just before 'x = 1;':
+  findSelectedASTNodesWithRange(
+      Source, {5, 2}, FileRange{{5, 2}, {9, 1}},
+      [](SourceRange SelectionRange, Optional Node) {
+        EXPECT_TRUE(Node);
+        Optional SelectedCode =
+            CodeRangeASTSelection::create(SelectionRange, std::move(*Node));
+        EXPECT_TRUE(SelectedCode);
+        EXPECT_EQ(SelectedCode->size(), 2u);
+        EXPECT_TRUE(isa((*SelectedCode)[0]));
+        EXPECT_TRUE(isa((*SelectedCode)[1]));
+        ArrayRef Parents =
+            SelectedCode->getParents();
+        EXPECT_EQ(Parents.size(), 4u);
+        EXPECT_TRUE(
+            isa(Parents[0].get().Node.get()));
+        // 'I' @implementation.
+        EXPECT_TRUE(isa(Parents[1].get().Node.get()));
+        // Function 'f' definition.
+        EXPECT_TRUE(isa(Parents[2].get().Node.get()));
+        // Function body of function 'F'.
+        EXPECT_TRUE(isa(Parents[3].get().Node.get()));
+      },
+      SelectionFinderVisitor::Lang_OBJC);
+}
+
 } // end anonymous namespace
-- 
GitLab


From 06b063e3bbf2ce05d25770a4c77cf1b748ce198c Mon Sep 17 00:00:00 2001
From: Alex Lorenz 
Date: Wed, 1 Nov 2017 00:20:55 +0000
Subject: [PATCH 0156/1682] [refactor][extract] prohibit extraction of ObjC
 property setters

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317056 91177308-0d34-0410-b5e6-96231b3b80d8
---
 .../clang/Basic/DiagnosticRefactoringKinds.td |  2 +
 lib/Tooling/Refactoring/Extract.cpp           | 19 ++++++---
 test/Refactor/Extract/ObjCProperty.m          | 41 +++++++++++++++++++
 3 files changed, 57 insertions(+), 5 deletions(-)
 create mode 100644 test/Refactor/Extract/ObjCProperty.m

diff --git a/include/clang/Basic/DiagnosticRefactoringKinds.td b/include/clang/Basic/DiagnosticRefactoringKinds.td
index b54b9301a7..ee396b9307 100644
--- a/include/clang/Basic/DiagnosticRefactoringKinds.td
+++ b/include/clang/Basic/DiagnosticRefactoringKinds.td
@@ -26,6 +26,8 @@ def err_refactor_code_outside_of_function : Error<"the selected code is not a "
   "part of a function's / method's body">;
 def err_refactor_extract_simple_expression : Error<"the selected expression "
   "is too simple to extract">;
+def err_refactor_extract_prohibited_expression : Error<"the selected "
+  "expression can't be extracted">;
 
 }
 
diff --git a/lib/Tooling/Refactoring/Extract.cpp b/lib/Tooling/Refactoring/Extract.cpp
index b1000b60ee..e81bb3ffe9 100644
--- a/lib/Tooling/Refactoring/Extract.cpp
+++ b/lib/Tooling/Refactoring/Extract.cpp
@@ -16,6 +16,7 @@
 #include "clang/Tooling/Refactoring/Extract/Extract.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
 #include "clang/Rewrite/Core/Rewriter.h"
 
 namespace clang {
@@ -70,12 +71,20 @@ ExtractFunction::initiate(RefactoringRuleContext &Context,
     return Context.createDiagnosticError(
         diag::err_refactor_code_outside_of_function);
 
-  // Avoid extraction of simple literals and references.
-  if (Code.size() == 1 && isSimpleExpression(dyn_cast(Code[0])))
-    return Context.createDiagnosticError(
-        diag::err_refactor_extract_simple_expression);
+  if (Code.size() == 1) {
+    // Avoid extraction of simple literals and references.
+    if (isSimpleExpression(dyn_cast(Code[0])))
+      return Context.createDiagnosticError(
+          diag::err_refactor_extract_simple_expression);
+
+    // Property setters can't be extracted.
+    if (const auto *PRE = dyn_cast(Code[0])) {
+      if (!PRE->isMessagingGetter())
+        return Context.createDiagnosticError(
+            diag::err_refactor_extract_prohibited_expression);
+    }
+  }
 
-  // FIXME (Alex L): Prohibit extraction of Objective-C property setters.
   return ExtractFunction(std::move(Code), DeclName);
 }
 
diff --git a/test/Refactor/Extract/ObjCProperty.m b/test/Refactor/Extract/ObjCProperty.m
new file mode 100644
index 0000000000..152ccb3484
--- /dev/null
+++ b/test/Refactor/Extract/ObjCProperty.m
@@ -0,0 +1,41 @@
+// RUN: clang-refactor extract -selection=test:%s %s -- 2>&1 | grep -v CHECK | FileCheck %s
+
+@interface HasProperty
+
+@property (strong) HasProperty *item;
+
+- (HasProperty *)implicitProp;
+
+- (void)setImplicitSetter:(HasProperty *)value;
+
+@end
+
+@implementation HasProperty
+
+- (void)allowGetterExtraction {
+  /*range allow_getter=->+0:42*/self.item;
+  /*range allow_imp_getter=->+0:54*/self.implicitProp;
+}
+// CHECK: 1 'allow_getter' results:
+// CHECK:      extracted() {
+// CHECK-NEXT: return self.item;{{$}}
+// CHECK-NEXT: }{{[[:space:]].*}}
+// CHECK-NEXT: - (void)allowGetterExtraction {
+// CHECK-NEXT: extracted();
+
+// CHECK: 1 'allow_imp_getter' results:
+// CHECK:      extracted() {
+// CHECK-NEXT: return self.implicitProp;{{$}}
+// CHECK-NEXT: }{{[[:space:]].*}}
+// CHECK-NEXT: - (void)allowGetterExtraction {
+// CHECK-NEXT: self.item;
+// CHECK-NEXT: extracted();
+
+- (void)prohibitSetterExtraction {
+  /*range prohibit_setter=->+0:45*/self.item = 0;
+  /*range prohibit_setter=->+0:55*/self.implicitSetter = 0;
+}
+// CHECK: 2 'prohibit_setter' results:
+// CHECK: the selected expression can't be extracted
+
+@end
-- 
GitLab


From 8ac52b01ceb1331c1642ac52b93229d038bf8df1 Mon Sep 17 00:00:00 2001
From: Alex Lorenz 
Date: Wed, 1 Nov 2017 01:12:56 +0000
Subject: [PATCH 0157/1682] [refactor][extract] code extracted from inline
 method should be placed in a function defined before the outer class

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317062 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Tooling/Refactoring/Extract.cpp           |  9 +++-
 .../Refactor/Extract/FromMethodToFunction.cpp | 42 +++++++++++++++++++
 2 files changed, 49 insertions(+), 2 deletions(-)
 create mode 100644 test/Refactor/Extract/FromMethodToFunction.cpp

diff --git a/lib/Tooling/Refactoring/Extract.cpp b/lib/Tooling/Refactoring/Extract.cpp
index e81bb3ffe9..3f5a839318 100644
--- a/lib/Tooling/Refactoring/Extract.cpp
+++ b/lib/Tooling/Refactoring/Extract.cpp
@@ -15,6 +15,7 @@
 
 #include "clang/Tooling/Refactoring/Extract/Extract.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/Rewrite/Core/Rewriter.h"
@@ -44,8 +45,12 @@ bool isSimpleExpression(const Expr *E) {
 }
 
 SourceLocation computeFunctionExtractionLocation(const Decl *D) {
-  // FIXME (Alex L): Method -> function extraction should place function before
-  // C++ record if the method is defined inside the record.
+  if (isa(D)) {
+    // Code from method that is defined in class body should be extracted to a
+    // function defined just before the class.
+    while (const auto *RD = dyn_cast(D->getLexicalDeclContext()))
+      D = RD;
+  }
   return D->getLocStart();
 }
 
diff --git a/test/Refactor/Extract/FromMethodToFunction.cpp b/test/Refactor/Extract/FromMethodToFunction.cpp
new file mode 100644
index 0000000000..86bec16edf
--- /dev/null
+++ b/test/Refactor/Extract/FromMethodToFunction.cpp
@@ -0,0 +1,42 @@
+// RUN: clang-refactor extract -selection=test:%s %s -- -std=c++11 2>&1 | grep -v CHECK | FileCheck --check-prefixes=CHECK,CHECK-INNER %s
+// RUN: clang-refactor extract -selection=test:%s %s -- -std=c++11 -DMULTIPLE 2>&1 | grep -v CHECK | FileCheck --check-prefixes=CHECK,CHECK-OUTER %s
+
+#ifdef MULTIPLE
+class OuterClass {
+#define PREFIX OuterClass ::
+#else
+#define PREFIX
+#endif
+
+class AClass {
+
+  int method(int x) {
+    return /*range inner=->+0:38*/1 + 2 * 2;
+  }
+// CHECK-INNER: 1 'inner' results:
+// CHECK-INNER:      static int extracted() {
+// CHECK-INNER-NEXT: return 1 + 2 * 2;{{$}}
+// CHECK-INNER-NEXT: }{{[[:space:]].*}}
+// CHECK-INNER-NEXT: class AClass {
+
+// CHECK-OUTER: 1 'inner' results:
+// CHECK-OUTER:      static int extracted() {
+// CHECK-OUTER-NEXT: return 1 + 2 * 2;{{$}}
+// CHECK-OUTER-NEXT: }{{[[:space:]].*}}
+// CHECK-OUTER-NEXT: class OuterClass {
+
+  int otherMethod(int x);
+};
+
+#ifdef MULTIPLE
+};
+#endif
+
+int PREFIX AClass::otherMethod(int x) {
+  return /*range outofline=->+0:46*/2 * 2 - 1;
+}
+// CHECK: 1 'outofline' results:
+// CHECK:      static int extracted() {
+// CHECK-NEXT: return 2 * 2 - 1;{{$}}
+// CHECK-NEXT: }{{[[:space:]].*}}
+// CHECK-NEXT: int PREFIX AClass::otherMethod
-- 
GitLab


From eb1c10e34de92b9ee0d0ccfbef13a231187eda3d Mon Sep 17 00:00:00 2001
From: George Karpenkov 
Date: Wed, 1 Nov 2017 01:36:01 +0000
Subject: [PATCH 0158/1682] [Analyzer] Use value storage for BodyFarm

Differential Revision: https://reviews.llvm.org/D39428

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317065 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Analysis/AnalysisDeclContext.h |  8 ++++----
 include/clang/Analysis/BodyFarm.h            |  3 +++
 lib/Analysis/AnalysisDeclContext.cpp         | 13 +++++--------
 3 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/include/clang/Analysis/AnalysisDeclContext.h b/include/clang/Analysis/AnalysisDeclContext.h
index ecd99f8054..39f6a8df7b 100644
--- a/include/clang/Analysis/AnalysisDeclContext.h
+++ b/include/clang/Analysis/AnalysisDeclContext.h
@@ -419,9 +419,9 @@ class AnalysisDeclContextManager {
   /// declarations from external source.
   std::unique_ptr Injector;
 
-  /// Pointer to a factory for creating and caching implementations for common
+  /// A factory for creating and caching implementations for common
   /// methods during the analysis.
-  std::unique_ptr FunctionBodyFarm;
+  BodyFarm FunctionBodyFarm;
 
   /// Flag to indicate whether or not bodies should be synthesized
   /// for well-known functions.
@@ -475,8 +475,8 @@ public:
     return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx);
   }
 
-  /// Get and lazily create a {@code BodyFarm} instance.
-  BodyFarm *getBodyFarm();
+  /// Get a reference to {@code BodyFarm} instance.
+  BodyFarm &getBodyFarm();
 
   /// Discard all previously created AnalysisDeclContexts.
   void clear();
diff --git a/include/clang/Analysis/BodyFarm.h b/include/clang/Analysis/BodyFarm.h
index 14cf2624b8..ff0859bc66 100644
--- a/include/clang/Analysis/BodyFarm.h
+++ b/include/clang/Analysis/BodyFarm.h
@@ -39,6 +39,9 @@ public:
   /// Factory method for creating bodies for Objective-C properties.
   Stmt *getBody(const ObjCMethodDecl *D);
 
+  /// Remove copy constructor to avoid accidental copying.
+  BodyFarm(const BodyFarm &other) = delete;
+
 private:
   typedef llvm::DenseMap> BodyMap;
 
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index c7c720eb77..f54e7c1654 100644
--- a/lib/Analysis/AnalysisDeclContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -68,7 +68,8 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(
     bool addInitializers, bool addTemporaryDtors, bool addLifetime,
     bool addLoopExit, bool synthesizeBodies, bool addStaticInitBranch,
     bool addCXXNewAllocator, CodeInjector *injector)
-    : ASTCtx(ASTCtx), Injector(injector), SynthesizeBodies(synthesizeBodies) {
+    : ASTCtx(ASTCtx), Injector(injector), FunctionBodyFarm(ASTCtx, injector),
+      SynthesizeBodies(synthesizeBodies) {
   cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
   cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
   cfgBuildOptions.AddInitializers = addInitializers;
@@ -88,7 +89,7 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
     if (auto *CoroBody = dyn_cast_or_null(Body))
       Body = CoroBody->getBody();
     if (Manager && Manager->synthesizeBodies()) {
-      Stmt *SynthesizedBody = Manager->getBodyFarm()->getBody(FD);
+      Stmt *SynthesizedBody = Manager->getBodyFarm().getBody(FD);
       if (SynthesizedBody) {
         Body = SynthesizedBody;
         IsAutosynthesized = true;
@@ -99,7 +100,7 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
   else if (const ObjCMethodDecl *MD = dyn_cast(D)) {
     Stmt *Body = MD->getBody();
     if (Manager && Manager->synthesizeBodies()) {
-      Stmt *SynthesizedBody = Manager->getBodyFarm()->getBody(MD);
+      Stmt *SynthesizedBody = Manager->getBodyFarm().getBody(MD);
       if (SynthesizedBody) {
         Body = SynthesizedBody;
         IsAutosynthesized = true;
@@ -304,11 +305,7 @@ AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) {
   return AC.get();
 }
 
-BodyFarm *AnalysisDeclContextManager::getBodyFarm() {
-  if (!FunctionBodyFarm)
-    FunctionBodyFarm = llvm::make_unique(ASTCtx, Injector.get());
-  return FunctionBodyFarm.get();
-}
+BodyFarm &AnalysisDeclContextManager::getBodyFarm() { return FunctionBodyFarm; }
 
 const StackFrameContext *
 AnalysisDeclContext::getStackFrame(LocationContext const *Parent, const Stmt *S,
-- 
GitLab


From 2680fb2e8a862140ca2ad728276eeea9bfb1d103 Mon Sep 17 00:00:00 2001
From: Richard Smith 
Date: Wed, 1 Nov 2017 01:37:11 +0000
Subject: [PATCH 0159/1682] [c++17] Refine resolution of constructor /
 conversion function disambiguation.

Given a choice between a constructor call and a conversion function in C++17,
we prefer the constructor for direct-initialization and the conversion function
for copy-initialization, matching the behavior in C++14 and before. The
guaranteed copy elision rules were not intended to change the meaning of such
code (other than by removing unnecessary copy constructor calls).

This tweak will be raised with CWG.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317066 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Sema/SemaOverload.cpp            | 26 ++++++++++++--------------
 test/SemaCXX/cxx1z-copy-omission.cpp |  9 +++++++++
 2 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 8efb7c69d3..56135288db 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -8977,6 +8977,18 @@ bool clang::isBetterOverloadCandidate(
     // C++14 [over.match.best]p1 section 2 bullet 3.
   }
 
+  // FIXME: Work around a defect in the C++17 guaranteed copy elision wording,
+  // as combined with the resolution to CWG issue 243.
+  //
+  // When the context is initialization by constructor ([over.match.ctor] or
+  // either phase of [over.match.list]), a constructor is preferred over
+  // a conversion function.
+  if (Kind == OverloadCandidateSet::CSK_InitByConstructor && NumArgs == 1 &&
+      Cand1.Function && Cand2.Function &&
+      isa(Cand1.Function) !=
+          isa(Cand2.Function))
+    return isa(Cand1.Function);
+
   //    -- F1 is a non-template function and F2 is a function template
   //       specialization, or, if not that,
   bool Cand1IsSpecialization = Cand1.Function &&
@@ -9035,20 +9047,6 @@ bool clang::isBetterOverloadCandidate(
         return true;
     }
   }
-  
-
-
-  // FIXME: Work around a defect in the C++17 guaranteed copy elision wording,
-  // as combined with the resolution to CWG issue 243.
-  //
-  // When the context is initialization by constructor ([over.match.ctor] or
-  // either phase of [over.match.list]), a constructor is preferred over
-  // a conversion function.
-  if (Kind == OverloadCandidateSet::CSK_InitByConstructor && NumArgs == 1 &&
-      Cand1.Function && Cand2.Function &&
-      isa(Cand1.Function) !=
-          isa(Cand2.Function))
-    return isa(Cand1.Function);
 
   // Check for enable_if value-based overload resolution.
   if (Cand1.Function && Cand2.Function) {
diff --git a/test/SemaCXX/cxx1z-copy-omission.cpp b/test/SemaCXX/cxx1z-copy-omission.cpp
index cba6bc3be3..a7133d79b4 100644
--- a/test/SemaCXX/cxx1z-copy-omission.cpp
+++ b/test/SemaCXX/cxx1z-copy-omission.cpp
@@ -160,3 +160,12 @@ struct AsDelegating final {
   // classes?
   AsDelegating(int n) : AsDelegating(make(n)) {} // expected-error {{deleted}}
 };
+
+namespace CtorTemplateBeatsNonTemplateConversionFn {
+  struct Foo { template  Foo(const Derived &); };
+  template  struct Base { operator Foo() const = delete; }; // expected-note {{deleted}}
+  struct Derived : Base {};
+
+  Foo f(Derived d) { return d; } // expected-error {{invokes a deleted function}}
+  Foo g(Derived d) { return Foo(d); } // ok, calls constructor
+}
-- 
GitLab


From 93dccb54579e30a41d0f9e2571b34ef7edebbfc5 Mon Sep 17 00:00:00 2001
From: Craig Topper 
Date: Wed, 1 Nov 2017 02:18:49 +0000
Subject: [PATCH 0160/1682] [X86] Define i586 and pentium preprocessor defines
 for -march=lakemont to match GCC

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317069 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Basic/Targets/X86.cpp                  |  2 ++
 test/Preprocessor/predefined-arch-macros.c | 18 +++++++++++-------
 2 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/lib/Basic/Targets/X86.cpp b/lib/Basic/Targets/X86.cpp
index 93dcd4e234..ee70c14e1d 100644
--- a/lib/Basic/Targets/X86.cpp
+++ b/lib/Basic/Targets/X86.cpp
@@ -852,6 +852,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
   case CK_KNM:
     break;
   case CK_Lakemont:
+    defineCPUMacros(Builder, "i586", /*Tuning*/false);
+    defineCPUMacros(Builder, "pentium", /*Tuning*/false);
     Builder.defineMacro("__tune_lakemont__");
     break;
   case CK_K6_2:
diff --git a/test/Preprocessor/predefined-arch-macros.c b/test/Preprocessor/predefined-arch-macros.c
index 2f3d9e3047..d7c10cec58 100644
--- a/test/Preprocessor/predefined-arch-macros.c
+++ b/test/Preprocessor/predefined-arch-macros.c
@@ -1158,15 +1158,19 @@
 //
 // RUN: %clang -march=lakemont -m32 -E -dM %s -o - 2>&1 \
 // RUN:     -target i386-unknown-linux \
-// RUN:   | FileCheck %s -check-prefix=CHECK_LMT_M32
-// CHECK_LMT_M32: #define __i386 1
-// CHECK_LMT_M32: #define __i386__ 1
-// CHECK_LMT_M32: #define __tune_lakemont__ 1
-// CHECK_LMT_M32: #define i386 1
+// RUN:   | FileCheck %s -check-prefix=CHECK_LAKEMONT_M32
+// CHECK_LAKEMONT_M32: #define __i386 1
+// CHECK_LAKEMONT_M32: #define __i386__ 1
+// CHECK_LAKEMONT_M32: #define __i586 1
+// CHECK_LAKEMONT_M32: #define __i586__ 1
+// CHECK_LAKEMONT_M32: #define __pentium 1
+// CHECK_LAKEMONT_M32: #define __pentium__ 1
+// CHECK_LAKEMONT_M32: #define __tune_lakemont__ 1
+// CHECK_LAKEMONT_M32: #define i386 1
 // RUN: not %clang -march=lakemont -m64 -E -dM %s -o - 2>&1 \
 // RUN:     -target i386-unknown-linux \
-// RUN:   | FileCheck %s -check-prefix=CHECK_LMT_M64
-// CHECK_LMT_M64: error:
+// RUN:   | FileCheck %s -check-prefix=CHECK_LAKEMONT_M64
+// CHECK_LAKEMONT_M64: error:
 //
 // RUN: %clang -march=geode -m32 -E -dM %s -o - 2>&1 \
 // RUN:     -target i386-unknown-linux \
-- 
GitLab


From dd478afe4c5a4f486cc2bcdb0974f4ac001532b1 Mon Sep 17 00:00:00 2001
From: George Karpenkov 
Date: Wed, 1 Nov 2017 02:29:04 +0000
Subject: [PATCH 0161/1682] [analyzer] Removing unused stored field.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317070 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Analysis/AnalysisDeclContext.h | 1 -
 lib/Analysis/AnalysisDeclContext.cpp         | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/include/clang/Analysis/AnalysisDeclContext.h b/include/clang/Analysis/AnalysisDeclContext.h
index 39f6a8df7b..03ff4a9516 100644
--- a/include/clang/Analysis/AnalysisDeclContext.h
+++ b/include/clang/Analysis/AnalysisDeclContext.h
@@ -410,7 +410,6 @@ class AnalysisDeclContextManager {
   typedef llvm::DenseMap>
       ContextMap;
 
-  ASTContext &ASTCtx;
   ContextMap Contexts;
   LocationContextManager LocContexts;
   CFG::BuildOptions cfgBuildOptions;
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index f54e7c1654..181edff0a0 100644
--- a/lib/Analysis/AnalysisDeclContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -68,7 +68,7 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(
     bool addInitializers, bool addTemporaryDtors, bool addLifetime,
     bool addLoopExit, bool synthesizeBodies, bool addStaticInitBranch,
     bool addCXXNewAllocator, CodeInjector *injector)
-    : ASTCtx(ASTCtx), Injector(injector), FunctionBodyFarm(ASTCtx, injector),
+    : Injector(injector), FunctionBodyFarm(ASTCtx, injector),
       SynthesizeBodies(synthesizeBodies) {
   cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
   cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
-- 
GitLab


From bcfd8ea6e72cf5f685c1a682bd29464e3fb47762 Mon Sep 17 00:00:00 2001
From: Richard Trieu 
Date: Wed, 1 Nov 2017 03:57:27 +0000
Subject: [PATCH 0162/1682] Change assertion to quick exit from checking
 function.

Remove the assertion that could be triggered by invalid code.  Replace it with
an early exit from the checking function.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317073 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Sema/SemaDeclCXX.cpp         |  5 ++---
 test/SemaCXX/missing-members.cpp | 14 ++++++++++++++
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index fa9e9f3218..a5ccce6154 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2555,9 +2555,8 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
   CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
                      /*DetectVirtual=*/false);
   bool DerivationOkay = IsDerivedFrom(Loc, Derived, Base, Paths);
-  assert(DerivationOkay &&
-         "Can only be used with a derived-to-base conversion");
-  (void)DerivationOkay;
+  if (!DerivationOkay)
+    return true;
 
   const CXXBasePath *Path = nullptr;
   if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType()))
diff --git a/test/SemaCXX/missing-members.cpp b/test/SemaCXX/missing-members.cpp
index 96bed074db..61dddcbe50 100644
--- a/test/SemaCXX/missing-members.cpp
+++ b/test/SemaCXX/missing-members.cpp
@@ -37,3 +37,17 @@ struct S : A::B::C {
   using A::B::C::f; // expected-error {{no member named 'f' in 'A::B::C'}}
   
 };
+
+struct S1 {};
+
+struct S2 : S1 {};
+
+struct S3 : S2 {
+  void run();
+};
+
+struct S4: S3 {};
+
+void test(S4 *ptr) {
+  ptr->S1::run();  // expected-error {{no member named 'run' in 'S1'}}
+}
-- 
GitLab


From 23966147d547ba36deb4726e5c09d680fedb8909 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi 
Date: Wed, 1 Nov 2017 04:43:22 +0000
Subject: [PATCH 0163/1682] clang/lib/Format/Format.cpp: Fix warnings
 introduced in rL316903. [-Wpedantic]

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317075 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Format/Format.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 0cd5398751..2252dd9743 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -45,8 +45,8 @@
 
 using clang::format::FormatStyle;
 
-LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::IncludeCategory);
-LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::RawStringFormat);
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::IncludeCategory)
+LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::RawStringFormat)
 
 namespace llvm {
 namespace yaml {
-- 
GitLab


From 2276925224353681293a6a8ff6758a984d9c2e1c Mon Sep 17 00:00:00 2001
From: Richard Smith 
Date: Wed, 1 Nov 2017 04:52:12 +0000
Subject: [PATCH 0164/1682] Fix -Wunused-private-field to fire regardless of
 which implicit special members have been implicitly declared.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317076 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Sema/Sema.cpp                          |  3 ++-
 lib/Sema/SemaExprMember.cpp                |  4 +++-
 test/SemaCXX/unused.cpp                    |  2 +-
 test/SemaCXX/warn-unused-private-field.cpp | 17 +++++++++++++++++
 4 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 58bca42677..31400e1de8 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -737,7 +737,8 @@ static bool MethodsAndNestedClassesComplete(const CXXRecordDecl *RD,
                                   E = RD->decls_end();
        I != E && Complete; ++I) {
     if (const CXXMethodDecl *M = dyn_cast(*I))
-      Complete = M->isDefined() || (M->isPure() && !isa(M));
+      Complete = M->isDefined() || M->isDefaulted() ||
+                 (M->isPure() && !isa(M));
     else if (const FunctionTemplateDecl *F = dyn_cast(*I))
       // If the template function is marked as late template parsed at this
       // point, it has not been instantiated and therefore we have not
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index bf4cb53b7d..03ddcc0a3e 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -1791,7 +1791,9 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
       MemberType = Context.getQualifiedType(MemberType, Combined);
   }
 
-  UnusedPrivateFields.remove(Field);
+  auto *CurMethod = dyn_cast(CurContext);
+  if (!(CurMethod && CurMethod->isDefaulted()))
+    UnusedPrivateFields.remove(Field);
 
   ExprResult Base = PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
                                                   FoundDecl, Field);
diff --git a/test/SemaCXX/unused.cpp b/test/SemaCXX/unused.cpp
index ba9ab2363b..abaf611b0d 100644
--- a/test/SemaCXX/unused.cpp
+++ b/test/SemaCXX/unused.cpp
@@ -6,7 +6,7 @@
 // PR4103 : Make sure we don't get a bogus unused expression warning
 namespace PR4103 {
   class APInt {
-    char foo;
+    char foo; // expected-warning {{private field 'foo' is not used}}
   };
   class APSInt : public APInt {
     char bar; // expected-warning {{private field 'bar' is not used}}
diff --git a/test/SemaCXX/warn-unused-private-field.cpp b/test/SemaCXX/warn-unused-private-field.cpp
index fb34fa98ea..fe44122a1d 100644
--- a/test/SemaCXX/warn-unused-private-field.cpp
+++ b/test/SemaCXX/warn-unused-private-field.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -Wunused-private-field -Wused-but-marked-unused -Wno-uninitialized -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -Wunused-private-field -Wused-but-marked-unused -Wno-uninitialized -verify -std=c++17 %s
 
 class NotFullyDefined {
  public:
@@ -246,3 +247,19 @@ namespace pr13543 {
     X x[4]; // no-warning
   };
 }
+
+class implicit_special_member {
+public:
+  static implicit_special_member make() { return implicit_special_member(); }
+
+private:
+  int n; // expected-warning{{private field 'n' is not used}}
+};
+
+class defaulted_special_member {
+public:
+  defaulted_special_member(const defaulted_special_member&) = default;
+
+private:
+  int n; // expected-warning{{private field 'n' is not used}}
+};
-- 
GitLab


From 57f668a2d1cc75d370edbbb5276684b89121ca16 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi 
Date: Wed, 1 Nov 2017 13:47:48 +0000
Subject: [PATCH 0165/1682] Reformat.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317089 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Sema/Sema.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index a156e88da6..0abf0f3258 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1734,7 +1734,7 @@ public:
     NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {}
 
     NameClassification(const IdentifierInfo *Keyword)
-      : Kind(NC_Keyword), Keyword(Keyword) { }
+        : Kind(NC_Keyword), Keyword(Keyword) {}
 
     static NameClassification Error() {
       return NameClassification(NC_Error);
-- 
GitLab


From 3789ad4283ec09df1ed8411abbb227d76e7ef8cb Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi 
Date: Wed, 1 Nov 2017 13:47:55 +0000
Subject: [PATCH 0166/1682] Fix warnings discovered by rL317076.
 [-Wunused-private-field]

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317091 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/Sema/Sema.h | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 0abf0f3258..66328adad6 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1724,7 +1724,6 @@ public:
     ExprResult Expr;
     TemplateName Template;
     ParsedType Type;
-    const IdentifierInfo *Keyword;
 
     explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {}
 
@@ -1733,8 +1732,7 @@ public:
 
     NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {}
 
-    NameClassification(const IdentifierInfo *Keyword)
-        : Kind(NC_Keyword), Keyword(Keyword) {}
+    NameClassification(const IdentifierInfo *Keyword) : Kind(NC_Keyword) {}
 
     static NameClassification Error() {
       return NameClassification(NC_Error);
-- 
GitLab


From ba0893fc83cd0f03803ca0799d7b6f10bc13d128 Mon Sep 17 00:00:00 2001
From: Krasimir Georgiev 
Date: Wed, 1 Nov 2017 18:20:41 +0000
Subject: [PATCH 0167/1682] [clang-format] Make parseUnaryOperator
 non-recursive, NFCI

Summary:
This patch makes the implementation of parseUnaryOperator non-recursive. We had
a problem with a file starting with tens of thousands of +'es and -'es which
caused clang-format to stack overflow.

Reviewers: bkramer

Reviewed By: bkramer

Subscribers: cfe-commits, klimek

Differential Revision: https://reviews.llvm.org/D39498

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317113 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Format/TokenAnnotator.cpp | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 1b22e26600..bc8fef8bda 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -1662,17 +1662,15 @@ private:
   /// \brief Parse unary operator expressions and surround them with fake
   /// parentheses if appropriate.
   void parseUnaryOperator() {
-    if (!Current || Current->isNot(TT_UnaryOperator)) {
-      parse(PrecedenceArrowAndPeriod);
-      return;
+    llvm::SmallVector Tokens;
+    while (Current && Current->is(TT_UnaryOperator)) {
+      Tokens.push_back(Current);
+      next();
     }
-
-    FormatToken *Start = Current;
-    next();
-    parseUnaryOperator();
-
-    // The actual precedence doesn't matter.
-    addFakeParenthesis(Start, prec::Unknown);
+    parse(PrecedenceArrowAndPeriod);
+    for (FormatToken *Token : llvm::reverse(Tokens))
+      // The actual precedence doesn't matter.
+      addFakeParenthesis(Token, prec::Unknown);
   }
 
   void parseConditionalExpr() {
-- 
GitLab


From c3c8524640ffce0427d81f78501f32c3c8a07427 Mon Sep 17 00:00:00 2001
From: Eugene Zelenko 
Date: Wed, 1 Nov 2017 23:09:49 +0000
Subject: [PATCH 0168/1682] [ASTMatchers] Fix some Clang-tidy modernize and
 Include What You Use warnings; other minor fixes (NFC).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317137 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/clang/ASTMatchers/ASTMatchers.h       |  84 +++++++----
 .../clang/ASTMatchers/ASTMatchersInternal.h   | 131 +++++++++++-------
 include/clang/ASTMatchers/Dynamic/Parser.h    |  31 +++--
 include/clang/ASTMatchers/Dynamic/Registry.h  |  16 +--
 lib/ASTMatchers/ASTMatchersInternal.cpp       |  52 +++++--
 lib/ASTMatchers/Dynamic/Marshallers.h         | 102 ++++++++++----
 lib/ASTMatchers/Dynamic/Parser.cpp            |  43 +++---
 lib/ASTMatchers/Dynamic/Registry.cpp          |  48 ++++---
 8 files changed, 327 insertions(+), 180 deletions(-)

diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 766e95cdde..d1a582508a 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -1,4 +1,4 @@
-//===--- ASTMatchers.h - Structural query framework -------------*- C++ -*-===//
+//===- ASTMatchers.h - Structural query framework ---------------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -46,13 +46,48 @@
 #define LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H
 
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclFriend.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/OperationKinds.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/AST/TemplateBase.h"
+#include "clang/AST/TemplateName.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
 #include "clang/ASTMatchers/ASTMatchersInternal.h"
 #include "clang/ASTMatchers/ASTMatchersMacros.h"
+#include "clang/Basic/AttrKinds.h"
+#include "clang/Basic/ExceptionSpecificationType.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/TypeTraits.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/Regex.h"
+#include 
+#include 
 #include 
+#include 
+#include 
+#include 
+#include 
 
 namespace clang {
 namespace ast_matchers {
@@ -78,7 +113,7 @@ public:
   /// \brief Type of mapping from binding identifiers to bound nodes. This type
   /// is an associative container with a key type of \c std::string and a value
   /// type of \c clang::ast_type_traits::DynTypedNode
-  typedef internal::BoundNodesMap::IDToNodeMap IDToNodeMap;
+  using IDToNodeMap = internal::BoundNodesMap::IDToNodeMap;
 
   /// \brief Retrieve mapping from binding identifiers to bound nodes.
   const IDToNodeMap &getMap() const {
@@ -86,13 +121,13 @@ public:
   }
 
 private:
+  friend class internal::BoundNodesTreeBuilder;
+
   /// \brief Create BoundNodes from a pre-filled map of bindings.
   BoundNodes(internal::BoundNodesMap &MyBoundNodes)
       : MyBoundNodes(MyBoundNodes) {}
 
   internal::BoundNodesMap MyBoundNodes;
-
-  friend class internal::BoundNodesTreeBuilder;
 };
 
 /// \brief If the provided matcher matches a node, binds the node to \c ID.
@@ -107,13 +142,13 @@ internal::Matcher id(StringRef ID,
 /// \brief Types of matchers for the top-level classes in the AST class
 /// hierarchy.
 /// @{
-typedef internal::Matcher DeclarationMatcher;
-typedef internal::Matcher StatementMatcher;
-typedef internal::Matcher TypeMatcher;
-typedef internal::Matcher TypeLocMatcher;
-typedef internal::Matcher NestedNameSpecifierMatcher;
-typedef internal::Matcher NestedNameSpecifierLocMatcher;
-typedef internal::Matcher CXXCtorInitializerMatcher;
+using DeclarationMatcher = internal::Matcher;
+using StatementMatcher = internal::Matcher;
+using TypeMatcher = internal::Matcher;
+using TypeLocMatcher = internal::Matcher;
+using NestedNameSpecifierMatcher = internal::Matcher;
+using NestedNameSpecifierLocMatcher = internal::Matcher;
+using CXXCtorInitializerMatcher = internal::Matcher;
 /// @}
 
 /// \brief Matches any node.
@@ -2186,23 +2221,23 @@ const internal::VariadicAllOfMatcher typeLoc;
 /// \c b.
 ///
 /// Usable as: Any Matcher
-const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> eachOf = {
-  internal::DynTypedMatcher::VO_EachOf
-};
+const internal::VariadicOperatorMatcherFunc<
+    2, std::numeric_limits::max()>
+    eachOf = {internal::DynTypedMatcher::VO_EachOf};
 
 /// \brief Matches if any of the given matchers matches.
 ///
 /// Usable as: Any Matcher
-const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> anyOf = {
-  internal::DynTypedMatcher::VO_AnyOf
-};
+const internal::VariadicOperatorMatcherFunc<
+    2, std::numeric_limits::max()>
+    anyOf = {internal::DynTypedMatcher::VO_AnyOf};
 
 /// \brief Matches if all given matchers match.
 ///
 /// Usable as: Any Matcher
-const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> allOf = {
-  internal::DynTypedMatcher::VO_AllOf
-};
+const internal::VariadicOperatorMatcherFunc<
+    2, std::numeric_limits::max()>
+    allOf = {internal::DynTypedMatcher::VO_AllOf};
 
 /// \brief Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
 ///
@@ -4004,7 +4039,6 @@ AST_MATCHER_P(UnaryOperator, hasUnaryOperand,
 /// \code
 /// int a = b ?: 1;
 /// \endcode
-
 AST_POLYMORPHIC_MATCHER_P(hasSourceExpression,
                           AST_POLYMORPHIC_SUPPORTED_TYPES(CastExpr,
                                                           OpaqueValueExpr),
@@ -5677,7 +5711,6 @@ AST_MATCHER_P(ReturnStmt, hasReturnValue, internal::Matcher,
   return false;
 }
 
-
 /// \brief Matches CUDA kernel call expression.
 ///
 /// Example matches,
@@ -5688,7 +5721,6 @@ const internal::VariadicDynCastAllOfMatcher<
   Stmt,
   CUDAKernelCallExpr> cudaKernelCallExpr;
 
-
 /// \brief Matches expressions that resolve to a null pointer constant, such as
 /// GNU's __null, C++11's nullptr, or C's NULL macro.
 ///
@@ -5772,7 +5804,7 @@ AST_MATCHER(NamedDecl, hasExternalFormalLinkage) {
   return Node.hasExternalFormalLinkage();
 }
 
-} // end namespace ast_matchers
-} // end namespace clang
+} // namespace ast_matchers
+} // namespace clang
 
-#endif
+#endif // LLVM_CLANG_ASTMATCHERS_ASTMATCHERS_H
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index cd59bbcaeb..203575e689 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1,4 +1,4 @@
-//===--- ASTMatchersInternal.h - Structural query framework -----*- C++ -*-===//
+//===- ASTMatchersInternal.h - Structural query framework -------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -38,23 +38,42 @@
 #include "clang/AST/ASTTypeTraits.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
+#include "clang/AST/NestedNameSpecifier.h"
 #include "clang/AST/Stmt.h"
-#include "clang/AST/StmtCXX.h"
-#include "clang/AST/StmtObjC.h"
+#include "clang/AST/TemplateName.h"
 #include "clang/AST/Type.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/OperatorKinds.h"
+#include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/None.h"
 #include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/Support/ManagedStatic.h"
+#include 
+#include 
+#include 
+#include 
 #include 
 #include 
+#include 
+#include 
+#include 
 #include 
 
 namespace clang {
+
+class ASTContext;
+
 namespace ast_matchers {
 
 class BoundNodes;
@@ -158,7 +177,7 @@ public:
   /// Note that we're using std::map here, as for memoization:
   /// - we need a comparison operator
   /// - we need an assignment operator
-  typedef std::map IDToNodeMap;
+  using IDToNodeMap = std::map;
 
   const IDToNodeMap &getMap() const {
     return NodeMap;
@@ -188,7 +207,7 @@ public:
   /// BoundNodesTree.
   class Visitor {
   public:
-    virtual ~Visitor() {}
+    virtual ~Visitor() = default;
 
     /// \brief Called multiple times during a single call to VisitMatches(...).
     ///
@@ -248,7 +267,7 @@ class ASTMatchFinder;
 class DynMatcherInterface
     : public llvm::ThreadSafeRefCountedBase {
 public:
-  virtual ~DynMatcherInterface() {}
+  virtual ~DynMatcherInterface() = default;
 
   /// \brief Returns true if \p DynNode can be matched.
   ///
@@ -317,26 +336,29 @@ public:
   /// \brief Takes ownership of the provided implementation pointer.
   template 
   DynTypedMatcher(MatcherInterface *Implementation)
-      : AllowBind(false),
-        SupportedKind(ast_type_traits::ASTNodeKind::getFromNodeKind()),
+      : SupportedKind(ast_type_traits::ASTNodeKind::getFromNodeKind()),
         RestrictKind(SupportedKind), Implementation(Implementation) {}
 
   /// \brief Construct from a variadic function.
   enum VariadicOperator {
     /// \brief Matches nodes for which all provided matchers match.
     VO_AllOf,
+
     /// \brief Matches nodes for which at least one of the provided matchers
     /// matches.
     VO_AnyOf,
+
     /// \brief Matches nodes for which at least one of the provided matchers
     /// matches, but doesn't stop at the first match.
     VO_EachOf,
+
     /// \brief Matches nodes that do not match the provided matcher.
     ///
     /// Uses the variadic matcher interface, but fails if
     /// InnerMatchers.size() != 1.
     VO_UnaryNot
   };
+
   static DynTypedMatcher
   constructVariadic(VariadicOperator Op,
                     ast_type_traits::ASTNodeKind SupportedKind,
@@ -382,7 +404,7 @@ public:
   /// include both in the ID to make it unique.
   ///
   /// \c MatcherIDType supports operator< and provides strict weak ordering.
-  typedef std::pair MatcherIDType;
+  using MatcherIDType = std::pair;
   MatcherIDType getID() const {
     /// FIXME: Document the requirements this imposes on matcher
     /// implementations (no new() implementation_ during a Matches()).
@@ -428,13 +450,12 @@ private:
  DynTypedMatcher(ast_type_traits::ASTNodeKind SupportedKind,
                  ast_type_traits::ASTNodeKind RestrictKind,
                  IntrusiveRefCntPtr Implementation)
-     : AllowBind(false),
-       SupportedKind(SupportedKind),
-       RestrictKind(RestrictKind),
+     : SupportedKind(SupportedKind), RestrictKind(RestrictKind),
        Implementation(std::move(Implementation)) {}
 
-  bool AllowBind;
+  bool AllowBind = false;
   ast_type_traits::ASTNodeKind SupportedKind;
+
   /// \brief A potentially stricter node kind.
   ///
   /// It allows to perform implicit and dynamic cast of matchers without
@@ -545,6 +566,7 @@ public:
 private:
   // For Matcher <=> Matcher conversions.
   template  friend class Matcher;
+
   // For DynTypedMatcher::unconditionalConvertTo.
   friend class DynTypedMatcher;
 
@@ -618,8 +640,8 @@ bool matchesFirstInPointerRange(const MatcherT &Matcher, IteratorT Start,
 // Metafunction to determine if type T has a member called getDecl.
 template 
 class has_getDecl {
-  typedef char yes[1];
-  typedef char no[2];
+  using yes = char[1];
+  using no = char[2];
 
   template 
   static yes& test(Inner *I, decltype(I->getDecl()) * = nullptr);
@@ -741,7 +763,6 @@ private:
   /// matcher matches on it.
   bool matchesSpecialized(const Type &Node, ASTMatchFinder *Finder,
                           BoundNodesTreeBuilder *Builder) const {
-
     // DeducedType does not have declarations of its own, so
     // match the deduced type instead.
     const Type *EffectiveType = &Node;
@@ -917,6 +938,7 @@ public:
   enum TraversalKind {
     /// Will traverse any child nodes.
     TK_AsIs,
+
     /// Will not traverse implicit casts and parentheses.
     TK_IgnoreImplicitCastsAndParentheses
   };
@@ -925,6 +947,7 @@ public:
   enum BindKind {
     /// Stop at the first match and only bind the first match.
     BK_First,
+
     /// Create results for all combinations of bindings that match.
     BK_All
   };
@@ -933,11 +956,12 @@ public:
   enum AncestorMatchMode {
     /// All ancestors.
     AMM_All,
+
     /// Direct parent only.
     AMM_ParentOnly
   };
 
-  virtual ~ASTMatchFinder() {}
+  virtual ~ASTMatchFinder() = default;
 
   /// \brief Returns true if the given class is directly or indirectly derived
   /// from a base type matching \c base.
@@ -960,7 +984,7 @@ public:
                   std::is_base_of::value ||
                   std::is_base_of::value,
                   "unsupported type for recursive matching");
-   return matchesChildOf(ast_type_traits::DynTypedNode::create(Node),
+    return matchesChildOf(ast_type_traits::DynTypedNode::create(Node),
                           Matcher, Builder, Traverse, Bind);
   }
 
@@ -1023,17 +1047,17 @@ template  struct TypeList {}; // Empty sentinel type list.
 
 template  struct TypeList {
   /// \brief The first type on the list.
-  typedef T1 head;
+  using head = T1;
 
   /// \brief A sublist with the tail. ie everything but the head.
   ///
   /// This type is used to do recursion. TypeList<>/EmptyTypeList indicates the
   /// end of the list.
-  typedef TypeList tail;
+  using tail = TypeList;
 };
 
 /// \brief The empty type list.
-typedef TypeList<> EmptyTypeList;
+using EmptyTypeList = TypeList<>;
 
 /// \brief Helper meta-function to determine if some type \c T is present or
 ///   a parent type in the list.
@@ -1051,8 +1075,9 @@ struct TypeListContainsSuperOf {
 /// \brief A "type list" that contains all types.
 ///
 /// Useful for matchers like \c anything and \c unless.
-typedef TypeList AllNodeBaseTypes;
+using AllNodeBaseTypes =
+    TypeList;
 
 /// \brief Helper meta-function to extract the argument out of a function of
 ///   type void(Arg).
@@ -1060,21 +1085,22 @@ typedef TypeList struct ExtractFunctionArgMeta;
 template  struct ExtractFunctionArgMeta {
-  typedef T type;
+  using type = T;
 };
 
 /// \brief Default type lists for ArgumentAdaptingMatcher matchers.
-typedef AllNodeBaseTypes AdaptativeDefaultFromTypes;
-typedef TypeList AdaptativeDefaultToTypes;
+using AdaptativeDefaultFromTypes = AllNodeBaseTypes;
+using AdaptativeDefaultToTypes =
+    TypeList;
 
 /// \brief All types that are supported by HasDeclarationMatcher above.
-typedef TypeList
-    HasDeclarationSupportedTypes;
+using HasDeclarationSupportedTypes =
+    TypeList;
 
 /// \brief Converts a \c Matcher to a matcher of desired type \c To by
 /// "adapting" a \c To into a \c T.
@@ -1098,7 +1124,7 @@ struct ArgumentAdaptingMatcherFunc {
     explicit Adaptor(const Matcher &InnerMatcher)
         : InnerMatcher(InnerMatcher) {}
 
-    typedef ToTypes ReturnTypes;
+    using ReturnTypes = ToTypes;
 
     template  operator Matcher() const {
       return Matcher(new ArgumentAdapterT(InnerMatcher));
@@ -1135,7 +1161,8 @@ template