[clang] [llvm] [clang] Support per-function [[clang::code_align(N)]] attribute. (PR #80765)
AntonBikineev wrote: > I am not sure a case where people care for specific functions and want > annotating them. Our (V8 and Chromium) use case is that we know some hot functions that suffer from misaligned jumps. These functions would ideally be annotated with the attribute. We don't want to use the option for the entire binary as it'd significantly increase the binary size. The alternative would be moving those functions into a separate TU(s), but it's just cumbersome. https://github.com/llvm/llvm-project/pull/80765 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [llvm] [clang] Support per-function [[clang::code_align(N)]] attribute. (PR #80765)
AntonBikineev wrote: > Aligning the targets of branches is a different thing from what you've > implemented. There are basic blocks which are not branch targets, and there > are branch targets which are not at the beginning of a basic block. (Branch > targets that aren't at the beginning of a basic block are rare on most > targets, but it doesn't seem like something we should completely ignore.) That makes sense, thanks. Would there be an interest in something like [[clang::x86_align_branch_boundary]] that would align branch instructions per function? https://github.com/llvm/llvm-project/pull/80765 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[llvm] [clang] [clang] Support per-function [[clang::code_align(N)]] attribute. (PR #80765)
https://github.com/AntonBikineev updated https://github.com/llvm/llvm-project/pull/80765 >From 88151098d3087f95d3a5b652309a12fb2e9f757e Mon Sep 17 00:00:00 2001 From: Anton Bikineev Date: Mon, 5 Feb 2024 12:24:17 +0100 Subject: [PATCH] [clang] Support per-function [[clang::code_align(N)]] attribute. The existing attribute works only for loop headers. This can unfortunately be quite limiting, especially as a protection against the "Jump Conditional Code Erratum" [0] (for example, if there is an unaligned check in a hot loop). The command line option -malign-branch-boundary can help with that, but it's too coarse-grained and can significantly increase the binary size. This change introduces a per-function [[clang::code_align(N)]] attribute that aligns all the basic blocks of a function by the given N. [0] https://www.intel.com/content/dam/support/us/en/documents/processors/mitigations-jump-conditional-code-erratum.pdf --- clang/include/clang/Basic/Attr.td | 7 ++-- clang/include/clang/Basic/AttrDocs.td | 16 --- clang/lib/CodeGen/CodeGenModule.cpp | 6 +++ clang/lib/Sema/SemaDeclAttr.cpp | 10 + clang/test/CodeGen/code_align_function.c | 42 +++ ...a-attribute-supported-attributes-list.test | 1 + clang/test/Sema/code_align.c | 14 ++- llvm/lib/CodeGen/MachineBlockPlacement.cpp| 28 ++--- .../CodeGen/X86/code-align-basic-blocks.ll| 29 + 9 files changed, 137 insertions(+), 16 deletions(-) create mode 100644 clang/test/CodeGen/code_align_function.c create mode 100644 llvm/test/CodeGen/X86/code-align-basic-blocks.ll diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index b2d5309e142c1..abce685e9f7a6 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4435,10 +4435,11 @@ def PreferredType: InheritableAttr { let Documentation = [PreferredTypeDocumentation]; } -def CodeAlign: StmtAttr { +def CodeAlign : InheritableAttr { let Spellings = [Clang<"code_align">]; - let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt], - ErrorDiag, "'for', 'while', and 'do' statements">; + let Subjects = + SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt, Function], + ErrorDiag, "'for', 'while', 'do' statements and functions">; let Args = [ExprArgument<"Alignment">]; let Documentation = [CodeAlignAttrDocs]; let AdditionalMembers = [{ diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 041786f37fb8a..57b63469f1573 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -7704,11 +7704,12 @@ def CodeAlignAttrDocs : Documentation { let Category = DocCatVariable; let Heading = "clang::code_align"; let Content = [{ -The ``clang::code_align(N)`` attribute applies to a loop and specifies the byte -alignment for a loop. The attribute accepts a positive integer constant -initialization expression indicating the number of bytes for the minimum -alignment boundary. Its value must be a power of 2, between 1 and 4096 -(inclusive). +The ``clang::code_align(N)`` attribute applies to a loop or a function. When +applied to a loop it specifies the byte alignment for the loop header. When +applied to a function it aligns all the basic blocks of the function. The +attribute accepts a positive integer constant initialization expression +indicating the number of bytes for the minimum alignment boundary. Its value +must be a power of 2, between 1 and 4096 (inclusive). .. code-block:: c++ @@ -7738,6 +7739,11 @@ alignment boundary. Its value must be a power of 2, between 1 and 4096 [[clang::code_align(A)]] for(;;) { } } + [[clang:code_align(16)]] int foo(bool b) { +if (b) return 2; +return 3; + } + }]; } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 36b63d78b06f8..87a822e91fff6 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2515,6 +2515,12 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, F->setAlignment(std::max(llvm::Align(2), F->getAlign().valueOrOne())); } + if (const auto *CodeAlign = D->getAttr()) { +const auto *CE = cast(CodeAlign->getAlignment()); +std::string ArgValStr = llvm::toString(CE->getResultAsAPSInt(), 10); +F->addFnAttr("align-basic-blocks", ArgValStr); + } + // In the cross-dso CFI mode with canonical jump tables, we want !type // attributes on definitions only. if (CodeGenOpts.SanitizeCfiCrossDso && diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index d785714c4d811..40412801b632a 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -9036,6 +9036,12 @@ static void handleArmNewAttr(Sema ,
[llvm] [clang] [clang] Support per-function [[clang::code_align(N)]] attribute. (PR #80765)
https://github.com/AntonBikineev updated https://github.com/llvm/llvm-project/pull/80765 >From 99d2cc55fb952361b1fe04e2c21dcb5b04f11d47 Mon Sep 17 00:00:00 2001 From: Anton Bikineev Date: Mon, 5 Feb 2024 12:24:17 +0100 Subject: [PATCH] [clang] Support per-function [[clang::code_align(N)]] attribute. The existing attribute works only for loop headers. This can unfortunately be quite limiting, especially as a protection against the "Jump Conditional Code Erratum" [0] (for example, if there is an unaligned check in a hot loop). The command line option -malign-branch-boundary can help with that, but it's too coarse-grained and can significantly increase the binary size. This change introduces a per-function [[clang::code_align(N)]] attribute that aligns all the basic blocks of a function by the given N. [0] https://www.intel.com/content/dam/support/us/en/documents/processors/mitigations-jump-conditional-code-erratum.pdf --- clang/include/clang/Basic/Attr.td | 7 ++-- clang/include/clang/Basic/AttrDocs.td | 16 --- clang/lib/CodeGen/CodeGenModule.cpp | 6 +++ clang/lib/Sema/SemaDeclAttr.cpp | 10 + clang/test/CodeGen/code_align_function.c | 42 +++ clang/test/Sema/code_align.c | 14 ++- llvm/lib/CodeGen/MachineBlockPlacement.cpp| 28 ++--- .../CodeGen/X86/code-align-basic-blocks.ll| 29 + 8 files changed, 136 insertions(+), 16 deletions(-) create mode 100644 clang/test/CodeGen/code_align_function.c create mode 100644 llvm/test/CodeGen/X86/code-align-basic-blocks.ll diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index b2d5309e142c1a..abce685e9f7a64 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4435,10 +4435,11 @@ def PreferredType: InheritableAttr { let Documentation = [PreferredTypeDocumentation]; } -def CodeAlign: StmtAttr { +def CodeAlign : InheritableAttr { let Spellings = [Clang<"code_align">]; - let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt], - ErrorDiag, "'for', 'while', and 'do' statements">; + let Subjects = + SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt, Function], + ErrorDiag, "'for', 'while', 'do' statements and functions">; let Args = [ExprArgument<"Alignment">]; let Documentation = [CodeAlignAttrDocs]; let AdditionalMembers = [{ diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 041786f37fb8a7..57b63469f1573f 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -7704,11 +7704,12 @@ def CodeAlignAttrDocs : Documentation { let Category = DocCatVariable; let Heading = "clang::code_align"; let Content = [{ -The ``clang::code_align(N)`` attribute applies to a loop and specifies the byte -alignment for a loop. The attribute accepts a positive integer constant -initialization expression indicating the number of bytes for the minimum -alignment boundary. Its value must be a power of 2, between 1 and 4096 -(inclusive). +The ``clang::code_align(N)`` attribute applies to a loop or a function. When +applied to a loop it specifies the byte alignment for the loop header. When +applied to a function it aligns all the basic blocks of the function. The +attribute accepts a positive integer constant initialization expression +indicating the number of bytes for the minimum alignment boundary. Its value +must be a power of 2, between 1 and 4096 (inclusive). .. code-block:: c++ @@ -7738,6 +7739,11 @@ alignment boundary. Its value must be a power of 2, between 1 and 4096 [[clang::code_align(A)]] for(;;) { } } + [[clang:code_align(16)]] int foo(bool b) { +if (b) return 2; +return 3; + } + }]; } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 36b63d78b06f83..87a822e91fff61 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2515,6 +2515,12 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, F->setAlignment(std::max(llvm::Align(2), F->getAlign().valueOrOne())); } + if (const auto *CodeAlign = D->getAttr()) { +const auto *CE = cast(CodeAlign->getAlignment()); +std::string ArgValStr = llvm::toString(CE->getResultAsAPSInt(), 10); +F->addFnAttr("align-basic-blocks", ArgValStr); + } + // In the cross-dso CFI mode with canonical jump tables, we want !type // attributes on definitions only. if (CodeGenOpts.SanitizeCfiCrossDso && diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index d785714c4d811e..40412801b632ae 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -9036,6 +9036,12 @@ static void handleArmNewAttr(Sema , Decl *D, const ParsedAttr ) {
[llvm] [clang] [clang] Support per-function [[clang::code_align(N)]] attribute. (PR #80765)
https://github.com/AntonBikineev created https://github.com/llvm/llvm-project/pull/80765 The existing attribute works only for loop headers. This can unfortunately be quite limiting, especially as a protection against the "Jump Conditional Code Erratum" [0] (for example, if there is an unaligned check in a hot loop). The command line option -malign-branch-boundary can help with that, but it's too coarse-grained and can significantly increase the binary size. This change introduces a per-function [[clang::code_align(N)]] attribute that aligns all the basic blocks of a function by the given N. [0] https://www.intel.com/content/dam/support/us/en/documents/processors/mitigations-jump-conditional-code-erratum.pdf >From ff8cf4e87473dec2e3f55114cb92ae5a63d9488c Mon Sep 17 00:00:00 2001 From: Anton Bikineev Date: Mon, 5 Feb 2024 12:24:17 +0100 Subject: [PATCH] [clang] Support per-function [[clang::code_align(N)]] attribute. The existing attribute works only for loop headers. This can unfortunately be quite limiting, especially as a protection against the "Jump Conditional Code Erratum" [0] (for example, if there is an unaligned check in a hot loop). The command line option -malign-branch-boundary can help with that, but it's too coarse-grained and can significantly increase the binary size. This change introduces a per-function [[clang::code_align(N)]] attribute that aligns all the basic blocks of a function by the given N. [0] https://www.intel.com/content/dam/support/us/en/documents/processors/mitigations-jump-conditional-code-erratum.pdf --- clang/include/clang/Basic/Attr.td | 7 ++-- clang/include/clang/Basic/AttrDocs.td | 16 --- clang/lib/CodeGen/CodeGenModule.cpp | 6 +++ clang/lib/Sema/SemaDeclAttr.cpp | 10 + clang/test/CodeGen/code_align_function.c | 42 +++ clang/test/Sema/code_align.c | 14 ++- llvm/lib/CodeGen/MachineBlockPlacement.cpp| 27 +--- .../CodeGen/X86/code-align-basic-blocks.ll| 29 + 8 files changed, 135 insertions(+), 16 deletions(-) create mode 100644 clang/test/CodeGen/code_align_function.c create mode 100644 llvm/test/CodeGen/X86/code-align-basic-blocks.ll diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index b2d5309e142c1..abce685e9f7a6 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -4435,10 +4435,11 @@ def PreferredType: InheritableAttr { let Documentation = [PreferredTypeDocumentation]; } -def CodeAlign: StmtAttr { +def CodeAlign : InheritableAttr { let Spellings = [Clang<"code_align">]; - let Subjects = SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt], - ErrorDiag, "'for', 'while', and 'do' statements">; + let Subjects = + SubjectList<[ForStmt, CXXForRangeStmt, WhileStmt, DoStmt, Function], + ErrorDiag, "'for', 'while', 'do' statements and functions">; let Args = [ExprArgument<"Alignment">]; let Documentation = [CodeAlignAttrDocs]; let AdditionalMembers = [{ diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 041786f37fb8a..57b63469f1573 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -7704,11 +7704,12 @@ def CodeAlignAttrDocs : Documentation { let Category = DocCatVariable; let Heading = "clang::code_align"; let Content = [{ -The ``clang::code_align(N)`` attribute applies to a loop and specifies the byte -alignment for a loop. The attribute accepts a positive integer constant -initialization expression indicating the number of bytes for the minimum -alignment boundary. Its value must be a power of 2, between 1 and 4096 -(inclusive). +The ``clang::code_align(N)`` attribute applies to a loop or a function. When +applied to a loop it specifies the byte alignment for the loop header. When +applied to a function it aligns all the basic blocks of the function. The +attribute accepts a positive integer constant initialization expression +indicating the number of bytes for the minimum alignment boundary. Its value +must be a power of 2, between 1 and 4096 (inclusive). .. code-block:: c++ @@ -7738,6 +7739,11 @@ alignment boundary. Its value must be a power of 2, between 1 and 4096 [[clang::code_align(A)]] for(;;) { } } + [[clang:code_align(16)]] int foo(bool b) { +if (b) return 2; +return 3; + } + }]; } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 36b63d78b06f8..87a822e91fff6 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2515,6 +2515,12 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, F->setAlignment(std::max(llvm::Align(2), F->getAlign().valueOrOne())); } + if (const auto *CodeAlign = D->getAttr()) { +const auto
[clang] 7b85e76 - [PGO] Consider parent context when weighing branches with likelyhood.
Author: Anton Bikineev Date: 2022-10-08T23:49:27+02:00 New Revision: 7b85e765000df36fcc6a5191dec9a28f444245ba URL: https://github.com/llvm/llvm-project/commit/7b85e765000df36fcc6a5191dec9a28f444245ba DIFF: https://github.com/llvm/llvm-project/commit/7b85e765000df36fcc6a5191dec9a28f444245ba.diff LOG: [PGO] Consider parent context when weighing branches with likelyhood. Generally, with PGO enabled the C++20 likelyhood attributes shall be dropped assuming the profile has a good coverage. However, currently this is not the case for the following code: if (always_false()) [[likely]] { ... } The patch fixes this and drops the attribute, if the parent context was executed in the profile. The patch still preserves the attribute, if the parent context was not executed, e.g. to support the cases when the profile has insufficient coverage. Differential Revision: https://reviews.llvm.org/D134456 Added: clang/test/Profile/Inputs/cxx-never-executed-branch.proftext clang/test/Profile/cxx-never-executed-branch.cpp Modified: clang/lib/CodeGen/CGStmt.cpp Removed: diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 9935fcc0d3ea2..ebbc79cc8b4b6 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -815,11 +815,20 @@ void CodeGenFunction::EmitIfStmt(const IfStmt ) { // Prefer the PGO based weights over the likelihood attribute. // When the build isn't optimized the metadata isn't used, so don't generate // it. + // Also, diff erentiate between disabled PGO and a never executed branch with + // PGO. Assuming PGO is in use: + // - we want to ignore the [[likely]] attribute if the branch is never + // executed, + // - assuming the profile is poor, preserving the attribute may still be + // beneficial. + // As an approximation, preserve the attribute only if both the branch and the + // parent context were not executed. Stmt::Likelihood LH = Stmt::LH_None; - uint64_t Count = getProfileCount(S.getThen()); - if (!Count && CGM.getCodeGenOpts().OptimizationLevel) + uint64_t ThenCount = getProfileCount(S.getThen()); + if (!ThenCount && !getCurrentProfileCount() && + CGM.getCodeGenOpts().OptimizationLevel) LH = Stmt::getLikelihood(S.getThen(), S.getElse()); - EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, Count, LH); + EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock, ThenCount, LH); // Emit the 'then' code. EmitBlock(ThenBlock); diff --git a/clang/test/Profile/Inputs/cxx-never-executed-branch.proftext b/clang/test/Profile/Inputs/cxx-never-executed-branch.proftext new file mode 100644 index 0..64a55b3e52b37 --- /dev/null +++ b/clang/test/Profile/Inputs/cxx-never-executed-branch.proftext @@ -0,0 +1,13 @@ +_Z13is_in_profilev +0x00029f493458 +2 +2 +# The branch is never executed. +0 + +_Z17is_not_in_profilev +0x00029f493458 +2 +# The function was never executed +0 +0 diff --git a/clang/test/Profile/cxx-never-executed-branch.cpp b/clang/test/Profile/cxx-never-executed-branch.cpp new file mode 100644 index 0..812f65f3996d3 --- /dev/null +++ b/clang/test/Profile/cxx-never-executed-branch.cpp @@ -0,0 +1,32 @@ +// Test that clang doesn't emit llvm.expect when the counter is 0 + +// RUN: llvm-profdata merge %S/Inputs/cxx-never-executed-branch.proftext -o %t.profdata +// RUN: %clang_cc1 -std=c++20 %s -triple %itanium_abi_triple -O2 -o - -emit-llvm -fprofile-instrument-use-path=%t.profdata -disable-llvm-passes | FileCheck %s + +int rand(); + +// CHECK: define {{.*}}@_Z13is_in_profilev +// CHECK-NOT: call {{.*}}@llvm.expect + +int is_in_profile() { + int rando = rand(); + int x = 0; + if (rando == 0) [[likely]] +x = 2; + else +x = 3; + return x; +} + +// CHECK: define {{.*}}@_Z17is_not_in_profilev +// CHECK: call {{.*}}@llvm.expect + +int is_not_in_profile() { + int rando = rand(); + int x = 0; + if (rando == 0) [[likely]] +x = 2; + else +x = 3; + return x; +} ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] 6954515 - [Sema] Move 'char-expression-as-unsigned < 0' into a separate diagnostic
Author: Anton Bikineev Date: 2021-04-14T01:01:40+02:00 New Revision: 69545154cc28a0a7f813174253c6cb428666eb3a URL: https://github.com/llvm/llvm-project/commit/69545154cc28a0a7f813174253c6cb428666eb3a DIFF: https://github.com/llvm/llvm-project/commit/69545154cc28a0a7f813174253c6cb428666eb3a.diff LOG: [Sema] Move 'char-expression-as-unsigned < 0' into a separate diagnostic This change splits '-Wtautological-unsigned-zero-compare' by reporting char-expressions-interpreted-as-unsigned under a separate diagnostic '-Wtautological-unsigned-char-zero-compare'. This is beneficial for projects that want to enable '-Wtautological-unsigned-zero-compare' but at the same time want to keep code portable for platforms with char being signed or unsigned, such as Chromium. Differential Revision: https://reviews.llvm.org/D99808 Added: clang/test/Sema/tautological-unsigned-char-zero-compare.cc Modified: clang/include/clang/Basic/DiagnosticGroups.td clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Sema/SemaChecking.cpp Removed: diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 85f798013a3d..e202645d1f2b 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -591,11 +591,13 @@ def SwiftNameAttribute : DiagGroup<"swift-name-attribute">; def IntInBoolContext : DiagGroup<"int-in-bool-context">; def TautologicalTypeLimitCompare : DiagGroup<"tautological-type-limit-compare">; def TautologicalUnsignedZeroCompare : DiagGroup<"tautological-unsigned-zero-compare">; +def TautologicalUnsignedCharZeroCompare : DiagGroup<"tautological-unsigned-char-zero-compare">; def TautologicalUnsignedEnumZeroCompare : DiagGroup<"tautological-unsigned-enum-zero-compare">; // For compatibility with GCC. Tautological comparison warnings for constants // that are an extremal value of the type. def TypeLimits : DiagGroup<"type-limits", [TautologicalTypeLimitCompare, TautologicalUnsignedZeroCompare, + TautologicalUnsignedCharZeroCompare, TautologicalUnsignedEnumZeroCompare]>; // Additional tautological comparison warnings based on the expression, not // only on its type. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index af7eea06f6f5..afef86ab5890 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6784,6 +6784,10 @@ def warn_unsigned_always_true_comparison : Warning< "result of comparison of %select{%3|unsigned expression}0 %2 " "%select{unsigned expression|%3}0 is always %4">, InGroup, DefaultIgnore; +def warn_unsigned_char_always_true_comparison : Warning< + "result of comparison of %select{%3|char expression}0 %2 " + "%select{char expression|%3}0 is always %4, since char is interpreted as " + "unsigned">, InGroup, DefaultIgnore; def warn_unsigned_enum_always_true_comparison : Warning< "result of comparison of %select{%3|unsigned enum expression}0 %2 " "%select{unsigned enum expression|%3}0 is always %4">, diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index fa5e184d2864..7b6e0541aa4d 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -11446,11 +11446,14 @@ static bool CheckTautologicalComparison(Sema , BinaryOperator *E, << OtherIsBooleanDespiteType << *Result << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange()); } else { -unsigned Diag = (isKnownToHaveUnsignedValue(OriginalOther) && Value == 0) -? (HasEnumType(OriginalOther) - ? diag::warn_unsigned_enum_always_true_comparison - : diag::warn_unsigned_always_true_comparison) -: diag::warn_tautological_constant_compare; +bool IsCharTy = OtherT.withoutLocalFastQualifiers() == S.Context.CharTy; +unsigned Diag = +(isKnownToHaveUnsignedValue(OriginalOther) && Value == 0) +? (HasEnumType(OriginalOther) + ? diag::warn_unsigned_enum_always_true_comparison + : IsCharTy ? diag::warn_unsigned_char_always_true_comparison + : diag::warn_unsigned_always_true_comparison) +: diag::warn_tautological_constant_compare; S.Diag(E->getOperatorLoc(), Diag) << RhsConstant << OtherT << E->getOpcodeStr() << OS.str() << *Result diff --git a/clang/test/Sema/tautological-unsigned-char-zero-compare.cc b/clang/test/Sema/tautological-unsigned-char-zero-compare.cc new file mode 100644 index ..4d14954b3213 --- /dev/null +++
[clang] dc7ebd2 - [C++2b] Support size_t literals
Author: Anton Bikineev Date: 2021-03-31T13:36:23Z New Revision: dc7ebd2cb0cf4a83bb6cd1bfc8853b0a30054777 URL: https://github.com/llvm/llvm-project/commit/dc7ebd2cb0cf4a83bb6cd1bfc8853b0a30054777 DIFF: https://github.com/llvm/llvm-project/commit/dc7ebd2cb0cf4a83bb6cd1bfc8853b0a30054777.diff LOG: [C++2b] Support size_t literals This adds support for C++2b's z/uz suffixes for size_t literals (P0330). Added: clang/test/Lexer/size_t-literal.cpp clang/test/SemaCXX/size_t-literal.cpp Modified: clang/include/clang/Basic/DiagnosticCommonKinds.td clang/include/clang/Lex/LiteralSupport.h clang/lib/Frontend/InitPreprocessor.cpp clang/lib/Lex/LiteralSupport.cpp clang/lib/Lex/PPExpressions.cpp clang/lib/Sema/SemaExpr.cpp clang/test/Lexer/cxx-features.cpp clang/test/SemaCXX/cxx1y-user-defined-literals.cpp clang/www/cxx_status.html Removed: diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index a237d492de201..eab8206b104dc 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -187,6 +187,17 @@ def ext_cxx11_longlong : Extension< def warn_cxx98_compat_longlong : Warning< "'long long' is incompatible with C++98">, InGroup, DefaultIgnore; +def ext_cxx2b_size_t_suffix : ExtWarn< + "'size_t' suffix for literals is a C++2b extension">, + InGroup; +def warn_cxx20_compat_size_t_suffix : Warning< + "'size_t' suffix for literals is incompatible with C++ standards before " + "C++2b">, InGroup, DefaultIgnore; +def err_cxx2b_size_t_suffix: Error< + "'size_t' suffix for literals is a C++2b feature">; +def err_size_t_literal_too_large: Error< + "%select{signed |}0'size_t' literal is out of range of possible " + "%select{signed |}0'size_t' values">; def err_integer_literal_too_large : Error< "integer literal is too large to be represented in any %select{signed |}0" "integer type">; diff --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h index 0c4f0fe277b7c..f131f045a73ea 100644 --- a/clang/include/clang/Lex/LiteralSupport.h +++ b/clang/include/clang/Lex/LiteralSupport.h @@ -63,6 +63,7 @@ class NumericLiteralParser { bool isUnsigned : 1; bool isLong : 1; // This is *not* set for long long. bool isLongLong : 1; + bool isSizeT : 1; // 1z, 1uz (C++2b) bool isHalf : 1; // 1.0h bool isFloat : 1; // 1.0f bool isImaginary : 1; // 1.0i diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 15f254515822b..3d69c59d166d0 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -589,6 +589,9 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions , //Builder.defineMacro("__cpp_modules", "201907L"); //Builder.defineMacro("__cpp_using_enum", "201907L"); } + // C++2b features. + if (LangOpts.CPlusPlus2b) +Builder.defineMacro("__cpp_size_t_suffix", "202011L"); if (LangOpts.Char8) Builder.defineMacro("__cpp_char8_t", "201811L"); Builder.defineMacro("__cpp_impl_destroying_delete", "201806L"); diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp index df98516ee61d1..bfcb3c478b62d 100644 --- a/clang/lib/Lex/LiteralSupport.cpp +++ b/clang/lib/Lex/LiteralSupport.cpp @@ -546,6 +546,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, isLong = false; isUnsigned = false; isLongLong = false; + isSizeT = false; isHalf = false; isFloat = false; isImaginary = false; @@ -589,6 +590,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, // integer constant. bool isFixedPointConstant = isFixedPointLiteral(); bool isFPConstant = isFloatingLiteral(); + bool HasSize = false; // Loop over all of the characters of the suffix. If we see something bad, // we break out of the loop. @@ -616,14 +618,17 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, if (!(LangOpts.Half || LangOpts.FixedPoint)) break; if (isIntegerLiteral()) break; // Error for integer constant. - if (isHalf || isFloat || isLong) break; // HH, FH, LH invalid. + if (HasSize) +break; + HasSize = true; isHalf = true; continue; // Success. case 'f': // FP Suffix for "float" case 'F': if (!isFPConstant) break; // Error for integer constant. - if (isHalf || isFloat || isLong || isFloat128) -break; // HF, FF, LF, QF invalid. + if (HasSize) +break; + HasSize = true; // CUDA host and device may have diff erent _Float16 support, therefore // allows f16 literals to avoid false alarm. @@ -640,8 +645,9 @@
[clang] 4f8e299 - [Sema] Fix diagnostics for one-byte length modifier
Author: Anton Bikineev Date: 2021-03-09T16:56:20+01:00 New Revision: 4f8e299785e860cf974d696d7ca83b70a94977fe URL: https://github.com/llvm/llvm-project/commit/4f8e299785e860cf974d696d7ca83b70a94977fe DIFF: https://github.com/llvm/llvm-project/commit/4f8e299785e860cf974d696d7ca83b70a94977fe.diff LOG: [Sema] Fix diagnostics for one-byte length modifier In case a char-literal of type int (C/ObjectiveC) corresponds to a format specifier with the %hh length modifier, don't treat the literal as of type char for issuing diagnostics, as otherwise this results in: printf("%hhd", 'e'); warning: format specifies type 'char' but the argument has type 'char'. Differential revision: https://reviews.llvm.org/D97951 Added: Modified: clang/lib/Sema/SemaChecking.cpp clang/test/FixIt/format.m Removed: diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index fef6a9306eaf..e390159a8f64 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -8730,8 +8730,11 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier , } else if (const CharacterLiteral *CL = dyn_cast(E)) { // Special case for 'a', which has type 'int' in C. // Note, however, that we do /not/ want to treat multibyte constants like -// 'MooV' as characters! This form is deprecated but still exists. -if (ExprTy == S.Context.IntTy) +// 'MooV' as characters! This form is deprecated but still exists. In +// addition, don't treat expressions as of type 'char' if one byte length +// modifier is provided. +if (ExprTy == S.Context.IntTy && +FS.getLengthModifier().getKind() != LengthModifier::AsChar) if (llvm::isUIntN(S.Context.getCharWidth(), CL->getValue())) ExprTy = S.Context.CharTy; } diff --git a/clang/test/FixIt/format.m b/clang/test/FixIt/format.m index ef27b1bac353..0d173846d0ad 100644 --- a/clang/test/FixIt/format.m +++ b/clang/test/FixIt/format.m @@ -169,6 +169,12 @@ void test_char(char c, signed char s, unsigned char u, uint8_t n) { NSLog(@"%@", 'abcd'); // expected-warning{{format specifies type 'id' but the argument has type 'int'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d" + + NSLog(@"%hhd", 'a'); // expected-warning{{format specifies type 'char' but the argument has type 'int'}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:15}:"%d" + + NSLog(@"%hhu", 'a'); // expected-warning{{format specifies type 'unsigned char' but the argument has type 'int'}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:15}:"%d" } void multichar_constants_false_negative() { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang-tools-extra] d36a033 - [clang-tidy] New checker performance-trivially-destructible-check
Author: Anton Bikineev Date: 2019-11-01T16:16:49+01:00 New Revision: d36a0333102698a1398971d0717465322b1c5c2c URL: https://github.com/llvm/llvm-project/commit/d36a0333102698a1398971d0717465322b1c5c2c DIFF: https://github.com/llvm/llvm-project/commit/d36a0333102698a1398971d0717465322b1c5c2c.diff LOG: [clang-tidy] New checker performance-trivially-destructible-check Checks for types which can be made trivially-destructible by removing out-of-line defaulted destructor declarations. The check is motivated by the work on C++ garbage collector in Blink (rendering engine for Chrome), which strives to minimize destructors and improve runtime of sweeping phase. In the entire chromium codebase the check hits over 2000 times. Differential Revision: https://reviews.llvm.org/D69435 Added: clang-tools-extra/clang-tidy/performance/TriviallyDestructibleCheck.cpp clang-tools-extra/clang-tidy/performance/TriviallyDestructibleCheck.h clang-tools-extra/docs/clang-tidy/checks/performance-trivially-destructible.rst clang-tools-extra/test/clang-tidy/checkers/performance-trivially-destructible.cpp Modified: clang-tools-extra/clang-tidy/performance/CMakeLists.txt clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp clang-tools-extra/clang-tidy/utils/Matchers.h clang-tools-extra/clang-tidy/utils/TypeTraits.cpp clang-tools-extra/clang-tidy/utils/TypeTraits.h clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/list.rst Removed: diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt index b6302a5ff815..cde2e246bf9e 100644 --- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt @@ -11,6 +11,7 @@ add_clang_library(clangTidyPerformanceModule MoveConstructorInitCheck.cpp NoexceptMoveConstructorCheck.cpp PerformanceTidyModule.cpp + TriviallyDestructibleCheck.cpp TypePromotionInMathFnCheck.cpp UnnecessaryCopyInitialization.cpp UnnecessaryValueParamCheck.cpp diff --git a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp index f4b620a14f85..269d09b98a68 100644 --- a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp @@ -18,6 +18,7 @@ #include "MoveConstArgCheck.h" #include "MoveConstructorInitCheck.h" #include "NoexceptMoveConstructorCheck.h" +#include "TriviallyDestructibleCheck.h" #include "TypePromotionInMathFnCheck.h" #include "UnnecessaryCopyInitialization.h" #include "UnnecessaryValueParamCheck.h" @@ -47,6 +48,8 @@ class PerformanceModule : public ClangTidyModule { "performance-move-constructor-init"); CheckFactories.registerCheck( "performance-noexcept-move-constructor"); +CheckFactories.registerCheck( +"performance-trivially-destructible"); CheckFactories.registerCheck( "performance-type-promotion-in-math-fn"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/performance/TriviallyDestructibleCheck.cpp b/clang-tools-extra/clang-tidy/performance/TriviallyDestructibleCheck.cpp new file mode 100644 index ..5ed705b0cd79 --- /dev/null +++ b/clang-tools-extra/clang-tidy/performance/TriviallyDestructibleCheck.cpp @@ -0,0 +1,82 @@ +//===--- TriviallyDestructibleCheck.cpp - clang-tidy --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// + +#include "TriviallyDestructibleCheck.h" +#include "../utils/LexerUtils.h" +#include "../utils/Matchers.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; +using namespace clang::ast_matchers::internal; +using namespace clang::tidy::matchers; + +namespace clang { +namespace tidy { +namespace performance { + +namespace { + +AST_MATCHER(Decl, isFirstDecl) { return Node.isFirstDecl(); } + +AST_MATCHER_P(CXXRecordDecl, hasBase, Matcher, InnerMatcher) { + for (const CXXBaseSpecifier : Node.bases()) { +QualType BaseType = BaseSpec.getType(); +if (InnerMatcher.matches(BaseType, Finder, Builder)) + return true; + } + return false; +} + +} // namespace + +void TriviallyDestructibleCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus11) +return; + + Finder->addMatcher( + cxxDestructorDecl( + isDefaulted(), + unless(anyOf(isFirstDecl(), isVirtual(), +
r368152 - [clang] Fix mismatched args constructing AddressSpaceAttr.
Author: antonbikineev Date: Wed Aug 7 04:12:43 2019 New Revision: 368152 URL: http://llvm.org/viewvc/llvm-project?rev=368152=rev Log: [clang] Fix mismatched args constructing AddressSpaceAttr. Differential Revision: https://reviews.llvm.org/D65589 Modified: cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/unittests/AST/ASTTraverserTest.cpp Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=368152=368151=368152=diff == --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Wed Aug 7 04:12:43 2019 @@ -5978,9 +5978,9 @@ static void HandleAddressSpaceTypeAttrib } ASTContext = S.Context; -auto *ASAttr = ::new (Ctx) AddressSpaceAttr( -Attr.getRange(), Ctx, Attr.getAttributeSpellingListIndex(), -static_cast(ASIdx)); +auto *ASAttr = ::new (Ctx) +AddressSpaceAttr(Attr.getRange(), Ctx, static_cast(ASIdx), + Attr.getAttributeSpellingListIndex()); // If the expression is not value dependent (not templated), then we can // apply the address space qualifiers just to the equivalent type. Modified: cfe/trunk/unittests/AST/ASTTraverserTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTTraverserTest.cpp?rev=368152=368151=368152=diff == --- cfe/trunk/unittests/AST/ASTTraverserTest.cpp (original) +++ cfe/trunk/unittests/AST/ASTTraverserTest.cpp Wed Aug 7 04:12:43 2019 @@ -139,6 +139,8 @@ struct templ { }; +void parmvardecl_attr(struct A __attribute__((address_space(19)))*); + )cpp"); const FunctionDecl *Func = getFunctionNode(AST.get(), "func"); @@ -220,5 +222,16 @@ FullComment R"cpp( TemplateArgument )cpp"); + + Func = getFunctionNode(AST.get(), "parmvardecl_attr"); + + const auto *Parm = Func->getParamDecl(0); + const auto TL = Parm->getTypeSourceInfo()->getTypeLoc(); + ASSERT_TRUE(TL.getType()->isPointerType()); + + const auto ATL = TL.getNextTypeLoc().getAs(); + const auto *AS = cast(ATL.getAttr()); + EXPECT_EQ(toTargetAddressSpace(static_cast(AS->getAddressSpace())), +19u); } } // namespace clang ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r367026 - [clang] Remove IsDerivedFromDeathTest.DiesOnEmptyBaseName test.
Author: antonbikineev Date: Thu Jul 25 08:09:37 2019 New Revision: 367026 URL: http://llvm.org/viewvc/llvm-project?rev=367026=rev Log: [clang] Remove IsDerivedFromDeathTest.DiesOnEmptyBaseName test. The semantics of an empty basename passed to isDerivedFrom matchers changed in r367022, so this test is no longer relevant. Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersInternalTest.cpp Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersInternalTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersInternalTest.cpp?rev=367026=367025=367026=diff == --- cfe/trunk/unittests/ASTMatchers/ASTMatchersInternalTest.cpp (original) +++ cfe/trunk/unittests/ASTMatchers/ASTMatchersInternalTest.cpp Thu Jul 25 08:09:37 2019 @@ -32,13 +32,6 @@ TEST(HasNameDeathTest, DiesOnEmptyPatter EXPECT_TRUE(notMatches("class X {};", HasEmptyName)); }, ""); } - -TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) { - ASSERT_DEBUG_DEATH({ -DeclarationMatcher IsDerivedFromEmpty = cxxRecordDecl(isDerivedFrom("")); -EXPECT_TRUE(notMatches("class X {};", IsDerivedFromEmpty)); - }, ""); -} #endif TEST(ConstructVariadic, MismatchedTypes_Regression) { ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r367022 - [clang] Fail for empty names in is*DerivedFrom matchers.
Author: antonbikineev Date: Thu Jul 25 07:48:55 2019 New Revision: 367022 URL: http://llvm.org/viewvc/llvm-project?rev=367022=rev Log: [clang] Fail for empty names in is*DerivedFrom matchers. Differential Revision: https://reviews.llvm.org/D65279 Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=367022=367021=367022=diff == --- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original) +++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Thu Jul 25 07:48:55 2019 @@ -2639,7 +2639,8 @@ AST_MATCHER_P(CXXRecordDecl, isDerivedFr /// Overloaded method as shortcut for \c isDerivedFrom(hasName(...)). AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDerivedFrom, std::string, BaseName, 1) { - assert(!BaseName.empty()); + if (BaseName.empty()) +return false; return isDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder); } @@ -2655,7 +2656,8 @@ AST_MATCHER_P_OVERLOAD(CXXRecordDecl, is /// \c isSameOrDerivedFrom(hasName(...)). AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, std::string, BaseName, 1) { - assert(!BaseName.empty()); + if (BaseName.empty()) +return false; return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder); } @@ -2687,7 +2689,8 @@ AST_MATCHER_P_OVERLOAD(CXXRecordDecl, is /// Overloaded method as shortcut for \c isDirectlyDerivedFrom(hasName(...)). AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDirectlyDerivedFrom, std::string, BaseName, 1) { - assert(!BaseName.empty()); + if (BaseName.empty()) +return false; return isDirectlyDerivedFrom(hasName(BaseName)) .matches(Node, Finder, Builder); } Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp?rev=367022=367021=367022=diff == --- cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp (original) +++ cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp Thu Jul 25 07:48:55 2019 @@ -566,6 +566,13 @@ TEST(DeclarationMatcher, ClassIsDerived) cxxRecordDecl(isDerivedFrom(namedDecl(hasName("X")); } +TEST(DeclarationMatcher, IsDerivedFromEmptyName) { + const char *const Code = "class X {}; class Y : public X {};"; + EXPECT_TRUE(notMatches(Code, cxxRecordDecl(isDerivedFrom(""; + EXPECT_TRUE(notMatches(Code, cxxRecordDecl(isDirectlyDerivedFrom(""; + EXPECT_TRUE(notMatches(Code, cxxRecordDecl(isSameOrDerivedFrom(""; +} + TEST(DeclarationMatcher, IsLambda) { const auto IsLambda = cxxMethodDecl(ofClass(cxxRecordDecl(isLambda(; EXPECT_TRUE(matches("auto x = []{};", IsLambda)); ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
r367010 - [clang] Add isDirectlyDerivedFrom AST matcher.
Author: antonbikineev Date: Thu Jul 25 04:54:13 2019 New Revision: 367010 URL: http://llvm.org/viewvc/llvm-project?rev=367010=rev Log: [clang] Add isDirectlyDerivedFrom AST matcher. Differential Revision: https://reviews.llvm.org/D65092 Modified: cfe/trunk/docs/LibASTMatchersReference.html cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp Modified: cfe/trunk/docs/LibASTMatchersReference.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LibASTMatchersReference.html?rev=367010=367009=367010=diff == --- cfe/trunk/docs/LibASTMatchersReference.html (original) +++ cfe/trunk/docs/LibASTMatchersReference.html Thu Jul 25 04:54:13 2019 @@ -2581,6 +2581,11 @@ class y; +Matcherhttps://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html;>CXXRecordDeclisDirectlyDerivedFromstd::string BaseName +Overloaded method as shortcut for isDirectlyDerivedFrom(hasName(...)). + + + Matcherhttps://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html;>CXXRecordDeclisExplicitTemplateSpecialization Matches explicit template specializations of function, class, or static member variable template instantiations. @@ -5252,6 +5257,26 @@ Example matches Y, Z, C (Base == hasName class X; class Y : public X {}; // directly derived class Z : public Y {}; // indirectly derived + typedef X A; + typedef A B; + class C : public B {}; // derived from a typedef of X + +In the following example, Bar matches isDerivedFrom(hasName("X")): + class Foo; + typedef Foo X; + class Bar : public Foo {}; // derived from a type that X is a typedef of + + + +Matcherhttps://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html;>CXXRecordDeclisDirectlyDerivedFromMatcherhttps://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html;>NamedDecl Base +Matches C++ classes that are directly derived from a class matching Base. + +Note that a class is not considered to be derived from itself. + +Example matches Y, C (Base == hasName("X")) + class X; + class Y : public X {}; // directly derived + class Z : public Y {}; // indirectly derived typedef X A; typedef A B; class C : public B {}; // derived from a typedef of X Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=367010=367009=367010=diff == --- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original) +++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Thu Jul 25 04:54:13 2019 @@ -2634,7 +2634,7 @@ hasOverloadedOperatorName(StringRef Name /// \endcode AST_MATCHER_P(CXXRecordDecl, isDerivedFrom, internal::Matcher, Base) { - return Finder->classIsDerivedFrom(, Base, Builder); + return Finder->classIsDerivedFrom(, Base, Builder, /*Directly=*/false); } /// Overloaded method as shortcut for \c isDerivedFrom(hasName(...)). @@ -2659,6 +2659,38 @@ AST_MATCHER_P_OVERLOAD(CXXRecordDecl, is return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder); } +/// Matches C++ classes that are directly derived from a class matching \c Base. +/// +/// Note that a class is not considered to be derived from itself. +/// +/// Example matches Y, C (Base == hasName("X")) +/// \code +/// class X; +/// class Y : public X {}; // directly derived +/// class Z : public Y {}; // indirectly derived +/// typedef X A; +/// typedef A B; +/// class C : public B {}; // derived from a typedef of X +/// \endcode +/// +/// In the following example, Bar matches isDerivedFrom(hasName("X")): +/// \code +/// class Foo; +/// typedef Foo X; +/// class Bar : public Foo {}; // derived from a type that X is a typedef of +/// \endcode +AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDirectlyDerivedFrom, + internal::Matcher, Base, 0) { + return Finder->classIsDerivedFrom(, Base, Builder, /*Directly=*/true); +} + +/// Overloaded method as shortcut for \c isDirectlyDerivedFrom(hasName(...)). +AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDirectlyDerivedFrom, std::string, + BaseName, 1) { + assert(!BaseName.empty()); + return isDirectlyDerivedFrom(hasName(BaseName)) + .matches(Node, Finder, Builder); +} /// Matches the first method of a class or struct that satisfies \c /// InnerMatcher. /// Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=367010=367009=367010=diff == ---
[PATCH] D26896: [libcxx] Make constexpr char_traits and char_traits
AntonBikineev marked 2 inline comments as done. AntonBikineev added inline comments. Comment at: include/__config:925 +#if !__has_builtin(__builtin_memcpy) +#define _LIBCPP_HAS_NO_BUILTIN_MEMCPY EricWF wrote: > What about GCC? Surely it implements some if not most of these. Thanks, good point. I've done it in the same way as it is done for __buitin_addressof. On the other hand, gcc has an option -fno-builtin to disable them. That way it *won't* compile. I try to stick to the current solution though. Comment at: include/__string:213 -static inline int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT -{return __n == 0 ? 0 : memcmp(__s1, __s2, __n);} -static inline size_t length(const char_type* __s) _NOEXCEPT {return strlen(__s);} -static inline const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT -{return __n == 0 ? NULL : (const char_type*) memchr(__s, to_int_type(__a), __n);} +#if _LIBCPP_STD_VER > 14 && !defined(_LIBCPP_HAS_NO_CXX14_CONSTEXPR) +static inline constexpr int EricWF wrote: > wow. This is #ifdef hell. Please find a way to do it with less (or hopefully > no) conditional compilation blocks. yep, this is generic hell. I want to cover as many cases as possible, i.e. combinations of (is_constexpr x has_builtin_xxx) for every function. I'm open to suggestions https://reviews.llvm.org/D26896 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26896: [libcxx] Make constexpr char_traits and char_traits
AntonBikineev updated this revision to Diff 79218. AntonBikineev added a comment. Support gcc's __builtin_memcpy, memchr, strlen https://reviews.llvm.org/D26896 Files: include/__config include/__string test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.char/assign2.pass.cpp test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.char/compare.pass.cpp test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.char/find.pass.cpp test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.char/length.pass.cpp test/std/strings/string.view/string.view.comparison/opeq.string_view.pointer.pass.cpp test/std/strings/string.view/string.view.comparison/opeq.string_view.string_view.pass.cpp test/std/strings/string.view/string.view.comparison/opge.string_view.pointer.pass.cpp test/std/strings/string.view/string.view.comparison/opge.string_view.string_view.pass.cpp test/std/strings/string.view/string.view.comparison/opgt.string_view.pointer.pass.cpp test/std/strings/string.view/string.view.comparison/opgt.string_view.string_view.pass.cpp test/std/strings/string.view/string.view.comparison/ople.string_view.pointer.pass.cpp test/std/strings/string.view/string.view.comparison/ople.string_view.string_view.pass.cpp test/std/strings/string.view/string.view.comparison/oplt.string_view.pointer.pass.cpp test/std/strings/string.view/string.view.comparison/oplt.string_view.string_view.pass.cpp test/std/strings/string.view/string.view.comparison/opne.string_view.pointer.pass.cpp test/std/strings/string.view/string.view.comparison/opne.string_view.string_view.pass.cpp test/std/strings/string.view/string.view.cons/from_literal.pass.cpp test/std/strings/string.view/string.view.find/find_char_size.pass.cpp test/std/strings/string.view/string.view.find/find_first_not_of_char_size.pass.cpp test/std/strings/string.view/string.view.find/find_first_not_of_pointer_size.pass.cpp test/std/strings/string.view/string.view.find/find_first_not_of_pointer_size_size.pass.cpp test/std/strings/string.view/string.view.find/find_first_of_char_size.pass.cpp test/std/strings/string.view/string.view.find/find_first_of_pointer_size.pass.cpp test/std/strings/string.view/string.view.find/find_first_of_pointer_size_size.pass.cpp test/std/strings/string.view/string.view.find/find_last_not_of_char_size.pass.cpp test/std/strings/string.view/string.view.find/find_last_not_of_pointer_size.pass.cpp test/std/strings/string.view/string.view.find/find_last_not_of_pointer_size_size.pass.cpp test/std/strings/string.view/string.view.find/find_last_of_char_size.pass.cpp test/std/strings/string.view/string.view.find/find_last_of_pointer_size.pass.cpp test/std/strings/string.view/string.view.find/find_last_of_pointer_size_size.pass.cpp test/std/strings/string.view/string.view.find/find_pointer_size.pass.cpp test/std/strings/string.view/string.view.find/find_pointer_size_size.pass.cpp test/std/strings/string.view/string.view.find/find_string_view_size.pass.cpp test/std/strings/string.view/string.view.find/rfind_char_size.pass.cpp test/std/strings/string.view/string.view.find/rfind_pointer_size.pass.cpp test/std/strings/string.view/string.view.find/rfind_pointer_size_size.pass.cpp test/std/strings/string.view/string.view.find/rfind_string_view_size.pass.cpp test/std/strings/string.view/string.view.ops/compare.pointer.pass.cpp test/std/strings/string.view/string.view.ops/compare.pointer_size.pass.cpp test/std/strings/string.view/string.view.ops/compare.size_size_sv.pass.cpp test/std/strings/string.view/string.view.ops/compare.size_size_sv_pointer_size.pass.cpp test/std/strings/string.view/string.view.ops/compare.size_size_sv_size_size.pass.cpp test/std/strings/string.view/string.view.ops/compare.sv.pass.cpp Index: test/std/strings/string.view/string.view.ops/compare.sv.pass.cpp === --- test/std/strings/string.view/string.view.ops/compare.sv.pass.cpp +++ test/std/strings/string.view/string.view.ops/compare.sv.pass.cpp @@ -119,4 +119,17 @@ static_assert ( sv2.compare(sv3) < 0, "" ); } #endif + +#if TEST_STD_VER > 14 +{ +typedef std::string_view SV; +constexpr SV sv1 { "abcde", 5 }; +constexpr SV sv2 { "abcde", 5 }; +constexpr SV sv3 { "edcba0", 6 }; +static_assert ( sv1.compare(sv2) == 0, "" ); +static_assert ( sv2.compare(sv1) == 0, "" ); +static_assert ( sv3.compare(sv2) > 0, "" ); +static_assert ( sv2.compare(sv3) < 0, "" ); +} +#endif } Index: test/std/strings/string.view/string.view.ops/compare.size_size_sv_size_size.pass.cpp === --- test/std/strings/string.view/string.view.ops/compare.size_size_sv_size_size.pass.cpp +++
[PATCH] D26896: [libcxx] Make constexpr char_traits and char_traits
AntonBikineev updated this revision to Diff 78773. https://reviews.llvm.org/D26896 Files: include/__config include/__string test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.char/assign2.pass.cpp test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.char/compare.pass.cpp test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.char/find.pass.cpp test/std/strings/char.traits/char.traits.specializations/char.traits.specializations.char/length.pass.cpp test/std/strings/string.view/string.view.comparison/opeq.string_view.pointer.pass.cpp test/std/strings/string.view/string.view.comparison/opeq.string_view.string_view.pass.cpp test/std/strings/string.view/string.view.comparison/opge.string_view.pointer.pass.cpp test/std/strings/string.view/string.view.comparison/opge.string_view.string_view.pass.cpp test/std/strings/string.view/string.view.comparison/opgt.string_view.pointer.pass.cpp test/std/strings/string.view/string.view.comparison/opgt.string_view.string_view.pass.cpp test/std/strings/string.view/string.view.comparison/ople.string_view.pointer.pass.cpp test/std/strings/string.view/string.view.comparison/ople.string_view.string_view.pass.cpp test/std/strings/string.view/string.view.comparison/oplt.string_view.pointer.pass.cpp test/std/strings/string.view/string.view.comparison/oplt.string_view.string_view.pass.cpp test/std/strings/string.view/string.view.comparison/opne.string_view.pointer.pass.cpp test/std/strings/string.view/string.view.comparison/opne.string_view.string_view.pass.cpp test/std/strings/string.view/string.view.cons/from_literal.pass.cpp test/std/strings/string.view/string.view.find/find_char_size.pass.cpp test/std/strings/string.view/string.view.find/find_first_not_of_char_size.pass.cpp test/std/strings/string.view/string.view.find/find_first_not_of_pointer_size.pass.cpp test/std/strings/string.view/string.view.find/find_first_not_of_pointer_size_size.pass.cpp test/std/strings/string.view/string.view.find/find_first_of_char_size.pass.cpp test/std/strings/string.view/string.view.find/find_first_of_pointer_size.pass.cpp test/std/strings/string.view/string.view.find/find_first_of_pointer_size_size.pass.cpp test/std/strings/string.view/string.view.find/find_last_not_of_char_size.pass.cpp test/std/strings/string.view/string.view.find/find_last_not_of_pointer_size.pass.cpp test/std/strings/string.view/string.view.find/find_last_not_of_pointer_size_size.pass.cpp test/std/strings/string.view/string.view.find/find_last_of_char_size.pass.cpp test/std/strings/string.view/string.view.find/find_last_of_pointer_size.pass.cpp test/std/strings/string.view/string.view.find/find_last_of_pointer_size_size.pass.cpp test/std/strings/string.view/string.view.find/find_pointer_size.pass.cpp test/std/strings/string.view/string.view.find/find_pointer_size_size.pass.cpp test/std/strings/string.view/string.view.find/find_string_view_size.pass.cpp test/std/strings/string.view/string.view.find/rfind_char_size.pass.cpp test/std/strings/string.view/string.view.find/rfind_pointer_size.pass.cpp test/std/strings/string.view/string.view.find/rfind_pointer_size_size.pass.cpp test/std/strings/string.view/string.view.find/rfind_string_view_size.pass.cpp test/std/strings/string.view/string.view.ops/compare.pointer.pass.cpp test/std/strings/string.view/string.view.ops/compare.pointer_size.pass.cpp test/std/strings/string.view/string.view.ops/compare.size_size_sv.pass.cpp test/std/strings/string.view/string.view.ops/compare.size_size_sv_pointer_size.pass.cpp test/std/strings/string.view/string.view.ops/compare.size_size_sv_size_size.pass.cpp test/std/strings/string.view/string.view.ops/compare.sv.pass.cpp Index: test/std/strings/string.view/string.view.ops/compare.sv.pass.cpp === --- test/std/strings/string.view/string.view.ops/compare.sv.pass.cpp +++ test/std/strings/string.view/string.view.ops/compare.sv.pass.cpp @@ -119,4 +119,17 @@ static_assert ( sv2.compare(sv3) < 0, "" ); } #endif + +#if TEST_STD_VER > 14 +{ +typedef std::string_view SV; +constexpr SV sv1 { "abcde", 5 }; +constexpr SV sv2 { "abcde", 5 }; +constexpr SV sv3 { "edcba0", 6 }; +static_assert ( sv1.compare(sv2) == 0, "" ); +static_assert ( sv2.compare(sv1) == 0, "" ); +static_assert ( sv3.compare(sv2) > 0, "" ); +static_assert ( sv2.compare(sv3) < 0, "" ); +} +#endif } Index: test/std/strings/string.view/string.view.ops/compare.size_size_sv_size_size.pass.cpp === --- test/std/strings/string.view/string.view.ops/compare.size_size_sv_size_size.pass.cpp +++ test/std/strings/string.view/string.view.ops/compare.size_size_sv_size_size.pass.cpp @@ -5844,4 +5844,14 @@
[PATCH] D26829: [clang] Allow lexer to handle string_view literals
AntonBikineev updated this revision to Diff 78739. https://reviews.llvm.org/D26829 Files: include/clang/Lex/LiteralSupport.h lib/Lex/Lexer.cpp lib/Lex/LiteralSupport.cpp lib/Sema/SemaDeclCXX.cpp test/SemaCXX/cxx1z-user-defined-literals.cpp Index: test/SemaCXX/cxx1z-user-defined-literals.cpp === --- test/SemaCXX/cxx1z-user-defined-literals.cpp +++ test/SemaCXX/cxx1z-user-defined-literals.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -std=c++1z %s -include %s -verify + +#ifndef INCLUDED +#define INCLUDED + +#pragma clang system_header +namespace std { + using size_t = decltype(sizeof(0)); + + struct string_view {}; + string_view operator""sv(const char*, size_t); +} + +#else + +using namespace std; +string_view s = "foo"sv; +const char* p = "bar"sv; // expected-error {{no viable conversion}} +char error = 'x'sv; // expected-error {{invalid suffix}} expected-error {{expected ';'}} + +#endif Index: lib/Sema/SemaDeclCXX.cpp === --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -12908,7 +12908,7 @@ // Literal suffix identifiers that do not start with an underscore // are reserved for future standardization. Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved) - << NumericLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName); + << StringLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName); } return false; Index: lib/Lex/LiteralSupport.cpp === --- lib/Lex/LiteralSupport.cpp +++ lib/Lex/LiteralSupport.cpp @@ -1708,3 +1708,12 @@ return SpellingPtr-SpellingStart; } + +/// Determine whether a suffix is a valid ud-suffix. We avoid treating reserved +/// suffixes as ud-suffixes, because the diagnostic experience is better if we +/// treat it as an invalid suffix. +bool StringLiteralParser::isValidUDSuffix(const LangOptions , + StringRef Suffix) { + return NumericLiteralParser::isValidUDSuffix(LangOpts, Suffix) || + Suffix == "sv"; +} Index: include/clang/Lex/LiteralSupport.h === --- include/clang/Lex/LiteralSupport.h +++ include/clang/Lex/LiteralSupport.h @@ -259,6 +259,8 @@ return UDSuffixOffset; } + static bool isValidUDSuffix(const LangOptions , StringRef Suffix); + private: void init(ArrayRef StringToks); bool CopyStringFragment(const Token , const char *TokBegin, Index: lib/Lex/Lexer.cpp === --- lib/Lex/Lexer.cpp +++ lib/Lex/Lexer.cpp @@ -1713,9 +1713,9 @@ getLangOpts()); if (!isIdentifierBody(Next)) { // End of suffix. Check whether this is on the whitelist. - IsUDSuffix = (Chars == 1 && Buffer[0] == 's') || - NumericLiteralParser::isValidUDSuffix( - getLangOpts(), StringRef(Buffer, Chars)); + const StringRef CompleteSuffix(Buffer, Chars); + IsUDSuffix = StringLiteralParser::isValidUDSuffix(getLangOpts(), +CompleteSuffix); break; } Index: test/SemaCXX/cxx1z-user-defined-literals.cpp === --- test/SemaCXX/cxx1z-user-defined-literals.cpp +++ test/SemaCXX/cxx1z-user-defined-literals.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -std=c++1z %s -include %s -verify + +#ifndef INCLUDED +#define INCLUDED + +#pragma clang system_header +namespace std { + using size_t = decltype(sizeof(0)); + + struct string_view {}; + string_view operator""sv(const char*, size_t); +} + +#else + +using namespace std; +string_view s = "foo"sv; +const char* p = "bar"sv; // expected-error {{no viable conversion}} +char error = 'x'sv; // expected-error {{invalid suffix}} expected-error {{expected ';'}} + +#endif Index: lib/Sema/SemaDeclCXX.cpp === --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -12908,7 +12908,7 @@ // Literal suffix identifiers that do not start with an underscore // are reserved for future standardization. Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved) - << NumericLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName); + << StringLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName); } return false; Index: lib/Lex/LiteralSupport.cpp === --- lib/Lex/LiteralSupport.cpp +++ lib/Lex/LiteralSupport.cpp @@ -1708,3 +1708,12 @@ return SpellingPtr-SpellingStart; } + +/// Determine whether a suffix is a valid ud-suffix. We avoid treating reserved +/// suffixes as ud-suffixes, because the
[PATCH] D26829: [clang] Allow lexer to handle string_view literals
AntonBikineev updated this revision to Diff 78654. AntonBikineev added a comment. Richard, thanks, I addressed your comments. https://reviews.llvm.org/D26829 Files: include/clang/Lex/LiteralSupport.h lib/Lex/Lexer.cpp lib/Lex/LiteralSupport.cpp lib/Sema/SemaDeclCXX.cpp test/SemaCXX/cxx1z-user-defined-literals.cpp Index: test/SemaCXX/cxx1z-user-defined-literals.cpp === --- test/SemaCXX/cxx1z-user-defined-literals.cpp +++ test/SemaCXX/cxx1z-user-defined-literals.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -std=c++1z %s -include %s -verify + +#ifndef INCLUDED +#define INCLUDED + +#pragma clang system_header +namespace std { + using size_t = decltype(sizeof(0)); + + struct string_view {}; + string_view operator""sv(const char*, size_t); +} + +#else + +using namespace std; +string_view s = "foo"sv; +const char* p = "bar"sv; // expected-error {{no viable conversion}} +char error = 'x'sv; // expected-error {{invalid suffix}} expected-error {{expected ';'}} + +#endif Index: lib/Sema/SemaDeclCXX.cpp === --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -12908,7 +12908,7 @@ // Literal suffix identifiers that do not start with an underscore // are reserved for future standardization. Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved) - << NumericLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName); + << StringLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName); } return false; Index: lib/Lex/LiteralSupport.cpp === --- lib/Lex/LiteralSupport.cpp +++ lib/Lex/LiteralSupport.cpp @@ -1708,3 +1708,12 @@ return SpellingPtr-SpellingStart; } + +/// Determine whether a suffix is a valid ud-suffix. We avoid treating reserved +/// suffixes as ud-suffixes, because the diagnostic experience is better if we +/// treat it as an invalid suffix. +bool StringLiteralParser::isValidUDSuffix(const LangOptions , + StringRef Suffix) { + return NumericLiteralParser::isValidUDSuffix(LangOpts, Suffix) || + Suffix == "sv"; +} Index: include/clang/Lex/LiteralSupport.h === --- include/clang/Lex/LiteralSupport.h +++ include/clang/Lex/LiteralSupport.h @@ -259,6 +259,8 @@ return UDSuffixOffset; } + static bool isValidUDSuffix(const LangOptions , StringRef Suffix); + private: void init(ArrayRef StringToks); bool CopyStringFragment(const Token , const char *TokBegin, Index: lib/Lex/Lexer.cpp === --- lib/Lex/Lexer.cpp +++ lib/Lex/Lexer.cpp @@ -1713,9 +1713,10 @@ getLangOpts()); if (!isIdentifierBody(Next)) { // End of suffix. Check whether this is on the whitelist. - IsUDSuffix = (Chars == 1 && Buffer[0] == 's') || - NumericLiteralParser::isValidUDSuffix( - getLangOpts(), StringRef(Buffer, Chars)); + const StringRef CompleteSuffix(Buffer, Chars); + const LangOptions = getLangOpts(); + IsUDSuffix = + StringLiteralParser::isValidUDSuffix(LangOpts, CompleteSuffix); break; } Index: test/SemaCXX/cxx1z-user-defined-literals.cpp === --- test/SemaCXX/cxx1z-user-defined-literals.cpp +++ test/SemaCXX/cxx1z-user-defined-literals.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -std=c++1z %s -include %s -verify + +#ifndef INCLUDED +#define INCLUDED + +#pragma clang system_header +namespace std { + using size_t = decltype(sizeof(0)); + + struct string_view {}; + string_view operator""sv(const char*, size_t); +} + +#else + +using namespace std; +string_view s = "foo"sv; +const char* p = "bar"sv; // expected-error {{no viable conversion}} +char error = 'x'sv; // expected-error {{invalid suffix}} expected-error {{expected ';'}} + +#endif Index: lib/Sema/SemaDeclCXX.cpp === --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -12908,7 +12908,7 @@ // Literal suffix identifiers that do not start with an underscore // are reserved for future standardization. Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved) - << NumericLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName); + << StringLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName); } return false; Index: lib/Lex/LiteralSupport.cpp === --- lib/Lex/LiteralSupport.cpp +++ lib/Lex/LiteralSupport.cpp @@ -1708,3 +1708,12 @@ return SpellingPtr-SpellingStart; } + +/// Determine whether a suffix is a valid
[PATCH] D26829: [clang] Allow lexer to handle string_view literals
AntonBikineev added inline comments. Comment at: lib/Lex/LiteralSupport.cpp:1716-1717 +StringLiteralParser::UDSuffixResult +StringLiteralParser::isValidUDSuffix(const LangOptions , + StringRef Suffix) { + if (!LangOpts.CPlusPlus11 || Suffix.empty()) rsmith wrote: > Just make this call `NumericLiteralParser::isValidUDSuffix` and then check > for the `sv` case. All the numeric suffixes are also valid string literal > suffixes for the form `operator""suffix`. This makes sense for the call sites we currently have. > All the numeric suffixes are also valid string literal suffixes for the form > operator""suffix. Don't really understand this part. It seems inconsistent if one calls, say, ``` StringLiteralParser::isValidUDSuffix(LangOpts(), "if") ``` and gets ```true``` https://reviews.llvm.org/D26829 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26829: [clang] Allow lexer to handle string_view literals
AntonBikineev added a comment. In https://reviews.llvm.org/D26829#599906, @malcolm.parsons wrote: > Does `Sema::CheckLiteralOperatorDeclaration` need to check > `StringLiteralParser::isValidUDSuffix`? Thanks, nice point! Just addressed it. https://reviews.llvm.org/D26829 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26829: [clang] Allow lexer to handle string_view literals
AntonBikineev updated this revision to Diff 78602. https://reviews.llvm.org/D26829 Files: include/clang/Basic/DiagnosticLexKinds.td include/clang/Lex/LiteralSupport.h lib/Lex/Lexer.cpp lib/Lex/LiteralSupport.cpp lib/Sema/SemaDeclCXX.cpp test/SemaCXX/cxx1z-user-defined-literals.cpp Index: test/SemaCXX/cxx1z-user-defined-literals.cpp === --- test/SemaCXX/cxx1z-user-defined-literals.cpp +++ test/SemaCXX/cxx1z-user-defined-literals.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -std=c++1z %s -include %s -verify + +#ifndef INCLUDED +#define INCLUDED + +#pragma clang system_header +namespace std { + using size_t = decltype(sizeof(0)); + + struct string_view {}; + string_view operator""sv(const char*, size_t); +} + +#else + +using namespace std; +string_view s = "foo"sv; +const char* p = "bar"sv; // expected-error {{no viable conversion}} +char error = 'x'sv; // expected-error {{invalid suffix}} expected-error {{expected ';'}} + +#endif Index: lib/Sema/SemaDeclCXX.cpp === --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -12904,11 +12904,15 @@ StringRef LiteralName = FnDecl->getDeclName().getCXXLiteralIdentifier()->getName(); if (LiteralName[0] != '_') { +bool MoreMessage = +NumericLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName) || +(StringLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName) == + StringLiteralParser::UDSuffixResult::Valid); // C++11 [usrlit.suffix]p1: // Literal suffix identifiers that do not start with an underscore // are reserved for future standardization. Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved) - << NumericLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName); + << std::move(MoreMessage); } return false; Index: lib/Lex/LiteralSupport.cpp === --- lib/Lex/LiteralSupport.cpp +++ lib/Lex/LiteralSupport.cpp @@ -1708,3 +1708,28 @@ return SpellingPtr-SpellingStart; } + +/// Determine whether a suffix is a valid ud-suffix. We avoid treating reserved +/// suffixes as ud-suffixes, because the diagnostic experience is better if we +/// treat it as an invalid suffix. +StringLiteralParser::UDSuffixResult +StringLiteralParser::isValidUDSuffix(const LangOptions , + StringRef Suffix) { + if (!LangOpts.CPlusPlus11 || Suffix.empty()) +return UDSuffixResult::Invalid; + + // By C++11 [lex.ext]p10, ud-suffixes starting with an '_' are always valid. + if (Suffix[0] == '_') +return UDSuffixResult::Valid; + + // In C++11, there are no library suffixes. + if (!LangOpts.CPlusPlus14) +return UDSuffixResult::Invalid; + + // C++1z adds "sv" literals + if (Suffix == "sv") +return LangOpts.CPlusPlus1z ? UDSuffixResult::Valid +: UDSuffixResult::SVIncompatible; + + return Suffix == "s" ? UDSuffixResult::Valid : UDSuffixResult::Invalid; +} Index: include/clang/Lex/LiteralSupport.h === --- include/clang/Lex/LiteralSupport.h +++ include/clang/Lex/LiteralSupport.h @@ -259,6 +259,13 @@ return UDSuffixOffset; } + enum class UDSuffixResult : uint8_t { +Valid, Invalid, SVIncompatible + }; + + static UDSuffixResult isValidUDSuffix(const LangOptions , +StringRef Suffix); + private: void init(ArrayRef StringToks); bool CopyStringFragment(const Token , const char *TokBegin, Index: include/clang/Basic/DiagnosticLexKinds.td === --- include/clang/Basic/DiagnosticLexKinds.td +++ include/clang/Basic/DiagnosticLexKinds.td @@ -186,6 +186,8 @@ "hexadecimal floating literals are incompatible with " "C++ standards before C++1z">, InGroup, DefaultIgnore; +def err_cxx1z_string_view_literal : Error< + "string_view literals are a C++1z feature">; def ext_binary_literal : Extension< "binary integer literals are a GNU extension">, InGroup; def ext_binary_literal_cxx14 : Extension< Index: lib/Lex/Lexer.cpp === --- lib/Lex/Lexer.cpp +++ lib/Lex/Lexer.cpp @@ -1697,6 +1697,8 @@ // likely to be a ud-suffix than a macro, however, and accept that. if (!Consumed) { bool IsUDSuffix = false; +StringLiteralParser::UDSuffixResult IsStringUDSuffix = +StringLiteralParser::UDSuffixResult::Invalid; if (C == '_') IsUDSuffix = true; else if (IsStringLiteral && getLangOpts().CPlusPlus14) { @@ -1713,9 +1715,18 @@ getLangOpts()); if (!isIdentifierBody(Next)) { // End of suffix. Check whether this is on the whitelist. - IsUDSuffix = (Chars == 1 && Buffer[0] == 's') ||
[PATCH] D26830: [libcxx] Add string_view literals
AntonBikineev updated this revision to Diff 78532. AntonBikineev marked an inline comment as done. AntonBikineev added a comment. Fixing typos... https://reviews.llvm.org/D26830 Files: include/string_view test/std/strings/string.view/string.view.literals/literal.pass.cpp test/std/strings/string.view/string.view.literals/literal1.fail.cpp test/std/strings/string.view/string.view.literals/literal1.pass.cpp test/std/strings/string.view/string.view.literals/literal2.fail.cpp test/std/strings/string.view/string.view.literals/literal2.pass.cpp test/std/strings/string.view/string.view.literals/literal3.pass.cpp Index: test/std/strings/string.view/string.view.literals/literal3.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal3.pass.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using namespace std; + +string_view foo = ""sv; +} Index: test/std/strings/string.view/string.view.literals/literal2.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal2.pass.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using namespace std::literals::string_view_literals; + +std::string_view foo = ""sv; +} Index: test/std/strings/string.view/string.view.literals/literal2.fail.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal2.fail.cpp @@ -0,0 +1,19 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +std::string_view foo = ""sv; // should fail w/conversion operator not found +} Index: test/std/strings/string.view/string.view.literals/literal1.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal1.pass.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using namespace std::literals; + +std::string_view foo = ""sv; +} Index: test/std/strings/string.view/string.view.literals/literal1.fail.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal1.fail.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using std::string_view; + +string_view foo = ""sv; // should fail w/conversion operator not found +} Index: test/std/strings/string.view/string.view.literals/literal.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal.pass.cpp @@ -0,0 +1,45 @@ +// -*- C++ -*- +//===--===// +// +//
[PATCH] D26829: [clang] Allow lexer to handle string_view literals
AntonBikineev updated this revision to Diff 78523. AntonBikineev added a comment. Just added a small test case https://reviews.llvm.org/D26829 Files: include/clang/Basic/DiagnosticLexKinds.td include/clang/Lex/LiteralSupport.h lib/Lex/Lexer.cpp lib/Lex/LiteralSupport.cpp test/SemaCXX/cxx1z-user-defined-literals.cpp Index: test/SemaCXX/cxx1z-user-defined-literals.cpp === --- test/SemaCXX/cxx1z-user-defined-literals.cpp +++ test/SemaCXX/cxx1z-user-defined-literals.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -std=c++1z %s -include %s -verify + +#ifndef INCLUDED +#define INCLUDED + +#pragma clang system_header +namespace std { + using size_t = decltype(sizeof(0)); + + struct string_view {}; + string_view operator""sv(const char*, size_t); +} + +#else + +using namespace std; +string_view s = "foo"sv; +const char* p = "bar"sv; // expected-error {{no viable conversion}} +char error = 'x'sv; // expected-error {{invalid suffix}} expected-error {{expected ';'}} + +#endif Index: lib/Lex/LiteralSupport.cpp === --- lib/Lex/LiteralSupport.cpp +++ lib/Lex/LiteralSupport.cpp @@ -1708,3 +1708,28 @@ return SpellingPtr-SpellingStart; } + +/// Determine whether a suffix is a valid ud-suffix. We avoid treating reserved +/// suffixes as ud-suffixes, because the diagnostic experience is better if we +/// treat it as an invalid suffix. +StringLiteralParser::UDSuffixResult +StringLiteralParser::isValidUDSuffix(const LangOptions , + StringRef Suffix) { + if (!LangOpts.CPlusPlus11 || Suffix.empty()) +return UDSuffixResult::Invalid; + + // By C++11 [lex.ext]p10, ud-suffixes starting with an '_' are always valid. + if (Suffix[0] == '_') +return UDSuffixResult::Valid; + + // In C++11, there are no library suffixes. + if (!LangOpts.CPlusPlus14) +return UDSuffixResult::Invalid; + + // C++1z adds "sv" literals + if (Suffix == "sv") +return LangOpts.CPlusPlus1z ? UDSuffixResult::Valid +: UDSuffixResult::SVIncompatible; + + return Suffix == "s" ? UDSuffixResult::Valid : UDSuffixResult::Invalid; +} Index: include/clang/Lex/LiteralSupport.h === --- include/clang/Lex/LiteralSupport.h +++ include/clang/Lex/LiteralSupport.h @@ -259,6 +259,13 @@ return UDSuffixOffset; } + enum class UDSuffixResult : uint8_t { +Valid, Invalid, SVIncompatible + }; + + static UDSuffixResult isValidUDSuffix(const LangOptions , +StringRef Suffix); + private: void init(ArrayRef StringToks); bool CopyStringFragment(const Token , const char *TokBegin, Index: include/clang/Basic/DiagnosticLexKinds.td === --- include/clang/Basic/DiagnosticLexKinds.td +++ include/clang/Basic/DiagnosticLexKinds.td @@ -186,6 +186,8 @@ "hexadecimal floating literals are incompatible with " "C++ standards before C++1z">, InGroup, DefaultIgnore; +def err_cxx1z_string_view_literal : Error< + "string_view literals are a C++1z feature">; def ext_binary_literal : Extension< "binary integer literals are a GNU extension">, InGroup; def ext_binary_literal_cxx14 : Extension< Index: lib/Lex/Lexer.cpp === --- lib/Lex/Lexer.cpp +++ lib/Lex/Lexer.cpp @@ -1697,6 +1697,8 @@ // likely to be a ud-suffix than a macro, however, and accept that. if (!Consumed) { bool IsUDSuffix = false; +StringLiteralParser::UDSuffixResult IsStringUDSuffix = +StringLiteralParser::UDSuffixResult::Invalid; if (C == '_') IsUDSuffix = true; else if (IsStringLiteral && getLangOpts().CPlusPlus14) { @@ -1713,9 +1715,18 @@ getLangOpts()); if (!isIdentifierBody(Next)) { // End of suffix. Check whether this is on the whitelist. - IsUDSuffix = (Chars == 1 && Buffer[0] == 's') || - NumericLiteralParser::isValidUDSuffix( - getLangOpts(), StringRef(Buffer, Chars)); + const StringRef CompleteSuffix(Buffer, Chars); + const LangOptions = getLangOpts(); + // First, check if the suffix is a numeric suffix (s,sv) + IsUDSuffix = + NumericLiteralParser::isValidUDSuffix(LangOpts, CompleteSuffix); + // If it is not, check for a string suffix + if (!IsUDSuffix) { +IsStringUDSuffix = +StringLiteralParser::isValidUDSuffix(LangOpts, CompleteSuffix); +IsUDSuffix = +IsStringUDSuffix == StringLiteralParser::UDSuffixResult::Valid; + } break; } @@ -1729,11 +1740,18 @@ } if (!IsUDSuffix) { - if (!isLexingRawMode()) -Diag(CurPtr,
[PATCH] D26829: [clang] Allow lexer to handle string_view literals
AntonBikineev updated this revision to Diff 78511. https://reviews.llvm.org/D26829 Files: include/clang/Basic/DiagnosticLexKinds.td include/clang/Lex/LiteralSupport.h lib/Lex/Lexer.cpp lib/Lex/LiteralSupport.cpp Index: lib/Lex/LiteralSupport.cpp === --- lib/Lex/LiteralSupport.cpp +++ lib/Lex/LiteralSupport.cpp @@ -1708,3 +1708,28 @@ return SpellingPtr-SpellingStart; } + +/// Determine whether a suffix is a valid ud-suffix. We avoid treating reserved +/// suffixes as ud-suffixes, because the diagnostic experience is better if we +/// treat it as an invalid suffix. +StringLiteralParser::UDSuffixResult +StringLiteralParser::isValidUDSuffix(const LangOptions , + StringRef Suffix) { + if (!LangOpts.CPlusPlus11 || Suffix.empty()) +return UDSuffixResult::Invalid; + + // By C++11 [lex.ext]p10, ud-suffixes starting with an '_' are always valid. + if (Suffix[0] == '_') +return UDSuffixResult::Valid; + + // In C++11, there are no library suffixes. + if (!LangOpts.CPlusPlus14) +return UDSuffixResult::Invalid; + + // C++1z adds "sv" literals + if (Suffix == "sv") +return LangOpts.CPlusPlus1z ? UDSuffixResult::Valid +: UDSuffixResult::SVIncompatible; + + return Suffix == "s" ? UDSuffixResult::Valid : UDSuffixResult::Invalid; +} Index: include/clang/Lex/LiteralSupport.h === --- include/clang/Lex/LiteralSupport.h +++ include/clang/Lex/LiteralSupport.h @@ -259,6 +259,13 @@ return UDSuffixOffset; } + enum class UDSuffixResult : uint8_t { +Valid, Invalid, SVIncompatible + }; + + static UDSuffixResult isValidUDSuffix(const LangOptions , +StringRef Suffix); + private: void init(ArrayRef StringToks); bool CopyStringFragment(const Token , const char *TokBegin, Index: include/clang/Basic/DiagnosticLexKinds.td === --- include/clang/Basic/DiagnosticLexKinds.td +++ include/clang/Basic/DiagnosticLexKinds.td @@ -186,6 +186,8 @@ "hexadecimal floating literals are incompatible with " "C++ standards before C++1z">, InGroup, DefaultIgnore; +def err_cxx1z_string_view_literal : Error< + "string_view literals are a C++1z feature">; def ext_binary_literal : Extension< "binary integer literals are a GNU extension">, InGroup; def ext_binary_literal_cxx14 : Extension< Index: lib/Lex/Lexer.cpp === --- lib/Lex/Lexer.cpp +++ lib/Lex/Lexer.cpp @@ -1697,6 +1697,8 @@ // likely to be a ud-suffix than a macro, however, and accept that. if (!Consumed) { bool IsUDSuffix = false; +StringLiteralParser::UDSuffixResult IsStringUDSuffix = +StringLiteralParser::UDSuffixResult::Invalid; if (C == '_') IsUDSuffix = true; else if (IsStringLiteral && getLangOpts().CPlusPlus14) { @@ -1713,9 +1715,18 @@ getLangOpts()); if (!isIdentifierBody(Next)) { // End of suffix. Check whether this is on the whitelist. - IsUDSuffix = (Chars == 1 && Buffer[0] == 's') || - NumericLiteralParser::isValidUDSuffix( - getLangOpts(), StringRef(Buffer, Chars)); + const StringRef CompleteSuffix(Buffer, Chars); + const LangOptions = getLangOpts(); + // First, check if the suffix is a numeric suffix (s,sv) + IsUDSuffix = + NumericLiteralParser::isValidUDSuffix(LangOpts, CompleteSuffix); + // If it is not, check for a string suffix + if (!IsUDSuffix) { +IsStringUDSuffix = +StringLiteralParser::isValidUDSuffix(LangOpts, CompleteSuffix); +IsUDSuffix = +IsStringUDSuffix == StringLiteralParser::UDSuffixResult::Valid; + } break; } @@ -1729,11 +1740,18 @@ } if (!IsUDSuffix) { - if (!isLexingRawMode()) -Diag(CurPtr, getLangOpts().MSVCCompat - ? diag::ext_ms_reserved_user_defined_literal - : diag::ext_reserved_user_defined_literal) - << FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); + if (!isLexingRawMode()) { +if (IsStringUDSuffix == +StringLiteralParser::UDSuffixResult::SVIncompatible) { + Diag(CurPtr, diag::err_cxx1z_string_view_literal) +<< FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); +} else { + Diag(CurPtr, getLangOpts().MSVCCompat + ? diag::ext_ms_reserved_user_defined_literal + : diag::ext_reserved_user_defined_literal) +<< FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); +} + } return
[PATCH] D26829: [clang] Allow lexer to handle string_view literals
AntonBikineev updated this revision to Diff 78510. https://reviews.llvm.org/D26829 Files: include/clang/Basic/DiagnosticLexKinds.td include/clang/Lex/LiteralSupport.h lib/Lex/Lexer.cpp lib/Lex/LiteralSupport.cpp Index: lib/Lex/LiteralSupport.cpp === --- lib/Lex/LiteralSupport.cpp +++ lib/Lex/LiteralSupport.cpp @@ -1708,3 +1708,28 @@ return SpellingPtr-SpellingStart; } + +/// Determine whether a suffix is a valid ud-suffix. We avoid treating reserved +/// suffixes as ud-suffixes, because the diagnostic experience is better if we +/// treat it as an invalid suffix. +StringLiteralParser::UDSuffixResult +StringLiteralParser::isValidUDSuffix(const LangOptions , + StringRef Suffix) { + if (!LangOpts.CPlusPlus11 || Suffix.empty()) +return UDSuffixResult::Invalid; + + // By C++11 [lex.ext]p10, ud-suffixes starting with an '_' are always valid. + if (Suffix[0] == '_') +return UDSuffixResult::Valid; + + // In C++11, there are no library suffixes. + if (!LangOpts.CPlusPlus14) +return UDSuffixResult::Invalid; + + // C++1z adds "sv" literals + if (Suffix == "sv") +return LangOpts.CPlusPlus1z ? UDSuffixResult::Valid +: UDSuffixResult::SVIncompatible; + + return Suffix == "s" ? UDSuffixResult::Valid : UDSuffixResult::Invalid; +} Index: include/clang/Lex/LiteralSupport.h === --- include/clang/Lex/LiteralSupport.h +++ include/clang/Lex/LiteralSupport.h @@ -259,6 +259,13 @@ return UDSuffixOffset; } + enum class UDSuffixResult : uint8_t { +Valid, Invalid, SVIncompatible + }; + + static UDSuffixResult isValidUDSuffix(const LangOptions , +StringRef Suffix); + private: void init(ArrayRef StringToks); bool CopyStringFragment(const Token , const char *TokBegin, Index: include/clang/Basic/DiagnosticLexKinds.td === --- include/clang/Basic/DiagnosticLexKinds.td +++ include/clang/Basic/DiagnosticLexKinds.td @@ -186,6 +186,8 @@ "hexadecimal floating literals are incompatible with " "C++ standards before C++1z">, InGroup, DefaultIgnore; +def err_cxx1z_string_view_literal : Error< + "string_view literals are a C++1z feature">; def ext_binary_literal : Extension< "binary integer literals are a GNU extension">, InGroup; def ext_binary_literal_cxx14 : Extension< Index: lib/Lex/Lexer.cpp === --- lib/Lex/Lexer.cpp +++ lib/Lex/Lexer.cpp @@ -1697,6 +1697,8 @@ // likely to be a ud-suffix than a macro, however, and accept that. if (!Consumed) { bool IsUDSuffix = false; +StringLiteralParser::UDSuffixResult IsStringUDSuffix = +StringLiteralParser::UDSuffixResult::Invalid; if (C == '_') IsUDSuffix = true; else if (IsStringLiteral && getLangOpts().CPlusPlus14) { @@ -1713,9 +1715,18 @@ getLangOpts()); if (!isIdentifierBody(Next)) { // End of suffix. Check whether this is on the whitelist. - IsUDSuffix = (Chars == 1 && Buffer[0] == 's') || - NumericLiteralParser::isValidUDSuffix( - getLangOpts(), StringRef(Buffer, Chars)); + const StringRef CompleteSuffix = StringRef(Buffer, Chars); + const LangOptions = getLangOpts(); + // First, check if the suffix is a numeric suffix (s,sv) + IsUDSuffix = + NumericLiteralParser::isValidUDSuffix(LangOpts, CompleteSuffix); + // If it is not, check for a string suffix + if (!IsUDSuffix) { +IsStringUDSuffix = +StringLiteralParser::isValidUDSuffix(LangOpts, CompleteSuffix); +IsUDSuffix = +IsStringUDSuffix == StringLiteralParser::UDSuffixResult::Valid; + } break; } @@ -1730,10 +1741,16 @@ if (!IsUDSuffix) { if (!isLexingRawMode()) -Diag(CurPtr, getLangOpts().MSVCCompat - ? diag::ext_ms_reserved_user_defined_literal - : diag::ext_reserved_user_defined_literal) - << FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); +if (IsStringUDSuffix == +StringLiteralParser::UDSuffixResult::SVIncompatible) { + Diag(CurPtr, diag::err_cxx1z_string_view_literal) +<< FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); +} else { + Diag(CurPtr, getLangOpts().MSVCCompat + ? diag::ext_ms_reserved_user_defined_literal + : diag::ext_reserved_user_defined_literal) +<< FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); +} return CurPtr; }
[PATCH] D26829: [clang] Allow lexer to handle string_view literals
AntonBikineev updated the summary for this revision. AntonBikineev updated this revision to Diff 78507. https://reviews.llvm.org/D26829 Files: include/clang/Basic/DiagnosticLexKinds.td include/clang/Lex/LiteralSupport.h lib/Lex/Lexer.cpp lib/Lex/LiteralSupport.cpp Index: lib/Lex/LiteralSupport.cpp === --- lib/Lex/LiteralSupport.cpp +++ lib/Lex/LiteralSupport.cpp @@ -1708,3 +1708,28 @@ return SpellingPtr-SpellingStart; } + +/// Determine whether a suffix is a valid ud-suffix. We avoid treating reserved +/// suffixes as ud-suffixes, because the diagnostic experience is better if we +/// treat it as an invalid suffix. +StringLiteralParser::UDSuffixResult +StringLiteralParser::isValidUDSuffix(const LangOptions , + StringRef Suffix) { + if (!LangOpts.CPlusPlus11 || Suffix.empty()) +return UDSuffixResult::Invalid; + + // By C++11 [lex.ext]p10, ud-suffixes starting with an '_' are always valid. + if (Suffix[0] == '_') +return UDSuffixResult::Valid; + + // In C++11, there are no library suffixes. + if (!LangOpts.CPlusPlus14) +return UDSuffixResult::Invalid; + + // C++1z adds "sv" literals + if (Suffix == "sv") +return LangOpts.CPlusPlus1z ? UDSuffixResult::Valid +: UDSuffixResult::SVIncompatible; + + return Suffix == "s" ? UDSuffixResult::Valid : UDSuffixResult::Invalid; +} Index: include/clang/Lex/LiteralSupport.h === --- include/clang/Lex/LiteralSupport.h +++ include/clang/Lex/LiteralSupport.h @@ -259,6 +259,13 @@ return UDSuffixOffset; } + enum class UDSuffixResult : uint8_t { +Valid, Invalid, SVIncompatible + }; + + static UDSuffixResult isValidUDSuffix(const LangOptions , + StringRef Suffix); + private: void init(ArrayRef StringToks); bool CopyStringFragment(const Token , const char *TokBegin, Index: include/clang/Basic/DiagnosticLexKinds.td === --- include/clang/Basic/DiagnosticLexKinds.td +++ include/clang/Basic/DiagnosticLexKinds.td @@ -186,6 +186,8 @@ "hexadecimal floating literals are incompatible with " "C++ standards before C++1z">, InGroup, DefaultIgnore; +def err_cxx1z_string_view_literal : Error< + "string_view literals are a C++1z feature">; def ext_binary_literal : Extension< "binary integer literals are a GNU extension">, InGroup; def ext_binary_literal_cxx14 : Extension< Index: lib/Lex/Lexer.cpp === --- lib/Lex/Lexer.cpp +++ lib/Lex/Lexer.cpp @@ -1697,6 +1697,8 @@ // likely to be a ud-suffix than a macro, however, and accept that. if (!Consumed) { bool IsUDSuffix = false; +StringLiteralParser::UDSuffixResult IsStringUDSuffix = +StringLiteralParser::UDSuffixResult::Invalid; if (C == '_') IsUDSuffix = true; else if (IsStringLiteral && getLangOpts().CPlusPlus14) { @@ -1713,9 +1715,18 @@ getLangOpts()); if (!isIdentifierBody(Next)) { // End of suffix. Check whether this is on the whitelist. - IsUDSuffix = (Chars == 1 && Buffer[0] == 's') || - NumericLiteralParser::isValidUDSuffix( - getLangOpts(), StringRef(Buffer, Chars)); + const StringRef CompleteSuffix = StringRef(Buffer, Chars); + const LangOptions = getLangOpts(); + // First, check if the suffix is a numeric suffix (s,sv) + IsUDSuffix = + NumericLiteralParser::isValidUDSuffix(LangOpts, CompleteSuffix); + // If it is not, check for a string suffix + if (!IsUDSuffix) { +IsStringUDSuffix = +StringLiteralParser::isValidUDSuffix(LangOpts, CompleteSuffix); +IsUDSuffix = +IsStringUDSuffix == StringLiteralParser::UDSuffixResult::Valid; + } break; } @@ -1730,10 +1741,16 @@ if (!IsUDSuffix) { if (!isLexingRawMode()) -Diag(CurPtr, getLangOpts().MSVCCompat - ? diag::ext_ms_reserved_user_defined_literal - : diag::ext_reserved_user_defined_literal) - << FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); +if (IsStringUDSuffix == +StringLiteralParser::UDSuffixResult::SVIncompatible) { + Diag(CurPtr, diag::err_cxx1z_string_view_literal) +<< FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); +} else { + Diag(CurPtr, getLangOpts().MSVCCompat + ? diag::ext_ms_reserved_user_defined_literal + : diag::ext_reserved_user_defined_literal) +<< FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); +
[PATCH] D26830: [libcxx] Add string_view literals
AntonBikineev marked an inline comment as done. AntonBikineev added inline comments. Comment at: include/string_view:749 +inline namespace literals +{ EricWF wrote: > AntonBikineev wrote: > > EricWF wrote: > > > If this is new to C++17 then the new declarations should be guarded by > > > `#if _LIBCPP_VERSION > 14`. > > Eric, I was thinking about it, but the fact that the whole string_view code > > is not guarded by _LIBCPP_VERSION > 14 (I guess it's because it can be > > compiled with lower Standards just fine) stopped me from doing that. I'm > > still not sure though. > Understandable. The decision to backport most of `string_view` was > intentional. > > However we shouldn't backport these, since the literal suffix is only > supported by the compiler in C++17. Agreed https://reviews.llvm.org/D26830 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26830: [libcxx] Add string_view literals
AntonBikineev updated this revision to Diff 78498. https://reviews.llvm.org/D26830 Files: include/string_view test/std/strings/string.view/string.view.literals/literal.pass.cpp test/std/strings/string.view/string.view.literals/literal1.fail.cpp test/std/strings/string.view/string.view.literals/literal1.pass.cpp test/std/strings/string.view/string.view.literals/literal2.fail.cpp test/std/strings/string.view/string.view.literals/literal2.pass.cpp test/std/strings/string.view/string.view.literals/literal3.pass.cpp Index: test/std/strings/string.view/string.view.literals/literal3.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal3.pass.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using namespace std; + +string_view foo = ""sv; +} Index: test/std/strings/string.view/string.view.literals/literal2.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal2.pass.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using namespace std::literals::string_view_literals; + +std::string_view foo = ""sv; +} Index: test/std/strings/string.view/string.view.literals/literal2.fail.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal2.fail.cpp @@ -0,0 +1,19 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +std::string_view foo = ""sv; // should fail w/conversion operator not found +} Index: test/std/strings/string.view/string.view.literals/literal1.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal1.pass.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using namespace std::literals; + +std::string_view foo = ""sv; +} Index: test/std/strings/string.view/string.view.literals/literal1.fail.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal1.fail.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using std::string_view; + +string_view foo = ""sv; // should fail w/conversion operator not found +} Index: test/std/strings/string.view/string.view.literals/literal.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal.pass.cpp @@ -0,0 +1,45 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and
[PATCH] D26830: [libcxx] Add string_view literals
AntonBikineev updated this revision to Diff 78497. https://reviews.llvm.org/D26830 Files: include/string_view test/std/strings/string.view/string.view.literals/literal.pass.cpp test/std/strings/string.view/string.view.literals/literal1.fail.cpp test/std/strings/string.view/string.view.literals/literal1.pass.cpp test/std/strings/string.view/string.view.literals/literal2.fail.cpp test/std/strings/string.view/string.view.literals/literal2.pass.cpp test/std/strings/string.view/string.view.literals/literal3.pass.cpp Index: test/std/strings/string.view/string.view.literals/literal3.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal3.pass.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using namespace std; + +string_view foo = ""sv; +} Index: test/std/strings/string.view/string.view.literals/literal2.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal2.pass.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using namespace std::literals::string_view_literals; + +std::string_view foo = ""sv; +} Index: test/std/strings/string.view/string.view.literals/literal2.fail.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal2.fail.cpp @@ -0,0 +1,19 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +std::string_view foo = ""sv; // should fail w/conversion operator not found +} Index: test/std/strings/string.view/string.view.literals/literal1.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal1.pass.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using namespace std::literals; + +std::string_view foo = ""sv; +} Index: test/std/strings/string.view/string.view.literals/literal1.fail.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal1.fail.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using std::string_view; + +string_view foo = ""sv; // should fail w/conversion operator not found +} Index: test/std/strings/string.view/string.view.literals/literal.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal.pass.cpp @@ -0,0 +1,45 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and
[PATCH] D26830: [libcxx] Add string_view literals
AntonBikineev updated this revision to Diff 78493. AntonBikineev marked an inline comment as done. https://reviews.llvm.org/D26830 Files: include/string_view test/std/strings/string.view/string.view.literals/literal.pass.cpp test/std/strings/string.view/string.view.literals/literal1.fail.cpp test/std/strings/string.view/string.view.literals/literal1.pass.cpp test/std/strings/string.view/string.view.literals/literal2.fail.cpp test/std/strings/string.view/string.view.literals/literal2.pass.cpp test/std/strings/string.view/string.view.literals/literal3.pass.cpp Index: test/std/strings/string.view/string.view.literals/literal3.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal3.pass.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using namespace std; + +string_view foo = ""sv; +} Index: test/std/strings/string.view/string.view.literals/literal2.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal2.pass.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using namespace std::literals::string_view_literals; + +std::string_view foo = ""sv; +} Index: test/std/strings/string.view/string.view.literals/literal2.fail.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal2.fail.cpp @@ -0,0 +1,19 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +std::string_view foo = ""sv; // should fail w/conversion operator not found +} Index: test/std/strings/string.view/string.view.literals/literal1.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal1.pass.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using namespace std::literals; + +std::string_view foo = ""sv; +} Index: test/std/strings/string.view/string.view.literals/literal1.fail.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal1.fail.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using std::string_view; + +string_view foo = ""sv; // should fail w/conversion operator not found +} Index: test/std/strings/string.view/string.view.literals/literal.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal.pass.cpp @@ -0,0 +1,45 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +//
[PATCH] D26830: [libcxx] Add string_view literals
AntonBikineev added inline comments. Comment at: include/string_view:749 +inline namespace literals +{ EricWF wrote: > If this is new to C++17 then the new declarations should be guarded by `#if > _LIBCPP_VERSION > 14`. Eric, I was thinking about it, but the fact that the whole string_view code is not guarded by _LIBCPP_VERSION > 14 (I guess it's because it can be compiled with lower Standards just fine) stopped me from doing that. I'm still not sure though. https://reviews.llvm.org/D26830 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26829: [clang] Allow lexer to handle string_view literals
AntonBikineev updated this revision to Diff 78490. https://reviews.llvm.org/D26829 Files: include/clang/Basic/DiagnosticLexKinds.td lib/Lex/Lexer.cpp Index: lib/Lex/Lexer.cpp === --- lib/Lex/Lexer.cpp +++ lib/Lex/Lexer.cpp @@ -1713,6 +1713,13 @@ getLangOpts()); if (!isIdentifierBody(Next)) { // End of suffix. Check whether this is on the whitelist. + if (Chars == 2 && Buffer[0] == 's' && Buffer[1] == 'v') { +IsUDSuffix = true; +if (!getLangOpts().CPlusPlus1z) + Diag(CurPtr, diag::warn_cxx1z_string_view_literal) +<< FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); +break; + } IsUDSuffix = (Chars == 1 && Buffer[0] == 's') || NumericLiteralParser::isValidUDSuffix( getLangOpts(), StringRef(Buffer, Chars)); Index: include/clang/Basic/DiagnosticLexKinds.td === --- include/clang/Basic/DiagnosticLexKinds.td +++ include/clang/Basic/DiagnosticLexKinds.td @@ -186,6 +186,8 @@ "hexadecimal floating literals are incompatible with " "C++ standards before C++1z">, InGroup, DefaultIgnore; +def warn_cxx1z_string_view_literal : Warning< + "string_view literals are a C++1z feature">, InGroup; def ext_binary_literal : Extension< "binary integer literals are a GNU extension">, InGroup; def ext_binary_literal_cxx14 : Extension< Index: lib/Lex/Lexer.cpp === --- lib/Lex/Lexer.cpp +++ lib/Lex/Lexer.cpp @@ -1713,6 +1713,13 @@ getLangOpts()); if (!isIdentifierBody(Next)) { // End of suffix. Check whether this is on the whitelist. + if (Chars == 2 && Buffer[0] == 's' && Buffer[1] == 'v') { +IsUDSuffix = true; +if (!getLangOpts().CPlusPlus1z) + Diag(CurPtr, diag::warn_cxx1z_string_view_literal) +<< FixItHint::CreateInsertion(getSourceLocation(CurPtr), " "); +break; + } IsUDSuffix = (Chars == 1 && Buffer[0] == 's') || NumericLiteralParser::isValidUDSuffix( getLangOpts(), StringRef(Buffer, Chars)); Index: include/clang/Basic/DiagnosticLexKinds.td === --- include/clang/Basic/DiagnosticLexKinds.td +++ include/clang/Basic/DiagnosticLexKinds.td @@ -186,6 +186,8 @@ "hexadecimal floating literals are incompatible with " "C++ standards before C++1z">, InGroup, DefaultIgnore; +def warn_cxx1z_string_view_literal : Warning< + "string_view literals are a C++1z feature">, InGroup; def ext_binary_literal : Extension< "binary integer literals are a GNU extension">, InGroup; def ext_binary_literal_cxx14 : Extension< ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D26830: [libcxx] Add string_view literals
AntonBikineev created this revision. AntonBikineev added reviewers: mclow.lists, rsmith, cfe-commits. Herald added a reviewer: EricWF. https://reviews.llvm.org/D26830 Files: include/string_view test/std/strings/string.view/string.view.literals/literal.pass.cpp test/std/strings/string.view/string.view.literals/literal1.fail.cpp test/std/strings/string.view/string.view.literals/literal1.pass.cpp test/std/strings/string.view/string.view.literals/literal2.fail.cpp test/std/strings/string.view/string.view.literals/literal2.pass.cpp test/std/strings/string.view/string.view.literals/literal3.pass.cpp Index: test/std/strings/string.view/string.view.literals/literal3.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal3.pass.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using namespace std; + +string_view foo = ""sv; +} Index: test/std/strings/string.view/string.view.literals/literal2.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal2.pass.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using namespace std::literals::string_view_literals; + +std::string_view foo = ""sv; +} Index: test/std/strings/string.view/string.view.literals/literal2.fail.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal2.fail.cpp @@ -0,0 +1,19 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +std::string_view foo = ""sv; // should fail w/conversion operator not found +} Index: test/std/strings/string.view/string.view.literals/literal1.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal1.pass.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using namespace std::literals; + +std::string_view foo = ""sv; +} Index: test/std/strings/string.view/string.view.literals/literal1.fail.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal1.fail.cpp @@ -0,0 +1,21 @@ +// -*- C++ -*- +//===--===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===--===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +#include +#include + +int main() +{ +using std::string_view; + +string_view foo = ""sv; // should fail w/conversion operator not found +} Index: test/std/strings/string.view/string.view.literals/literal.pass.cpp === --- /dev/null +++ test/std/strings/string.view/string.view.literals/literal.pass.cpp @@ -0,0 +1,45 @@ +// -*- C++ -*- +//===--===// +// +//
[PATCH] D26829: [clang] Allow lexer to handle string_view literals
AntonBikineev created this revision. AntonBikineev added reviewers: mclow.lists, rsmith, cfe-commits. https://reviews.llvm.org/D26829 Files: lib/Lex/Lexer.cpp Index: lib/Lex/Lexer.cpp === --- lib/Lex/Lexer.cpp +++ lib/Lex/Lexer.cpp @@ -1713,6 +1713,11 @@ getLangOpts()); if (!isIdentifierBody(Next)) { // End of suffix. Check whether this is on the whitelist. + if (getLangOpts().CPlusPlus1z && Chars == 2 && + Buffer[0] == 's' && Buffer[1] == 'v') { +IsUDSuffix = true; +break; + } IsUDSuffix = (Chars == 1 && Buffer[0] == 's') || NumericLiteralParser::isValidUDSuffix( getLangOpts(), StringRef(Buffer, Chars)); Index: lib/Lex/Lexer.cpp === --- lib/Lex/Lexer.cpp +++ lib/Lex/Lexer.cpp @@ -1713,6 +1713,11 @@ getLangOpts()); if (!isIdentifierBody(Next)) { // End of suffix. Check whether this is on the whitelist. + if (getLangOpts().CPlusPlus1z && Chars == 2 && + Buffer[0] == 's' && Buffer[1] == 'v') { +IsUDSuffix = true; +break; + } IsUDSuffix = (Chars == 1 && Buffer[0] == 's') || NumericLiteralParser::isValidUDSuffix( getLangOpts(), StringRef(Buffer, Chars)); ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D21834: Implementing 'If statement with Initializer'
AntonBikineev updated this revision to Diff 63475. AntonBikineev added a comment. Moved stars to the right side of declarations http://reviews.llvm.org/D21834 Files: include/clang/AST/Stmt.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/ASTImporter.cpp lib/AST/ExprConstant.cpp lib/AST/Stmt.cpp lib/Analysis/BodyFarm.cpp lib/Analysis/CFG.cpp lib/CodeGen/CGStmt.cpp lib/Sema/JumpDiagnostics.cpp lib/Sema/SemaStmt.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp test/CodeGenCXX/cxx1z-init-statement.cpp test/PCH/cxx1z-init-statement.cpp test/PCH/cxx1z-init-statement.h test/Parser/cxx1z-init-statement.cpp test/SemaCXX/cxx1z-init-statement-warn-unused.cpp test/SemaCXX/cxx1z-init-statement.cpp Index: test/SemaCXX/cxx1z-init-statement.cpp === --- test/SemaCXX/cxx1z-init-statement.cpp +++ test/SemaCXX/cxx1z-init-statement.cpp @@ -0,0 +1,91 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +void testIf() { + int x = 0; + if (x; x) ++x; + if (int t = 0; t) ++t; else --t; + + if (int x, y = 0; y) // expected-note 2 {{previous definition is here}} +int x = 0; // expected-error {{redefinition of 'x'}} + else +int x = 0; // expected-error {{redefinition of 'x'}} + + if (x; int a = 0) ++a; + if (x, +x; int a = 0) // expected-note 2 {{previous definition is here}} expected-warning {{unused}} +int a = 0; // expected-error {{redefinition of 'a'}} + else +int a = 0; // expected-error {{redefinition of 'a'}} + + if (int b = 0; b) +; + b = 2; // expected-error {{use of undeclared identifier}} +} + +void testSwitch() { + int x = 0; + switch (x; x) { +case 1: + ++x; + } + + switch (int x, y = 0; y) { +case 1: + ++x; +default: + ++y; + } + + switch (int x, y = 0; y) { // expected-note 2 {{previous definition is here}} +case 0: + int x = 0; // expected-error {{redefinition of 'x'}} +case 1: + int y = 0; // expected-error {{redefinition of 'y'}} + }; + + switch (x; int a = 0) { +case 0: + ++a; + } + + switch (x, +x; int a = 0) { // expected-note {{previous definition is here}} expected-warning {{unused}} +case 0: + int a = 0; // expected-error {{redefinition of 'a'}} // expected-note {{previous definition is here}} +case 1: + int a = 0; // expected-error {{redefinition of 'a'}} + } + + switch (int b = 0; b) { +case 0: + break; + } + b = 2; // expected-error {{use of undeclared identifier}} +} + +constexpr bool constexpr_if_init(int n) { + if (int a = n; ++a > 0) +return true; + else +return false; +} + +constexpr int constexpr_switch_init(int n) { + switch (int p = n + 2; p) { +case 0: + return 0; +case 1: + return 1; +default: + return -1; + } +} + +void test_constexpr_init_stmt() { + constexpr bool a = constexpr_if_init(-2); + static_assert(!a, ""); + static_assert(constexpr_if_init(1), ""); + + constexpr int b = constexpr_switch_init(-1); + static_assert(b == 1, ""); + static_assert(constexpr_switch_init(-2) == 0, ""); + static_assert(constexpr_switch_init(-5) == -1, ""); +} Index: test/SemaCXX/cxx1z-init-statement-warn-unused.cpp === --- test/SemaCXX/cxx1z-init-statement-warn-unused.cpp +++ test/SemaCXX/cxx1z-init-statement-warn-unused.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -std=c++1z -verify -Wuninitialized %s + +void testIf() { + if (bool b; b) // expected-warning {{uninitialized}} expected-note {{to silence}} +; + if (int a, b = 2; a) // expected-warning {{uninitialized}} expected-note {{to silence}} +; + int a; + if (a = 0; a) {} // OK +} + +void testSwitch() { + switch (bool b; b) { // expected-warning {{uninitialized}} expected-warning {{boolean value}} expected-note {{to silence}} +case 0: + break; + } + switch (int a, b = 7; a) { // expected-warning {{uninitialized}} expected-note {{to silence}} +case 0: + break; + } + int c; + switch (c = 0; c) { // OK +case 0: + break; + } +} Index: test/Parser/cxx1z-init-statement.cpp === --- test/Parser/cxx1z-init-statement.cpp +++ test/Parser/cxx1z-init-statement.cpp @@ -4,18 +4,18 @@ typedef int T; int f() { // init-statement declarations - if (T n = 0; n != 0) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T(f()); f()) {} // expected-error {{not yet supported}} - if (T(f()), g, h; f()) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T f(), g, h; f()) {} // expected-error {{not yet supported}} - if (T(n) = 0; n) {} // expected-error {{not yet supported}} + if (T n = 0; n != 0) {} + if (T f(); f()) {} + if (T(f()); f())
Re: [PATCH] D21834: Implementing 'If statement with Initializer'
AntonBikineev updated this revision to Diff 63474. http://reviews.llvm.org/D21834 Files: include/clang/AST/Stmt.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/ASTImporter.cpp lib/AST/ExprConstant.cpp lib/AST/Stmt.cpp lib/Analysis/BodyFarm.cpp lib/Analysis/CFG.cpp lib/CodeGen/CGStmt.cpp lib/Sema/JumpDiagnostics.cpp lib/Sema/SemaStmt.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp test/CodeGenCXX/cxx1z-init-statement.cpp test/PCH/cxx1z-init-statement.cpp test/PCH/cxx1z-init-statement.h test/Parser/cxx1z-init-statement.cpp test/SemaCXX/cxx1z-init-statement-warn-unused.cpp test/SemaCXX/cxx1z-init-statement.cpp Index: test/SemaCXX/cxx1z-init-statement.cpp === --- test/SemaCXX/cxx1z-init-statement.cpp +++ test/SemaCXX/cxx1z-init-statement.cpp @@ -0,0 +1,91 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +void testIf() { + int x = 0; + if (x; x) ++x; + if (int t = 0; t) ++t; else --t; + + if (int x, y = 0; y) // expected-note 2 {{previous definition is here}} +int x = 0; // expected-error {{redefinition of 'x'}} + else +int x = 0; // expected-error {{redefinition of 'x'}} + + if (x; int a = 0) ++a; + if (x, +x; int a = 0) // expected-note 2 {{previous definition is here}} expected-warning {{unused}} +int a = 0; // expected-error {{redefinition of 'a'}} + else +int a = 0; // expected-error {{redefinition of 'a'}} + + if (int b = 0; b) +; + b = 2; // expected-error {{use of undeclared identifier}} +} + +void testSwitch() { + int x = 0; + switch (x; x) { +case 1: + ++x; + } + + switch (int x, y = 0; y) { +case 1: + ++x; +default: + ++y; + } + + switch (int x, y = 0; y) { // expected-note 2 {{previous definition is here}} +case 0: + int x = 0; // expected-error {{redefinition of 'x'}} +case 1: + int y = 0; // expected-error {{redefinition of 'y'}} + }; + + switch (x; int a = 0) { +case 0: + ++a; + } + + switch (x, +x; int a = 0) { // expected-note {{previous definition is here}} expected-warning {{unused}} +case 0: + int a = 0; // expected-error {{redefinition of 'a'}} // expected-note {{previous definition is here}} +case 1: + int a = 0; // expected-error {{redefinition of 'a'}} + } + + switch (int b = 0; b) { +case 0: + break; + } + b = 2; // expected-error {{use of undeclared identifier}} +} + +constexpr bool constexpr_if_init(int n) { + if (int a = n; ++a > 0) +return true; + else +return false; +} + +constexpr int constexpr_switch_init(int n) { + switch (int p = n + 2; p) { +case 0: + return 0; +case 1: + return 1; +default: + return -1; + } +} + +void test_constexpr_init_stmt() { + constexpr bool a = constexpr_if_init(-2); + static_assert(!a, ""); + static_assert(constexpr_if_init(1), ""); + + constexpr int b = constexpr_switch_init(-1); + static_assert(b == 1, ""); + static_assert(constexpr_switch_init(-2) == 0, ""); + static_assert(constexpr_switch_init(-5) == -1, ""); +} Index: test/SemaCXX/cxx1z-init-statement-warn-unused.cpp === --- test/SemaCXX/cxx1z-init-statement-warn-unused.cpp +++ test/SemaCXX/cxx1z-init-statement-warn-unused.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -std=c++1z -verify -Wuninitialized %s + +void testIf() { + if (bool b; b) // expected-warning {{uninitialized}} expected-note {{to silence}} +; + if (int a, b = 2; a) // expected-warning {{uninitialized}} expected-note {{to silence}} +; + int a; + if (a = 0; a) {} // OK +} + +void testSwitch() { + switch (bool b; b) { // expected-warning {{uninitialized}} expected-warning {{boolean value}} expected-note {{to silence}} +case 0: + break; + } + switch (int a, b = 7; a) { // expected-warning {{uninitialized}} expected-note {{to silence}} +case 0: + break; + } + int c; + switch (c = 0; c) { // OK +case 0: + break; + } +} Index: test/Parser/cxx1z-init-statement.cpp === --- test/Parser/cxx1z-init-statement.cpp +++ test/Parser/cxx1z-init-statement.cpp @@ -4,18 +4,18 @@ typedef int T; int f() { // init-statement declarations - if (T n = 0; n != 0) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T(f()); f()) {} // expected-error {{not yet supported}} - if (T(f()), g, h; f()) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T f(), g, h; f()) {} // expected-error {{not yet supported}} - if (T(n) = 0; n) {} // expected-error {{not yet supported}} + if (T n = 0; n != 0) {} + if (T f(); f()) {} + if (T(f()); f()) {} + if (T(f()), g, h; f()) {} + if (T f(); f()) {} + if (T f(), g, h; f())
Re: [PATCH] D21834: Implementing 'If statement with Initializer'
AntonBikineev updated this revision to Diff 63473. AntonBikineev added a comment. removed a leftover from parser/cxx1z-init-stmt.cpp test http://reviews.llvm.org/D21834 Files: include/clang/AST/Stmt.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/ASTImporter.cpp lib/AST/ExprConstant.cpp lib/AST/Stmt.cpp lib/Analysis/BodyFarm.cpp lib/Analysis/CFG.cpp lib/CodeGen/CGStmt.cpp lib/Sema/JumpDiagnostics.cpp lib/Sema/SemaStmt.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp test/CodeGenCXX/cxx1z-init-statement.cpp test/PCH/cxx1z-init-statement.cpp test/PCH/cxx1z-init-statement.h test/Parser/cxx1z-init-statement.cpp test/SemaCXX/cxx1z-init-statement-warn-unused.cpp test/SemaCXX/cxx1z-init-statement.cpp Index: test/SemaCXX/cxx1z-init-statement.cpp === --- test/SemaCXX/cxx1z-init-statement.cpp +++ test/SemaCXX/cxx1z-init-statement.cpp @@ -0,0 +1,91 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +void testIf() { + int x = 0; + if (x; x) ++x; + if (int t = 0; t) ++t; else --t; + + if (int x, y = 0; y) // expected-note 2 {{previous definition is here}} +int x = 0; // expected-error {{redefinition of 'x'}} + else +int x = 0; // expected-error {{redefinition of 'x'}} + + if (x; int a = 0) ++a; + if (x, +x; int a = 0) // expected-note 2 {{previous definition is here}} expected-warning {{unused}} +int a = 0; // expected-error {{redefinition of 'a'}} + else +int a = 0; // expected-error {{redefinition of 'a'}} + + if (int b = 0; b) +; + b = 2; // expected-error {{use of undeclared identifier}} +} + +void testSwitch() { + int x = 0; + switch (x; x) { +case 1: + ++x; + } + + switch (int x, y = 0; y) { +case 1: + ++x; +default: + ++y; + } + + switch (int x, y = 0; y) { // expected-note 2 {{previous definition is here}} +case 0: + int x = 0; // expected-error {{redefinition of 'x'}} +case 1: + int y = 0; // expected-error {{redefinition of 'y'}} + }; + + switch (x; int a = 0) { +case 0: + ++a; + } + + switch (x, +x; int a = 0) { // expected-note {{previous definition is here}} expected-warning {{unused}} +case 0: + int a = 0; // expected-error {{redefinition of 'a'}} // expected-note {{previous definition is here}} +case 1: + int a = 0; // expected-error {{redefinition of 'a'}} + } + + switch (int b = 0; b) { +case 0: + break; + } + b = 2; // expected-error {{use of undeclared identifier}} +} + +constexpr bool constexpr_if_init(int n) { + if (int a = n; ++a > 0) +return true; + else +return false; +} + +constexpr int constexpr_switch_init(int n) { + switch (int p = n + 2; p) { +case 0: + return 0; +case 1: + return 1; +default: + return -1; + } +} + +void test_constexpr_init_stmt() { + constexpr bool a = constexpr_if_init(-2); + static_assert(!a, ""); + static_assert(constexpr_if_init(1), ""); + + constexpr int b = constexpr_switch_init(-1); + static_assert(b == 1, ""); + static_assert(constexpr_switch_init(-2) == 0, ""); + static_assert(constexpr_switch_init(-5) == -1, ""); +} Index: test/SemaCXX/cxx1z-init-statement-warn-unused.cpp === --- test/SemaCXX/cxx1z-init-statement-warn-unused.cpp +++ test/SemaCXX/cxx1z-init-statement-warn-unused.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -std=c++1z -verify -Wuninitialized %s + +void testIf() { + if (bool b; b) // expected-warning {{uninitialized}} expected-note {{to silence}} +; + if (int a, b = 2; a) // expected-warning {{uninitialized}} expected-note {{to silence}} +; + int a; + if (a = 0; a) {} // OK +} + +void testSwitch() { + switch (bool b; b) { // expected-warning {{uninitialized}} expected-warning {{boolean value}} expected-note {{to silence}} +case 0: + break; + } + switch (int a, b = 7; a) { // expected-warning {{uninitialized}} expected-note {{to silence}} +case 0: + break; + } + int c; + switch (c = 0; c) { // OK +case 0: + break; + } +} Index: test/Parser/cxx1z-init-statement.cpp === --- test/Parser/cxx1z-init-statement.cpp +++ test/Parser/cxx1z-init-statement.cpp @@ -4,18 +4,18 @@ typedef int T; int f() { // init-statement declarations - if (T n = 0; n != 0) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T(f()); f()) {} // expected-error {{not yet supported}} - if (T(f()), g, h; f()) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T f(), g, h; f()) {} // expected-error {{not yet supported}} + if (T n = 0; n != 0) {} + if (T f(); f()) {} + if (T(f()); f()) {} + if (T(f()), g, h; f()) {} + if (T f(); f()) {}
Re: [PATCH] D21834: Implementing 'If statement with Initializer'
AntonBikineev updated this revision to Diff 63472. http://reviews.llvm.org/D21834 Files: include/clang/AST/Stmt.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/ASTImporter.cpp lib/AST/ExprConstant.cpp lib/AST/Stmt.cpp lib/Analysis/BodyFarm.cpp lib/Analysis/CFG.cpp lib/CodeGen/CGStmt.cpp lib/Sema/JumpDiagnostics.cpp lib/Sema/SemaStmt.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp test/CodeGenCXX/cxx1z-init-statement.cpp test/PCH/cxx1z-init-statement.cpp test/PCH/cxx1z-init-statement.h test/Parser/cxx1z-init-statement.cpp test/SemaCXX/cxx1z-init-statement-warn-unused.cpp test/SemaCXX/cxx1z-init-statement.cpp Index: test/SemaCXX/cxx1z-init-statement.cpp === --- test/SemaCXX/cxx1z-init-statement.cpp +++ test/SemaCXX/cxx1z-init-statement.cpp @@ -0,0 +1,91 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +void testIf() { + int x = 0; + if (x; x) ++x; + if (int t = 0; t) ++t; else --t; + + if (int x, y = 0; y) // expected-note 2 {{previous definition is here}} +int x = 0; // expected-error {{redefinition of 'x'}} + else +int x = 0; // expected-error {{redefinition of 'x'}} + + if (x; int a = 0) ++a; + if (x, +x; int a = 0) // expected-note 2 {{previous definition is here}} expected-warning {{unused}} +int a = 0; // expected-error {{redefinition of 'a'}} + else +int a = 0; // expected-error {{redefinition of 'a'}} + + if (int b = 0; b) +; + b = 2; // expected-error {{use of undeclared identifier}} +} + +void testSwitch() { + int x = 0; + switch (x; x) { +case 1: + ++x; + } + + switch (int x, y = 0; y) { +case 1: + ++x; +default: + ++y; + } + + switch (int x, y = 0; y) { // expected-note 2 {{previous definition is here}} +case 0: + int x = 0; // expected-error {{redefinition of 'x'}} +case 1: + int y = 0; // expected-error {{redefinition of 'y'}} + }; + + switch (x; int a = 0) { +case 0: + ++a; + } + + switch (x, +x; int a = 0) { // expected-note {{previous definition is here}} expected-warning {{unused}} +case 0: + int a = 0; // expected-error {{redefinition of 'a'}} // expected-note {{previous definition is here}} +case 1: + int a = 0; // expected-error {{redefinition of 'a'}} + } + + switch (int b = 0; b) { +case 0: + break; + } + b = 2; // expected-error {{use of undeclared identifier}} +} + +constexpr bool constexpr_if_init(int n) { + if (int a = n; ++a > 0) +return true; + else +return false; +} + +constexpr int constexpr_switch_init(int n) { + switch (int p = n + 2; p) { +case 0: + return 0; +case 1: + return 1; +default: + return -1; + } +} + +void test_constexpr_init_stmt() { + constexpr bool a = constexpr_if_init(-2); + static_assert(!a, ""); + static_assert(constexpr_if_init(1), ""); + + constexpr int b = constexpr_switch_init(-1); + static_assert(b == 1, ""); + static_assert(constexpr_switch_init(-2) == 0, ""); + static_assert(constexpr_switch_init(-5) == -1, ""); +} Index: test/SemaCXX/cxx1z-init-statement-warn-unused.cpp === --- test/SemaCXX/cxx1z-init-statement-warn-unused.cpp +++ test/SemaCXX/cxx1z-init-statement-warn-unused.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -std=c++1z -verify -Wuninitialized %s + +void testIf() { + if (bool b; b) // expected-warning {{uninitialized}} expected-note {{to silence}} +; + if (int a, b = 2; a) // expected-warning {{uninitialized}} expected-note {{to silence}} +; + int a; + if (a = 0; a) {} // OK +} + +void testSwitch() { + switch (bool b; b) { // expected-warning {{uninitialized}} expected-warning {{boolean value}} expected-note {{to silence}} +case 0: + break; + } + switch (int a, b = 7; a) { // expected-warning {{uninitialized}} expected-note {{to silence}} +case 0: + break; + } + int c; + switch (c = 0; c) { // OK +case 0: + break; + } +} Index: test/Parser/cxx1z-init-statement.cpp === --- test/Parser/cxx1z-init-statement.cpp +++ test/Parser/cxx1z-init-statement.cpp @@ -4,18 +4,18 @@ typedef int T; int f() { // init-statement declarations - if (T n = 0; n != 0) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T(f()); f()) {} // expected-error {{not yet supported}} - if (T(f()), g, h; f()) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T f(), g, h; f()) {} // expected-error {{not yet supported}} + if (T n = 0; n != 0) {} + if (T f(); f()) {} + if (T(f()); f()) {} + if (T(f()), g, h; f()) {} + if (T f(); f()) {} + if (T f(), g, h; f()) {} if (T(n) = 0; n) {} // expected-error {{not yet
Re: [PATCH] D21834: Implementing 'If statement with Initializer'
AntonBikineev updated the summary for this revision. AntonBikineev updated this revision to Diff 63471. AntonBikineev added a comment. @rsmith, Richard, again, thank you for guiding. I've addressed your comments. http://reviews.llvm.org/D21834 Files: include/clang/AST/Stmt.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/ASTImporter.cpp lib/AST/ExprConstant.cpp lib/AST/Stmt.cpp lib/Analysis/BodyFarm.cpp lib/Analysis/CFG.cpp lib/CodeGen/CGStmt.cpp lib/Sema/JumpDiagnostics.cpp lib/Sema/SemaStmt.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp test/CodeGenCXX/cxx1z-init-statement.cpp test/PCH/cxx1z-init-statement.cpp test/PCH/cxx1z-init-statement.h test/Parser/cxx1z-init-statement.cpp test/SemaCXX/cxx1z-init-statement-warn-unused.cpp test/SemaCXX/cxx1z-init-statement.cpp Index: test/SemaCXX/cxx1z-init-statement.cpp === --- test/SemaCXX/cxx1z-init-statement.cpp +++ test/SemaCXX/cxx1z-init-statement.cpp @@ -0,0 +1,91 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +void testIf() { + int x = 0; + if (x; x) ++x; + if (int t = 0; t) ++t; else --t; + + if (int x, y = 0; y) // expected-note 2 {{previous definition is here}} +int x = 0; // expected-error {{redefinition of 'x'}} + else +int x = 0; // expected-error {{redefinition of 'x'}} + + if (x; int a = 0) ++a; + if (x, +x; int a = 0) // expected-note 2 {{previous definition is here}} expected-warning {{unused}} +int a = 0; // expected-error {{redefinition of 'a'}} + else +int a = 0; // expected-error {{redefinition of 'a'}} + + if (int b = 0; b) +; + b = 2; // expected-error {{use of undeclared identifier}} +} + +void testSwitch() { + int x = 0; + switch (x; x) { +case 1: + ++x; + } + + switch (int x, y = 0; y) { +case 1: + ++x; +default: + ++y; + } + + switch (int x, y = 0; y) { // expected-note 2 {{previous definition is here}} +case 0: + int x = 0; // expected-error {{redefinition of 'x'}} +case 1: + int y = 0; // expected-error {{redefinition of 'y'}} + }; + + switch (x; int a = 0) { +case 0: + ++a; + } + + switch (x, +x; int a = 0) { // expected-note {{previous definition is here}} expected-warning {{unused}} +case 0: + int a = 0; // expected-error {{redefinition of 'a'}} // expected-note {{previous definition is here}} +case 1: + int a = 0; // expected-error {{redefinition of 'a'}} + } + + switch (int b = 0; b) { +case 0: + break; + } + b = 2; // expected-error {{use of undeclared identifier}} +} + +constexpr bool constexpr_if_init(int n) { + if (int a = n; ++a > 0) +return true; + else +return false; +} + +constexpr int constexpr_switch_init(int n) { + switch (int p = n + 2; p) { +case 0: + return 0; +case 1: + return 1; +default: + return -1; + } +} + +void test_constexpr_init_stmt() { + constexpr bool a = constexpr_if_init(-2); + static_assert(!a, ""); + static_assert(constexpr_if_init(1), ""); + + constexpr int b = constexpr_switch_init(-1); + static_assert(b == 1, ""); + static_assert(constexpr_switch_init(-2) == 0, ""); + static_assert(constexpr_switch_init(-5) == -1, ""); +} Index: test/SemaCXX/cxx1z-init-statement-warn-unused.cpp === --- test/SemaCXX/cxx1z-init-statement-warn-unused.cpp +++ test/SemaCXX/cxx1z-init-statement-warn-unused.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -std=c++1z -verify -Wuninitialized %s + +void testIf() { + if (bool b; b) // expected-warning {{uninitialized}} expected-note {{to silence}} +; + if (int a, b = 2; a) // expected-warning {{uninitialized}} expected-note {{to silence}} +; + int a; + if (a = 0; a) {} // OK +} + +void testSwitch() { + switch (bool b; b) { // expected-warning {{uninitialized}} expected-warning {{boolean value}} expected-note {{to silence}} +case 0: + break; + } + switch (int a, b = 7; a) { // expected-warning {{uninitialized}} expected-note {{to silence}} +case 0: + break; + } + int c; + switch (c = 0; c) { // OK +case 0: + break; + } +} Index: test/Parser/cxx1z-init-statement.cpp === --- test/Parser/cxx1z-init-statement.cpp +++ test/Parser/cxx1z-init-statement.cpp @@ -4,18 +4,18 @@ typedef int T; int f() { // init-statement declarations - if (T n = 0; n != 0) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T(f()); f()) {} // expected-error {{not yet supported}} - if (T(f()), g, h; f()) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T f(), g, h; f()) {} // expected-error {{not yet supported}} + if (T n = 0; n != 0) {} + if (T f(); f()) {}
Re: [PATCH] D21834: Implementing 'If statement with Initializer'
AntonBikineev updated this revision to Diff 63056. AntonBikineev added a comment. @rsmith, I've added some tests for c++1z init statement. Please let me know if there is anything else I should add or change. http://reviews.llvm.org/D21834 Files: include/clang/AST/Stmt.h include/clang/Sema/Sema.h lib/AST/ASTImporter.cpp lib/AST/ExprConstant.cpp lib/AST/Stmt.cpp lib/Analysis/BodyFarm.cpp lib/Analysis/CFG.cpp lib/CodeGen/CGStmt.cpp lib/Sema/JumpDiagnostics.cpp lib/Sema/SemaStmt.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp test/CodeGenCXX/cxx1z-init-statement.cpp test/PCH/cxx1z-init-statement.cpp test/PCH/cxx1z-init-statement.h test/Parser/cxx1z-init-statement.cpp test/SemaCXX/cxx1z-init-statement-warn-unused.cpp test/SemaCXX/cxx1z-init-statement.cpp Index: test/SemaCXX/cxx1z-init-statement.cpp === --- test/SemaCXX/cxx1z-init-statement.cpp +++ test/SemaCXX/cxx1z-init-statement.cpp @@ -0,0 +1,91 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +void testIf() { + int x = 0; + if (x; x) ++x; + if (int t = 0; t) ++t; else --t; + + if (int x, y = 0; y) // expected-note 2 {{previous definition is here}} +int x = 0; // expected-error {{redefinition of 'x'}} + else +int x = 0; // expected-error {{redefinition of 'x'}} + + if (x; int a = 0) ++a; + if (x, +x; int a = 0) // expected-note 2 {{previous definition is here}} expected-warning {{unused}} +int a = 0; // expected-error {{redefinition of 'a'}} + else +int a = 0; // expected-error {{redefinition of 'a'}} + + if (int b = 0; b) +; + b = 2; // expected-error {{use of undeclared identifier}} +} + +void testSwitch() { + int x = 0; + switch (x; x) { +case 1: + ++x; + } + + switch (int x, y = 0; y) { +case 1: + ++x; +default: + ++y; + } + + switch (int x, y = 0; y) { // expected-note 2 {{previous definition is here}} +case 0: + int x = 0; // expected-error {{redefinition of 'x'}} +case 1: + int y = 0; // expected-error {{redefinition of 'y'}} + }; + + switch (x; int a = 0) { +case 0: + ++a; + } + + switch (x, +x; int a = 0) { // expected-note {{previous definition is here}} expected-warning {{unused}} +case 0: + int a = 0; // expected-error {{redefinition of 'a'}} // expected-note {{previous definition is here}} +case 1: + int a = 0; // expected-error {{redefinition of 'a'}} + } + + switch (int b = 0; b) { +case 0: + break; + } + b = 2; // expected-error {{use of undeclared identifier}} +} + +constexpr bool constexpr_if_init(int n) { + if (int a = n; ++a > 0) +return true; + else +return false; +} + +constexpr int constexpr_switch_init(int n) { + switch (int p = n + 2; p) { +case 0: + return 0; +case 1: + return 1; +default: + return -1; + } +} + +void test_constexpr_init_stmt() { + constexpr bool a = constexpr_if_init(-2); + static_assert(!a, ""); + static_assert(constexpr_if_init(1), ""); + + constexpr int b = constexpr_switch_init(-1); + static_assert(b == 1, ""); + static_assert(constexpr_switch_init(-2) == 0, ""); + static_assert(constexpr_switch_init(-5) == -1, ""); +} Index: test/SemaCXX/cxx1z-init-statement-warn-unused.cpp === --- test/SemaCXX/cxx1z-init-statement-warn-unused.cpp +++ test/SemaCXX/cxx1z-init-statement-warn-unused.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -std=c++1z -verify -Wuninitialized %s + +void testIf() { + if (bool b; b) // expected-warning {{uninitialized}} expected-note {{to silence}} +; + if (int a, b = 2; a) // expected-warning {{uninitialized}} expected-note {{to silence}} +; +} + +void testSwitch() { + switch (bool b; b) { // expected-warning {{uninitialized}} expected-warning {{boolean value}} expected-note {{to silence}} +case 0: + break; + } + switch (int a, b = 7; a) { // expected-warning {{uninitialized}} expected-note {{to silence}} +case 0: + break; + } +} Index: test/Parser/cxx1z-init-statement.cpp === --- test/Parser/cxx1z-init-statement.cpp +++ test/Parser/cxx1z-init-statement.cpp @@ -4,17 +4,17 @@ typedef int T; int f() { // init-statement declarations - if (T n = 0; n != 0) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T(f()); f()) {} // expected-error {{not yet supported}} - if (T(f()), g, h; f()) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T f(), g, h; f()) {} // expected-error {{not yet supported}} + if (T n = 0; n != 0) {} + if (T f(); f()) {} + if (T(f()); f()) {} + if (T(f()), g, h; f()) {} + if (T f(); f()) {} + if (T f(), g, h; f()) {} // init-statement expressions - if (T{f()};
Re: [PATCH] D21834: Implementing 'If statement with Initializer'
AntonBikineev updated this revision to Diff 62790. AntonBikineev added a comment. @rsmith, Thanks for the comments, I've addressed them (except for tests, they are to be added asap). I'm especially not sure about changes in CFG.cpp, could you verify please? http://reviews.llvm.org/D21834 Files: include/clang/AST/Stmt.h include/clang/Sema/Sema.h lib/AST/ASTImporter.cpp lib/AST/ExprConstant.cpp lib/AST/Stmt.cpp lib/Analysis/BodyFarm.cpp lib/Analysis/CFG.cpp lib/CodeGen/CGStmt.cpp lib/Sema/JumpDiagnostics.cpp lib/Sema/SemaStmt.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp test/Parser/cxx1z-init-statement.cpp Index: test/Parser/cxx1z-init-statement.cpp === --- test/Parser/cxx1z-init-statement.cpp +++ test/Parser/cxx1z-init-statement.cpp @@ -4,17 +4,17 @@ typedef int T; int f() { // init-statement declarations - if (T n = 0; n != 0) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T(f()); f()) {} // expected-error {{not yet supported}} - if (T(f()), g, h; f()) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T f(), g, h; f()) {} // expected-error {{not yet supported}} + if (T n = 0; n != 0) {} + if (T f(); f()) {} + if (T(f()); f()) {} + if (T(f()), g, h; f()) {} + if (T f(); f()) {} + if (T f(), g, h; f()) {} // init-statement expressions - if (T{f()}; f()) {} // expected-error {{not yet supported}} - if (T{f()}, g, h; f()) {} // expected-error {{not yet supported}} expected-warning 2{{unused}} - if (T(f()), g, h + 1; f()) {} // expected-error {{not yet supported}} expected-warning 2{{unused}} + if (T{f()}; f()) {} + if (T{f()}, g, h; f()) {} // expected-warning 2{{unused}} + if (T(f()), g, h + 1; f()) {} // expected-warning 2{{unused}} // condition declarations if (T(n){g}) {} @@ -32,10 +32,10 @@ //if (T(n)(g)) {} // expected-err-FIXME {{not a function}} // Likewise for 'switch' - switch (int n; n) {} // expected-error {{not yet supported}} - switch (g; int g = 5) {} // expected-error {{not yet supported}} + switch (int n; n) {} + switch (g; int g = 5) {} - if (int a, b; int c = a) { // expected-error {{not yet supported}} expected-note 6{{previous}} + if (int a, b; int c = a) { // expected-note 6{{previous}} int a; // expected-error {{redefinition}} int b; // expected-error {{redefinition}} int c; // expected-error {{redefinition}} @@ -44,4 +44,6 @@ int b; // expected-error {{redefinition}} int c; // expected-error {{redefinition}} } + + return 0; } Index: lib/Serialization/ASTWriterStmt.cpp === --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -129,6 +129,7 @@ void ASTStmtWriter::VisitIfStmt(IfStmt *S) { VisitStmt(S); Record.push_back(S->isConstexpr()); + Record.AddStmt(S->getInit()); Record.AddDeclRef(S->getConditionVariable()); Record.AddStmt(S->getCond()); Record.AddStmt(S->getThen()); @@ -140,6 +141,7 @@ void ASTStmtWriter::VisitSwitchStmt(SwitchStmt *S) { VisitStmt(S); + Record.AddStmt(S->getInit()); Record.AddDeclRef(S->getConditionVariable()); Record.AddStmt(S->getCond()); Record.AddStmt(S->getBody()); Index: lib/Serialization/ASTReaderStmt.cpp === --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -185,6 +185,7 @@ void ASTStmtReader::VisitIfStmt(IfStmt *S) { VisitStmt(S); S->setConstexpr(Record[Idx++]); + S->setInit(Reader.ReadSubStmt()); S->setConditionVariable(Reader.getContext(), ReadDeclAs(Record, Idx)); S->setCond(Reader.ReadSubExpr()); @@ -196,6 +197,7 @@ void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) { VisitStmt(S); + S->setInit(Reader.ReadSubStmt()); S->setConditionVariable(Reader.getContext(), ReadDeclAs(Record, Idx)); S->setCond(Reader.ReadSubExpr()); Index: lib/Sema/TreeTransform.h === --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -1174,9 +1174,9 @@ /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, - Sema::ConditionResult Cond, Stmt *Then, + Sema::ConditionResult Cond, Stmt *Init, Stmt *Then, SourceLocation ElseLoc, Stmt *Else) { -return getSema().ActOnIfStmt(IfLoc, IsConstexpr, nullptr, Cond, Then, +return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Init, Cond, Then,
Re: [PATCH] D21834: Implementing 'If statement with Initializer'
AntonBikineev updated this revision to Diff 62321. AntonBikineev added a comment. Test Parser/cxx1z-init-statement.cpp has been updated according to Sema changes http://reviews.llvm.org/D21834 Files: include/clang/AST/Stmt.h include/clang/Sema/Sema.h lib/AST/ASTImporter.cpp lib/AST/Stmt.cpp lib/Analysis/BodyFarm.cpp lib/CodeGen/CGStmt.cpp lib/Sema/SemaStmt.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp test/Parser/cxx1z-init-statement.cpp Index: test/Parser/cxx1z-init-statement.cpp === --- test/Parser/cxx1z-init-statement.cpp +++ test/Parser/cxx1z-init-statement.cpp @@ -4,17 +4,17 @@ typedef int T; int f() { // init-statement declarations - if (T n = 0; n != 0) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T(f()); f()) {} // expected-error {{not yet supported}} - if (T(f()), g, h; f()) {} // expected-error {{not yet supported}} - if (T f(); f()) {} // expected-error {{not yet supported}} - if (T f(), g, h; f()) {} // expected-error {{not yet supported}} + if (T n = 0; n != 0) {} + if (T f(); f()) {} + if (T(f()); f()) {} + if (T(f()), g, h; f()) {} + if (T f(); f()) {} + if (T f(), g, h; f()) {} // init-statement expressions - if (T{f()}; f()) {} // expected-error {{not yet supported}} - if (T{f()}, g, h; f()) {} // expected-error {{not yet supported}} expected-warning 2{{unused}} - if (T(f()), g, h + 1; f()) {} // expected-error {{not yet supported}} expected-warning 2{{unused}} + if (T{f()}; f()) {} + if (T{f()}, g, h; f()) {} // expected-warning 2{{unused}} + if (T(f()), g, h + 1; f()) {} // expected-warning 2{{unused}} // condition declarations if (T(n){g}) {} @@ -32,10 +32,10 @@ //if (T(n)(g)) {} // expected-err-FIXME {{not a function}} // Likewise for 'switch' - switch (int n; n) {} // expected-error {{not yet supported}} - switch (g; int g = 5) {} // expected-error {{not yet supported}} + switch (int n; n) {} + switch (g; int g = 5) {} - if (int a, b; int c = a) { // expected-error {{not yet supported}} expected-note 6{{previous}} + if (int a, b; int c = a) { // expected-note 6{{previous}} int a; // expected-error {{redefinition}} int b; // expected-error {{redefinition}} int c; // expected-error {{redefinition}} @@ -44,4 +44,6 @@ int b; // expected-error {{redefinition}} int c; // expected-error {{redefinition}} } + + return 0; } Index: lib/Serialization/ASTWriterStmt.cpp === --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -129,6 +129,7 @@ void ASTStmtWriter::VisitIfStmt(IfStmt *S) { VisitStmt(S); Record.push_back(S->isConstexpr()); + Record.AddStmt(S->getInit()); Record.AddDeclRef(S->getConditionVariable()); Record.AddStmt(S->getCond()); Record.AddStmt(S->getThen()); @@ -140,6 +141,7 @@ void ASTStmtWriter::VisitSwitchStmt(SwitchStmt *S) { VisitStmt(S); + Record.AddStmt(S->getInit()); Record.AddDeclRef(S->getConditionVariable()); Record.AddStmt(S->getCond()); Record.AddStmt(S->getBody()); Index: lib/Serialization/ASTReaderStmt.cpp === --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -185,6 +185,7 @@ void ASTStmtReader::VisitIfStmt(IfStmt *S) { VisitStmt(S); S->setConstexpr(Record[Idx++]); + S->setInit(Reader.ReadSubStmt()); S->setConditionVariable(Reader.getContext(), ReadDeclAs(Record, Idx)); S->setCond(Reader.ReadSubExpr()); @@ -196,6 +197,7 @@ void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) { VisitStmt(S); + S->setInit(Reader.ReadSubStmt()); S->setConditionVariable(Reader.getContext(), ReadDeclAs(Record, Idx)); S->setCond(Reader.ReadSubExpr()); Index: lib/Sema/TreeTransform.h === --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -1174,9 +1174,9 @@ /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, - Sema::ConditionResult Cond, Stmt *Then, + Sema::ConditionResult Cond, Stmt *Init, Stmt *Then, SourceLocation ElseLoc, Stmt *Else) { -return getSema().ActOnIfStmt(IfLoc, IsConstexpr, nullptr, Cond, Then, +return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Init, Cond, Then, ElseLoc, Else); } @@ -1185,8 +1185,9 @@ /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different
Re: [PATCH] D21834: Implementing 'If statement with Initializer'
AntonBikineev updated this revision to Diff 62317. http://reviews.llvm.org/D21834 Files: include/clang/AST/Stmt.h include/clang/Sema/Sema.h lib/AST/ASTImporter.cpp lib/AST/Stmt.cpp lib/Analysis/BodyFarm.cpp lib/CodeGen/CGStmt.cpp lib/Sema/SemaStmt.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp Index: lib/Serialization/ASTWriterStmt.cpp === --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -129,6 +129,7 @@ void ASTStmtWriter::VisitIfStmt(IfStmt *S) { VisitStmt(S); Record.push_back(S->isConstexpr()); + Record.AddStmt(S->getInit()); Record.AddDeclRef(S->getConditionVariable()); Record.AddStmt(S->getCond()); Record.AddStmt(S->getThen()); @@ -140,6 +141,7 @@ void ASTStmtWriter::VisitSwitchStmt(SwitchStmt *S) { VisitStmt(S); + Record.AddStmt(S->getInit()); Record.AddDeclRef(S->getConditionVariable()); Record.AddStmt(S->getCond()); Record.AddStmt(S->getBody()); Index: lib/Serialization/ASTReaderStmt.cpp === --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -185,6 +185,7 @@ void ASTStmtReader::VisitIfStmt(IfStmt *S) { VisitStmt(S); S->setConstexpr(Record[Idx++]); + S->setInit(Reader.ReadSubStmt()); S->setConditionVariable(Reader.getContext(), ReadDeclAs(Record, Idx)); S->setCond(Reader.ReadSubExpr()); @@ -196,6 +197,7 @@ void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) { VisitStmt(S); + S->setInit(Reader.ReadSubStmt()); S->setConditionVariable(Reader.getContext(), ReadDeclAs(Record, Idx)); S->setCond(Reader.ReadSubExpr()); Index: lib/Sema/TreeTransform.h === --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -1174,9 +1174,9 @@ /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, - Sema::ConditionResult Cond, Stmt *Then, + Sema::ConditionResult Cond, Stmt *Init, Stmt *Then, SourceLocation ElseLoc, Stmt *Else) { -return getSema().ActOnIfStmt(IfLoc, IsConstexpr, nullptr, Cond, Then, +return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Init, Cond, Then, ElseLoc, Else); } @@ -1185,8 +1185,9 @@ /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc, +Stmt *Init, Sema::ConditionResult Cond) { -return getSema().ActOnStartOfSwitchStmt(SwitchLoc, nullptr, Cond); +return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Init, Cond); } /// \brief Attach the body to the switch statement. @@ -6236,6 +6237,11 @@ template StmtResult TreeTransform::TransformIfStmt(IfStmt *S) { + // Transform the initialization statement + StmtResult Init = getDerived().TransformStmt(S->getInit()); + if (Init.isInvalid()) +return StmtError(); + // Transform the condition Sema::ConditionResult Cond = getDerived().TransformCondition( S->getIfLoc(), S->getConditionVariable(), S->getCond(), @@ -6268,6 +6274,7 @@ } if (!getDerived().AlwaysRebuild() && + Init.get() == S->getInit() && Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) && Then.get() == S->getThen() && Else.get() == S->getElse()) @@ -6274,12 +6281,17 @@ return S; return getDerived().RebuildIfStmt(S->getIfLoc(), S->isConstexpr(), Cond, -Then.get(), S->getElseLoc(), Else.get()); +Init.get(), Then.get(), S->getElseLoc(), Else.get()); } template StmtResult TreeTransform::TransformSwitchStmt(SwitchStmt *S) { + // Transform the initialization statement + StmtResult Init = getDerived().TransformStmt(S->getInit()); + if (Init.isInvalid()) +return StmtError(); + // Transform the condition. Sema::ConditionResult Cond = getDerived().TransformCondition( S->getSwitchLoc(), S->getConditionVariable(), S->getCond(), @@ -6289,7 +6301,8 @@ // Rebuild the switch statement. StmtResult Switch -= getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), Cond); += getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), + S->getInit(), Cond); if (Switch.isInvalid()) return StmtError(); Index: lib/Sema/SemaStmt.cpp === ---
Re: [PATCH] D21834: Implementing 'If statement with Initializer'
AntonBikineev added a comment. @rsmith, > This is not correct; TryParseSimpleDeclaration usually stops long before it > reaches the end of the simple-declaration, so this will give false negatives > in lots of cases. Yes, I noticed that, that's why I changed use of TryParseSimpleDeclaration to something easier in last revision. Thanks for reply, Richard. The revision you sent looks great, I should have updated my working copy before :) Anyways, there are not too much of changes to Sema/AST stuff, I just applied them on top of yours, added the same for SwitchStmt. I'll update the test you put according to my changes tomorrow. http://reviews.llvm.org/D21834 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D21834: Implementing 'If statement with Initializer'
AntonBikineev added a subscriber: cfe-commits. AntonBikineev updated this revision to Diff 62254. http://reviews.llvm.org/D21834 Files: include/clang/AST/Stmt.h include/clang/Parse/Parser.h include/clang/Sema/Sema.h lib/AST/ASTImporter.cpp lib/AST/Stmt.cpp lib/Analysis/BodyFarm.cpp lib/CodeGen/CGStmt.cpp lib/Parse/ParseStmt.cpp lib/Parse/ParseTentative.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaStmt.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp Index: lib/Serialization/ASTWriterStmt.cpp === --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -129,6 +129,7 @@ void ASTStmtWriter::VisitIfStmt(IfStmt *S) { VisitStmt(S); Record.push_back(S->isConstexpr()); + Record.AddStmt(S->getInit()); Record.AddDeclRef(S->getConditionVariable()); Record.AddStmt(S->getCond()); Record.AddStmt(S->getThen()); Index: lib/Serialization/ASTReaderStmt.cpp === --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -185,6 +185,7 @@ void ASTStmtReader::VisitIfStmt(IfStmt *S) { VisitStmt(S); S->setConstexpr(Record[Idx++]); + S->setInit(Reader.ReadSubStmt()); S->setConditionVariable(Reader.getContext(), ReadDeclAs(Record, Idx)); S->setCond(Reader.ReadSubExpr()); Index: lib/Sema/TreeTransform.h === --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -1174,9 +1174,9 @@ /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, - Sema::ConditionResult Cond, Stmt *Then, + Sema::ConditionResult Cond, Stmt *Init, Stmt *Then, SourceLocation ElseLoc, Stmt *Else) { -return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Cond, Then, ElseLoc, Else); +return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Cond, Init, Then, ElseLoc, Else); } /// \brief Start building a new switch statement. @@ -6225,6 +6225,11 @@ template StmtResult TreeTransform::TransformIfStmt(IfStmt *S) { + // Transform the initialization statement + StmtResult Init = getDerived().TransformStmt(S->getInit()); + if (Init.isInvalid()) +return StmtError(); + // Transform the condition Sema::ConditionResult Cond = getDerived().TransformCondition( S->getIfLoc(), S->getConditionVariable(), S->getCond(), @@ -6257,6 +6262,7 @@ } if (!getDerived().AlwaysRebuild() && + Init.get() == S->getInit() && Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) && Then.get() == S->getThen() && Else.get() == S->getElse()) @@ -6263,7 +6269,7 @@ return S; return getDerived().RebuildIfStmt(S->getIfLoc(), S->isConstexpr(), Cond, -Then.get(), S->getElseLoc(), Else.get()); +Init.get(), Then.get(), S->getElseLoc(), Else.get()); } template Index: lib/Sema/SemaStmt.cpp === --- lib/Sema/SemaStmt.cpp +++ lib/Sema/SemaStmt.cpp @@ -505,7 +505,7 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, ConditionResult Cond, - Stmt *thenStmt, SourceLocation ElseLoc, + Stmt *initStmt, Stmt *thenStmt, SourceLocation ElseLoc, Stmt *elseStmt) { if (Cond.isInvalid()) Cond = ConditionResult( @@ -524,11 +524,11 @@ DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), thenStmt, diag::warn_empty_if_body); - return BuildIfStmt(IfLoc, IsConstexpr, Cond, thenStmt, ElseLoc, elseStmt); + return BuildIfStmt(IfLoc, IsConstexpr, Cond, initStmt, thenStmt, ElseLoc, elseStmt); } StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, - ConditionResult Cond, Stmt *thenStmt, + ConditionResult Cond, Stmt *initStmt, Stmt *thenStmt, SourceLocation ElseLoc, Stmt *elseStmt) { if (Cond.isInvalid()) return StmtError(); @@ -539,7 +539,7 @@ DiagnoseUnusedExprResult(thenStmt); DiagnoseUnusedExprResult(elseStmt); - return new (Context) IfStmt(Context, IfLoc, IsConstexpr, Cond.get().first, + return new (Context) IfStmt(Context, IfLoc, IsConstexpr, initStmt, Cond.get().first, Cond.get().second, thenStmt, ElseLoc, elseStmt); } Index: lib/Sema/SemaExprCXX.cpp === --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -3095,6 +3095,7 @@ switch
Re: [PATCH] D5744: Partial specialization after class template instantiation.
AntonBikineev added a comment. @rsmith, are there any plans/suggestions regarding this patch? http://reviews.llvm.org/D5744 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits