[PATCH] D133641: [Clang] [Sema] Ignore invalid multiversion function redeclarations

2022-09-10 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: tahonermann, erichkeane.
Herald added a project: All.
Izaron requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

If a redeclaration of a multiversion function is invalid,
it may be in a broken condition (for example, missing an important
attribute). We shouldn't analyze invalid redeclarations.

Fixes https://github.com/llvm/llvm-project/issues/57343


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D133641

Files:
  clang/lib/Sema/SemaDecl.cpp
  clang/test/Sema/attr-target-mv.c


Index: clang/test/Sema/attr-target-mv.c
===
--- clang/test/Sema/attr-target-mv.c
+++ clang/test/Sema/attr-target-mv.c
@@ -52,6 +52,15 @@
 // expected-note@-2 {{previous definition is here}}
 int __attribute__((target("default"))) redef2(void) { return 1;}
 
+int redef3(void) { return 1; }
+// expected-warning@+4 {{attribute declaration must precede definition}}
+// expected-note@-2 {{previous definition is here}}
+// expected-error@+2 {{redefinition of 'redef3'}}
+// expected-note@-4 {{previous definition is here}}
+int __attribute__((target("default"))) redef3(void) { return 1; }
+// allow this, since we don't complain about more than one redefinition
+int __attribute__((target("sse4.2"))) redef3(void) { return 1; }
+
 int __attribute__((target("sse4.2"))) mv_after_use(void) { return 1; }
 int use3(void) {
   return mv_after_use();
Index: clang/lib/Sema/SemaDecl.cpp
===
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -11081,11 +11081,11 @@
   bool MayNeedOverloadableChecks =
   AllowOverloadingOfFunction(Previous, S.Context, NewFD);
 
-  // Next, check ALL non-overloads to see if this is a redeclaration of a
-  // previous member of the MultiVersion set.
+  // Next, check ALL non-invalid non-overloads to see if this is a 
redeclaration
+  // of a previous member of the MultiVersion set.
   for (NamedDecl *ND : Previous) {
 FunctionDecl *CurFD = ND->getAsFunction();
-if (!CurFD)
+if (!CurFD || CurFD->isInvalidDecl())
   continue;
 if (MayNeedOverloadableChecks &&
 S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules))


Index: clang/test/Sema/attr-target-mv.c
===
--- clang/test/Sema/attr-target-mv.c
+++ clang/test/Sema/attr-target-mv.c
@@ -52,6 +52,15 @@
 // expected-note@-2 {{previous definition is here}}
 int __attribute__((target("default"))) redef2(void) { return 1;}
 
+int redef3(void) { return 1; }
+// expected-warning@+4 {{attribute declaration must precede definition}}
+// expected-note@-2 {{previous definition is here}}
+// expected-error@+2 {{redefinition of 'redef3'}}
+// expected-note@-4 {{previous definition is here}}
+int __attribute__((target("default"))) redef3(void) { return 1; }
+// allow this, since we don't complain about more than one redefinition
+int __attribute__((target("sse4.2"))) redef3(void) { return 1; }
+
 int __attribute__((target("sse4.2"))) mv_after_use(void) { return 1; }
 int use3(void) {
   return mv_after_use();
Index: clang/lib/Sema/SemaDecl.cpp
===
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -11081,11 +11081,11 @@
   bool MayNeedOverloadableChecks =
   AllowOverloadingOfFunction(Previous, S.Context, NewFD);
 
-  // Next, check ALL non-overloads to see if this is a redeclaration of a
-  // previous member of the MultiVersion set.
+  // Next, check ALL non-invalid non-overloads to see if this is a redeclaration
+  // of a previous member of the MultiVersion set.
   for (NamedDecl *ND : Previous) {
 FunctionDecl *CurFD = ND->getAsFunction();
-if (!CurFD)
+if (!CurFD || CurFD->isInvalidDecl())
   continue;
 if (MayNeedOverloadableChecks &&
 S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133641: [Clang] [Sema] Ignore invalid multiversion function redeclarations

2022-09-10 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

How the bug was working on this example:

  void foo() {}
  [[gnu::target("default")]] void foo() {}
  [[gnu::target("avx2")]] void foo() {}



1. Clang parses the definition of the `foo` function (line 1)
2. When parsing the second definition (line 2), Clang will delete `TargetAttr` 
in this function 

3. Eventually Clang will mark both `foo`s as invalid.
4. When parsing the third definition (line 3), in the 
`CheckMultiVersionAdditionalDecl` method Clang is trying to compare 
`TargetAttr` of the 2nd and the 3rd `foo`: link 
.
5. The `CurTA` variable is equal to `nullptr` (because we deleted the attribute 
in the second step), so there is undefined behaviour.

I suggest to stop looking to invalid declarations.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133641/new/

https://reviews.llvm.org/D133641

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133641: [Clang] [Sema] Ignore invalid multiversion function redeclarations

2022-09-13 Thread Evgeny Shulgin via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG67f08bf1bfa8: [Clang] [Sema] Ignore invalid multiversion 
function redeclarations (authored by Izaron).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133641/new/

https://reviews.llvm.org/D133641

Files:
  clang/lib/Sema/SemaDecl.cpp
  clang/test/Sema/attr-target-mv.c


Index: clang/test/Sema/attr-target-mv.c
===
--- clang/test/Sema/attr-target-mv.c
+++ clang/test/Sema/attr-target-mv.c
@@ -52,6 +52,15 @@
 // expected-note@-2 {{previous definition is here}}
 int __attribute__((target("default"))) redef2(void) { return 1;}
 
+int redef3(void) { return 1; }
+// expected-warning@+4 {{attribute declaration must precede definition}}
+// expected-note@-2 {{previous definition is here}}
+// expected-error@+2 {{redefinition of 'redef3'}}
+// expected-note@-4 {{previous definition is here}}
+int __attribute__((target("default"))) redef3(void) { return 1; }
+// allow this, since we don't complain about more than one redefinition
+int __attribute__((target("sse4.2"))) redef3(void) { return 1; }
+
 int __attribute__((target("sse4.2"))) mv_after_use(void) { return 1; }
 int use3(void) {
   return mv_after_use();
Index: clang/lib/Sema/SemaDecl.cpp
===
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -11082,11 +11082,11 @@
   bool MayNeedOverloadableChecks =
   AllowOverloadingOfFunction(Previous, S.Context, NewFD);
 
-  // Next, check ALL non-overloads to see if this is a redeclaration of a
-  // previous member of the MultiVersion set.
+  // Next, check ALL non-invalid non-overloads to see if this is a 
redeclaration
+  // of a previous member of the MultiVersion set.
   for (NamedDecl *ND : Previous) {
 FunctionDecl *CurFD = ND->getAsFunction();
-if (!CurFD)
+if (!CurFD || CurFD->isInvalidDecl())
   continue;
 if (MayNeedOverloadableChecks &&
 S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules))


Index: clang/test/Sema/attr-target-mv.c
===
--- clang/test/Sema/attr-target-mv.c
+++ clang/test/Sema/attr-target-mv.c
@@ -52,6 +52,15 @@
 // expected-note@-2 {{previous definition is here}}
 int __attribute__((target("default"))) redef2(void) { return 1;}
 
+int redef3(void) { return 1; }
+// expected-warning@+4 {{attribute declaration must precede definition}}
+// expected-note@-2 {{previous definition is here}}
+// expected-error@+2 {{redefinition of 'redef3'}}
+// expected-note@-4 {{previous definition is here}}
+int __attribute__((target("default"))) redef3(void) { return 1; }
+// allow this, since we don't complain about more than one redefinition
+int __attribute__((target("sse4.2"))) redef3(void) { return 1; }
+
 int __attribute__((target("sse4.2"))) mv_after_use(void) { return 1; }
 int use3(void) {
   return mv_after_use();
Index: clang/lib/Sema/SemaDecl.cpp
===
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -11082,11 +11082,11 @@
   bool MayNeedOverloadableChecks =
   AllowOverloadingOfFunction(Previous, S.Context, NewFD);
 
-  // Next, check ALL non-overloads to see if this is a redeclaration of a
-  // previous member of the MultiVersion set.
+  // Next, check ALL non-invalid non-overloads to see if this is a redeclaration
+  // of a previous member of the MultiVersion set.
   for (NamedDecl *ND : Previous) {
 FunctionDecl *CurFD = ND->getAsFunction();
-if (!CurFD)
+if (!CurFD || CurFD->isInvalidDecl())
   continue;
 if (MayNeedOverloadableChecks &&
 S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133887: [Clang] Support label at end of compound statement

2022-09-14 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: clang-language-wg, aaron.ballman.
Herald added a project: All.
Izaron requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Implements paper P2324R2
https://wg21.link/p2324r2
https://github.com/cplusplus/papers/issues/1006


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D133887

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/lib/Parse/ParseStmt.cpp
  clang/test/Parser/cxx2b-label.cpp
  clang/test/Parser/switch-recovery.cpp
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1456,7 +1456,7 @@
 
   Labels at the end of compound statements
   https://wg21.link/P2324R2";>P2324R2
-  No
+  Clang 16
 
 
   Delimited escape sequences
Index: clang/test/Parser/switch-recovery.cpp
===
--- clang/test/Parser/switch-recovery.cpp
+++ clang/test/Parser/switch-recovery.cpp
@@ -160,14 +160,14 @@
 void missing_statement_case(int x) {
   switch (x) {
 case 1:
-case 0: // expected-error {{label at end of compound statement: expected statement}}
+case 0: // expected-error {{label at end of switch compound statement: expected statement}}
   }
 }
 
 void missing_statement_default(int x) {
   switch (x) {
 case 0:
-default: // expected-error {{label at end of compound statement: expected statement}}
+default: // expected-error {{label at end of switch compound statement: expected statement}}
   }
 }
 
@@ -179,7 +179,7 @@
 void pr19022_1a(int x) {
   switch(x) {
   case 1  // expected-error{{expected ':' after 'case'}} \
-  // expected-error{{label at end of compound statement: expected statement}}
+  // expected-error{{label at end of switch compound statement: expected statement}}
   }
 }
 
Index: clang/test/Parser/cxx2b-label.cpp
===
--- /dev/null
+++ clang/test/Parser/cxx2b-label.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx2b -std=c++2b -Wpre-c++2b-compat %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx20 -std=c++20 %s
+
+void foo() {
+label1:
+int x;
+label2:
+x = 1;
+label3: label4: label5:
+} // cxx20-warning {{label at end of compound statement is a C++2b extension}} \
+ cxx2b-warning {{label at end of compound statement is incompatible with C++ standards before C++2b}}
Index: clang/lib/Parse/ParseStmt.cpp
===
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -679,9 +679,12 @@
 
 /// ParseLabeledStatement - We have an identifier and a ':' after it.
 ///
+///   label:
+/// identifier ':'
+/// [GNU]   identifier ':' attributes[opt]
+///
 ///   labeled-statement:
-/// identifier ':' statement
-/// [GNU]   identifier ':' attributes[opt] statement
+/// label statement
 ///
 StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
  ParsedStmtContext StmtCtx) {
@@ -725,6 +728,14 @@
 }
   }
 
+  // The label may have no statement following it
+  if (SubStmt.isUnset() && Tok.is(tok::r_brace)) {
+Diag(Tok, getLangOpts().CPlusPlus2b
+  ? diag::warn_cxx20_compat_label_end_of_compound_statement
+  : diag::ext_label_end_of_compound_statement);
+SubStmt = Actions.ActOnNullStmt(ColonLoc);
+  }
+
   // If we've not parsed a statement yet, parse one now.
   if (!SubStmt.isInvalid() && !SubStmt.isUsable())
 SubStmt = ParseStatement(nullptr, StmtCtx);
@@ -873,8 +884,8 @@
 // another parsing error, so avoid producing extra diagnostics.
 if (ColonLoc.isValid()) {
   SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
-  Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
-<< FixItHint::CreateInsertion(AfterColonLoc, " ;");
+  Diag(AfterColonLoc, diag::err_switch_label_end_of_compound_statement)
+  << FixItHint::CreateInsertion(AfterColonLoc, " ;");
 }
 SubStmt = StmtError();
   }
@@ -928,8 +939,8 @@
 // Diagnose the common error "switch (X) {... default: }", which is
 // not valid.
 SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
-Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
-  << FixItHint::CreateInsertion(AfterColonLoc, " ;");
+Diag(AfterColonLoc, diag::err_switch_label_end_of_compound_statement)
+<< FixItHint::CreateInsertion(AfterColonLoc, " ;");
 SubStmt = true;
   }
 
@@ -1096,10 +1107,10 @@
   return Actions.ActOnExprStmt(E, /*DiscardedValue=*/!IsStmtExprResult);
 }
 
-/// ParseCompoundStatementBody - Parse a sequence of statements a

[PATCH] D133887: [Clang] Support label at end of compound statement

2022-09-14 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

I thought it was a good idea to slightly rename 
`err_label_end_of_compound_statement` to 
`err_SWITCH_label_end_of_compound_statement` because we aren't going to support 
empty labels in switch statements. (GCC also doesn't compile it - 
https://godbolt.org/z/xabKaon8v)

So now we need to clarify that we don't support empty labels in SWITCH compound 
statements (just there).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133887/new/

https://reviews.llvm.org/D133887

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119651: [clang] Fix evaluation context type for consteval function calls in instantiations

2022-09-14 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

@usaxena95, thanks! It was a really tough issue =)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119651/new/

https://reviews.llvm.org/D119651

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D122078: [clang-tidy] Ignore concepts in `misc-redundant-expression`

2022-09-14 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 460209.
Izaron added a comment.

Add release note


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122078/new/

https://reviews.llvm.org/D122078

Files:
  clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s misc-redundant-expression %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy %s misc-redundant-expression -std=c++20 %t -- -- -fno-delayed-template-parsing
 
 typedef __INT64_TYPE__ I64;
 
@@ -843,3 +843,13 @@
 
   return 2;
 }
+
+namespace concepts {
+// redundant expressions inside concepts make sense, ignore them
+template 
+concept TestConcept = requires(I i) {
+  {i - i};
+  {i && i};
+  {i ? i : i};
+};
+} // namespace concepts
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -149,6 +149,12 @@
   copy assignment operators with nonstandard return types. The check is restricted to
   c++11-or-later.
 
+- Improved :doc:`misc-redundant-expression `
+  check.
+
+  The check now skips concept definitions since redundant expressions still make sense
+  inside them.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -10,6 +10,7 @@
 #include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
@@ -440,6 +441,8 @@
   return Node.isIntegerConstantExpr(Finder->getASTContext());
 }
 
+AST_MATCHER(Expr, isRequiresExpr) { return isa(Node); }
+
 AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
   return areEquivalentExpr(Node.getLHS(), Node.getRHS());
 }
@@ -858,6 +861,7 @@
 
   const auto BannedIntegerLiteral =
   integerLiteral(expandedByMacro(KnownBannedMacroNames));
+  const auto BannedAncestor = expr(isRequiresExpr());
 
   // Binary with equivalent operands, like (X != 2 && X != 2).
   Finder->addMatcher(
@@ -873,7 +877,8 @@
unless(hasType(realFloatingPointType())),
unless(hasEitherOperand(hasType(realFloatingPointType(,
unless(hasLHS(AnyLiteralExpr)),
-   unless(hasDescendant(BannedIntegerLiteral)))
+   unless(hasDescendant(BannedIntegerLiteral)),
+   unless(hasAncestor(BannedAncestor)))
.bind("binary")),
   this);
 
@@ -886,7 +891,8 @@
  unless(isInTemplateInstantiation()),
  unless(binaryOperatorIsInMacro()),
  // TODO: if the banned macros are themselves duplicated
- unless(hasDescendant(BannedIntegerLiteral)))
+ unless(hasDescendant(BannedIntegerLiteral)),
+ unless(hasAncestor(BannedAncestor)))
   .bind("nested-duplicates"),
   this);
 
@@ -896,7 +902,8 @@
conditionalOperator(expressionsAreEquivalent(),
// Filter noisy false positives.
unless(conditionalOperatorIsInMacro()),
-   unless(isInTemplateInstantiation()))
+   unless(isInTemplateInstantiation()),
+   unless(hasAncestor(BannedAncestor)))
.bind("cond")),
   this);
 
@@ -909,7 +916,8 @@
 ">=", "&&", "||", "="),
parametersAreEquivalent(),
// Filter noisy false positives.
-   unless(isMacro()), unless(isInTemplateInstantiation()))
+   unless(isMacro()), unless(isInTemplateInstantiation()),
+   unless(hasAncestor(BannedAncestor)))
.bind("call")),
   this);
 
@@ -919,7 +927,8 @@
   hasAnyOverloadedOperatorName("|", "&", "||", "&&", "^"),
   nestedParametersAreEquivalent(), argumentCountIs(2),
   // Filter noisy false positives.
-  unless(isMacro()), unless(isInTemplateInstantiation()))
+  unless(isMacro()), unless(

[PATCH] D122425: Pass -disable-llvm-passes to avoid running llvm passes

2022-03-26 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron accepted this revision.
Izaron added a comment.
This revision is now accepted and ready to land.

Hi! I don't actually know much about llvm passes, but I see that the LLVM IR 
output is much more understandable now, thanks! It will look nicer when I 
rebase my patch D119792  on top of this.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122425/new/

https://reviews.llvm.org/D122425

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119927: [Clang] [P2025] More exhaustive tests for NRVO

2022-03-16 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 415904.
Izaron added a comment.
Herald added a project: All.

Add the reverse_iterator-like pattern to tests


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119927/new/

https://reviews.llvm.org/D119927

Files:
  clang/test/CodeGenCXX/nrvo.cpp

Index: clang/test/CodeGenCXX/nrvo.cpp
===
--- clang/test/CodeGenCXX/nrvo.cpp
+++ clang/test/CodeGenCXX/nrvo.cpp
@@ -1,13 +1,14 @@
 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
 // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -o - %s | FileCheck %s
 // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++03 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-03 %s
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++11 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-11 %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++11 -DCXX11 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-11 %s
 
 // Test code generation for the named return value optimization.
 class X {
 public:
   X();
   X(const X&);
+  X(const volatile X &);
   ~X();
 };
 
@@ -19,6 +20,9 @@
   }
 };
 
+void ConsumeX(X x);
+extern X OuterX;
+
 // CHECK-LABEL: @_Z5test0v(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5:[0-9]+]]
@@ -29,10 +33,9 @@
 // CHECK-EH-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]])
 // CHECK-EH-NEXT:ret void
 //
-X test0() {
+X test0() { // http://wg21.link/p2025r2#ex-2
   X x;
-
-  return x;
+  return x; // NRVO happens
 }
 
 // CHECK-LABEL: @_Z5test1b(
@@ -48,8 +51,8 @@
 X test1(bool B) {
   X x;
   if (B)
-return (x);
-  return x;
+return (x); // NRVO happens
+  return x; // NRVO happens
 }
 
 // CHECK-LABEL: @_Z5test2b(
@@ -155,13 +158,11 @@
 // CHECK-EH-11-NEXT:resume { i8*, i32 } [[DOTPN]]
 //
 X test2(bool B) {
-  // No NRVO.
-
   X x;
   X y;
   if (B)
-return y;
-  return x;
+return y; // NRVO is impossible
+  return x;   // NRVO is impossible
 }
 
 // CHECK-LABEL: @_Z5test3b(
@@ -242,14 +243,13 @@
 // CHECK-EH-11:   return:
 // CHECK-EH-11-NEXT:ret void
 //
-X test3(bool B) {
+X test3(bool B) { // http://wg21.link/p2025r2#ex-4
   if (B) {
 X y;
-return y;
+return y; // NRVO happens
   }
-  // FIXME: we should NRVO this variable too.
   X x;
-  return x;
+  return x; // FIXME: NRVO could happen, but doesn't
 }
 
 extern "C" void exit(int) throw();
@@ -291,7 +291,7 @@
   {
 X x;
 if (B)
-  return x;
+  return x; // NRVO happens
   }
   exit(1);
 }
@@ -407,11 +407,11 @@
 // CHECK-EH-11-NEXT:call void @__clang_call_terminate(i8* [[TMP10]]) #[[ATTR8:[0-9]+]]
 // CHECK-EH-11-NEXT:unreachable
 //
-X test5() {
+X test5() { // http://wg21.link/p2025r2#ex-14
   try {
 may_throw();
   } catch (X x) {
-return x;
+return x; // FIXME: NRVO could happen, but doesn't
   }
 }
 #endif
@@ -476,7 +476,7 @@
 //
 X test6() {
   X a __attribute__((aligned(8)));
-  return a;
+  return a; // NRVO is impossible
 }
 
 // CHECK-LABEL: @_Z5test7b(
@@ -492,7 +492,7 @@
 X test7(bool b) {
   if (b) {
 X x;
-return x;
+return x; // NRVO happens
   }
   return X();
 }
@@ -510,10 +510,10 @@
 X test8(bool b) {
   if (b) {
 X x;
-return x;
+return x; // NRVO happens
   } else {
 X y;
-return y;
+return y; // NRVO happens
   }
 }
 
@@ -536,3 +536,1289 @@
 Y test9() {
   Y::f();
 }
+
+// CHECK-LABEL: @_Z6test10b(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
+// CHECK-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
+// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
+// CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
+// CHECK-NEXT:br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+// CHECK:   if.then:
+// CHECK-NEXT:call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
+// CHECK-NEXT:br label [[CLEANUP:%.*]]
+// CHECK:   if.else:
+// CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]]
+// CHECK-NEXT:br label [[CLEANUP]]
+// CHECK:   cleanup:
+// CHECK-NEXT:call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
+// CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
+// CHECK-NEXT:ret void
+//
+// CHECK-EH-03-LABEL:

[PATCH] D119927: [Clang] [P2025] More exhaustive tests for NRVO

2022-03-16 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

@Quuxplusone, thank you for the test idea! I added `test25` that resembles the 
pattern.

Could you please look if we're okay with `test25`?

If everything is OK, I could merge the patch myself: I've got repository merge 
access =)

P. S. Sorry for the long delay, I was really busy lately.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119927/new/

https://reviews.llvm.org/D119927

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119470: [clang-tidy] Don't check decltype return types in `readability-const-return-type`

2022-03-16 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 416035.
Izaron added a comment.
Herald added a project: All.

Don't warn on non-toplevel-const TypeOfType


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119470/new/

https://reviews.llvm.org/D119470

Files:
  clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s readability-const-return-type %t
+// RUN: %check_clang_tidy -std=c++14 %s readability-const-return-type %t
 
 //  p# = positive test
 //  n# = negative test
@@ -285,3 +285,40 @@
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const int' is 
'const'-qualified at the top level, which may reduce code readability without 
improving const correctness
   // CHECK-NOT-FIXES: int getC() { return 1; }
 };
+
+// Don't warn about const auto types, because it may be impossible to make 
them non-const
+// without a significant semantics change. Since `auto` drops cv-qualifiers,
+// tests check `decltype(auto)`.
+decltype(auto) n16() {
+  static const int i = 42;
+  return i;
+}
+
+// Don't warn about `decltype()` types
+const int n17i = 1;
+decltype(n17i) n17() {
+  return 17;
+}
+
+// Do warn when on decltype types with the local const qualifier
+// `const decltype(auto)` won't compile, so check only `const decltype()`
+const decltype(n17i) n18() {
+  // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const decltype(n17i)
+  // CHECK-FIXES: decltype(n17i) n18() {
+  return 18;
+}
+
+// `volatile` modifier doesn't affect the checker
+volatile decltype(n17i) n19() {
+  return 19;
+}
+
+// Don't warn about `__typeof__()` types
+__typeof__(n17i) n20() {
+  return 20;
+}
+
+// Don't warn about `__typeof__(type)` types
+__typeof__(const int) n21() {
+  return 21;
+}
Index: clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
@@ -53,6 +53,18 @@
 
 namespace {
 
+AST_MATCHER(QualType, isLocalConstQualified) {
+  return Node.isLocalConstQualified();
+}
+
+AST_MATCHER(QualType, isTypeOfType) {
+  return isa(Node.getTypePtr());
+}
+
+AST_MATCHER(QualType, isTypeOfExprType) {
+  return isa(Node.getTypePtr());
+}
+
 struct CheckResult {
   // Source range of the relevant `const` token in the definition being 
checked.
   CharSourceRange ConstRange;
@@ -95,10 +107,14 @@
 
 void ConstReturnTypeCheck::registerMatchers(MatchFinder *Finder) {
   // Find all function definitions for which the return types are `const`
-  // qualified.
+  // qualified, ignoring decltype types.
+  auto NonLocalConstType = qualType(
+  unless(isLocalConstQualified()),
+  anyOf(decltypeType(), autoType(), isTypeOfType(), isTypeOfExprType()));
   Finder->addMatcher(
-  functionDecl(returns(isConstQualified()),
-   anyOf(isDefinition(), cxxMethodDecl(isPure(
+  functionDecl(
+  returns(allOf(isConstQualified(), unless(NonLocalConstType))),
+  anyOf(isDefinition(), cxxMethodDecl(isPure(
   .bind("func"),
   this);
 }


Index: clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s readability-const-return-type %t
+// RUN: %check_clang_tidy -std=c++14 %s readability-const-return-type %t
 
 //  p# = positive test
 //  n# = negative test
@@ -285,3 +285,40 @@
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const int' is 'const'-qualified at the top level, which may reduce code readability without improving const correctness
   // CHECK-NOT-FIXES: int getC() { return 1; }
 };
+
+// Don't warn about const auto types, because it may be impossible to make them non-const
+// without a significant semantics change. Since `auto` drops cv-qualifiers,
+// tests check `decltype(auto)`.
+decltype(auto) n16() {
+  static const int i = 42;
+  return i;
+}
+
+// Don't warn about `decltype()` types
+const int n17i = 1;
+decltype(n17i) n17() {
+  return 17;
+}
+
+// Do warn when on decltype types with the local const qualifier
+// `const decltype(auto)` won't compile, so check only `const decltype()`
+const decltype(n17i) n18() {
+  // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const

[PATCH] D119470: [clang-tidy] Don't check decltype return types in `readability-const-return-type`

2022-03-16 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron marked 3 inline comments as done.
Izaron added a comment.

> You've submitted some quality patches already, would you be interested in 
> obtaining commit privileges 
> (https://llvm.org/docs/DeveloperPolicy.html#obtaining-commit-access)?

Thanks! I obtained the commit access =) Now I don't have to ask other peoples 
commit on my behalf.




Comment at: 
clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp:56-58
+AST_MATCHER(QualType, isLocalConstQualified) {
+  return Node.isLocalConstQualified();
+}

aaron.ballman wrote:
> I think we might as well hit all the local qualifiers instead of just 
> `const`, WDYT? e.g., `volatile` et al via `hasLocalQualifiers()`
In this case the checker will complain on this code:
```
const int i = 1;
volatile decltype(i) n() {
  return 12345;
}
```
```
warning: return type 'volatile decltype(i)' (aka 'const volatile int') is 
'const'-qualified at the top level, which may reduce code readability without 
improving const correctness [readability-const-return-type]
```
That wouldn't be the correct outcome.

I added the test for the snippet above.



Comment at: 
clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp:104
+  const auto NonLocalConstDecltypeType = qualType(
+  unless(isLocalConstQualified()), anyOf(decltypeType(), autoType()));
   Finder->addMatcher(

aaron.ballman wrote:
> How about a `TypeOfType`? (The GCC `typeof(foo)` extension)
Thanks! Didn't know about this extension. Now the checker filters this out.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119470/new/

https://reviews.llvm.org/D119470

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119927: [Clang] [P2025] More exhaustive tests for NRVO

2022-03-16 Thread Evgeny Shulgin via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG3587b15abe68: [Clang] [P2025] More exhaustive tests for NRVO 
(authored by Izaron).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119927/new/

https://reviews.llvm.org/D119927

Files:
  clang/test/CodeGenCXX/nrvo.cpp

Index: clang/test/CodeGenCXX/nrvo.cpp
===
--- clang/test/CodeGenCXX/nrvo.cpp
+++ clang/test/CodeGenCXX/nrvo.cpp
@@ -1,13 +1,14 @@
 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
 // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -o - %s | FileCheck %s
 // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++03 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-03 %s
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++11 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-11 %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++11 -DCXX11 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-11 %s
 
 // Test code generation for the named return value optimization.
 class X {
 public:
   X();
   X(const X&);
+  X(const volatile X &);
   ~X();
 };
 
@@ -19,6 +20,9 @@
   }
 };
 
+void ConsumeX(X x);
+extern X OuterX;
+
 // CHECK-LABEL: @_Z5test0v(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5:[0-9]+]]
@@ -29,10 +33,9 @@
 // CHECK-EH-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]])
 // CHECK-EH-NEXT:ret void
 //
-X test0() {
+X test0() { // http://wg21.link/p2025r2#ex-2
   X x;
-
-  return x;
+  return x; // NRVO happens
 }
 
 // CHECK-LABEL: @_Z5test1b(
@@ -48,8 +51,8 @@
 X test1(bool B) {
   X x;
   if (B)
-return (x);
-  return x;
+return (x); // NRVO happens
+  return x; // NRVO happens
 }
 
 // CHECK-LABEL: @_Z5test2b(
@@ -155,13 +158,11 @@
 // CHECK-EH-11-NEXT:resume { i8*, i32 } [[DOTPN]]
 //
 X test2(bool B) {
-  // No NRVO.
-
   X x;
   X y;
   if (B)
-return y;
-  return x;
+return y; // NRVO is impossible
+  return x;   // NRVO is impossible
 }
 
 // CHECK-LABEL: @_Z5test3b(
@@ -242,14 +243,13 @@
 // CHECK-EH-11:   return:
 // CHECK-EH-11-NEXT:ret void
 //
-X test3(bool B) {
+X test3(bool B) { // http://wg21.link/p2025r2#ex-4
   if (B) {
 X y;
-return y;
+return y; // NRVO happens
   }
-  // FIXME: we should NRVO this variable too.
   X x;
-  return x;
+  return x; // FIXME: NRVO could happen, but doesn't
 }
 
 extern "C" void exit(int) throw();
@@ -291,7 +291,7 @@
   {
 X x;
 if (B)
-  return x;
+  return x; // NRVO happens
   }
   exit(1);
 }
@@ -407,11 +407,11 @@
 // CHECK-EH-11-NEXT:call void @__clang_call_terminate(i8* [[TMP10]]) #[[ATTR8:[0-9]+]]
 // CHECK-EH-11-NEXT:unreachable
 //
-X test5() {
+X test5() { // http://wg21.link/p2025r2#ex-14
   try {
 may_throw();
   } catch (X x) {
-return x;
+return x; // FIXME: NRVO could happen, but doesn't
   }
 }
 #endif
@@ -476,7 +476,7 @@
 //
 X test6() {
   X a __attribute__((aligned(8)));
-  return a;
+  return a; // NRVO is impossible
 }
 
 // CHECK-LABEL: @_Z5test7b(
@@ -492,7 +492,7 @@
 X test7(bool b) {
   if (b) {
 X x;
-return x;
+return x; // NRVO happens
   }
   return X();
 }
@@ -510,10 +510,10 @@
 X test8(bool b) {
   if (b) {
 X x;
-return x;
+return x; // NRVO happens
   } else {
 X y;
-return y;
+return y; // NRVO happens
   }
 }
 
@@ -536,3 +536,1289 @@
 Y test9() {
   Y::f();
 }
+
+// CHECK-LABEL: @_Z6test10b(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
+// CHECK-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
+// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
+// CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
+// CHECK-NEXT:br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+// CHECK:   if.then:
+// CHECK-NEXT:call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
+// CHECK-NEXT:br label [[CLEANUP:%.*]]
+// CHECK:   if.else:
+// CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]]
+// CHECK-NEXT:br label [[CLEANUP]]
+// CHECK:   cleanup:
+// CHECK-NEXT:call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
+// CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
+// CHECK-NEXT:ret v

[PATCH] D119792: [Clang] [P2025] Analyze only potential scopes for NRVO

2022-03-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 416116.
Izaron added a comment.
Herald added a project: All.

Rebased the patch on top of D119927 


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119792/new/

https://reviews.llvm.org/D119792

Files:
  clang/include/clang/Sema/Scope.h
  clang/lib/Sema/Scope.cpp
  clang/test/CodeGenCXX/nrvo.cpp

Index: clang/test/CodeGenCXX/nrvo.cpp
===
--- clang/test/CodeGenCXX/nrvo.cpp
+++ clang/test/CodeGenCXX/nrvo.cpp
@@ -167,81 +167,13 @@
 
 // CHECK-LABEL: @_Z5test3b(
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
-// CHECK-NEXT:br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-// CHECK:   if.then:
 // CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]]
-// CHECK-NEXT:br label [[RETURN:%.*]]
-// CHECK:   if.end:
-// CHECK-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
-// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
-// CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
-// CHECK-NEXT:call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
-// CHECK-NEXT:call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
-// CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
-// CHECK-NEXT:br label [[RETURN]]
-// CHECK:   return:
 // CHECK-NEXT:ret void
 //
-// CHECK-EH-03-LABEL: @_Z5test3b(
-// CHECK-EH-03-NEXT:  entry:
-// CHECK-EH-03-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
-// CHECK-EH-03-NEXT:br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-// CHECK-EH-03:   if.then:
-// CHECK-EH-03-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]])
-// CHECK-EH-03-NEXT:br label [[RETURN:%.*]]
-// CHECK-EH-03:   if.end:
-// CHECK-EH-03-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
-// CHECK-EH-03-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]]
-// CHECK-EH-03-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-// CHECK-EH-03-NEXT:invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-// CHECK-EH-03-NEXT:to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
-// CHECK-EH-03:   invoke.cont:
-// CHECK-EH-03-NEXT:call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-// CHECK-EH-03-NEXT:call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]]
-// CHECK-EH-03-NEXT:br label [[RETURN]]
-// CHECK-EH-03:   lpad:
-// CHECK-EH-03-NEXT:[[TMP1:%.*]] = landingpad { i8*, i32 }
-// CHECK-EH-03-NEXT:cleanup
-// CHECK-EH-03-NEXT:invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-// CHECK-EH-03-NEXT:to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
-// CHECK-EH-03:   invoke.cont1:
-// CHECK-EH-03-NEXT:call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]]
-// CHECK-EH-03-NEXT:resume { i8*, i32 } [[TMP1]]
-// CHECK-EH-03:   return:
-// CHECK-EH-03-NEXT:ret void
-// CHECK-EH-03:   terminate.lpad:
-// CHECK-EH-03-NEXT:[[TMP2:%.*]] = landingpad { i8*, i32 }
-// CHECK-EH-03-NEXT:catch i8* null
-// CHECK-EH-03-NEXT:[[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0
-// CHECK-EH-03-NEXT:call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]]
-// CHECK-EH-03-NEXT:unreachable
-//
-// CHECK-EH-11-LABEL: @_Z5test3b(
-// CHECK-EH-11-NEXT:  entry:
-// CHECK-EH-11-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
-// CHECK-EH-11-NEXT:br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-// CHECK-EH-11:   if.then:
-// CHECK-EH-11-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]])
-// CHECK-EH-11-NEXT:br label [[RETURN:%.*]]
-// CHECK-EH-11:   if.end:
-// CHECK-EH-11-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
-// CHECK-EH-11-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]]
-// CHECK-EH-11-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-// CHECK-EH-11-NEXT:invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-

[PATCH] D119470: [clang-tidy] Don't check decltype return types in `readability-const-return-type`

2022-03-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG6043520c2072: [clang-tidy] Don't check decltype return 
types in `readability-const-return… (authored by Izaron).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119470/new/

https://reviews.llvm.org/D119470

Files:
  clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s readability-const-return-type %t
+// RUN: %check_clang_tidy -std=c++14 %s readability-const-return-type %t
 
 //  p# = positive test
 //  n# = negative test
@@ -285,3 +285,40 @@
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const int' is 
'const'-qualified at the top level, which may reduce code readability without 
improving const correctness
   // CHECK-NOT-FIXES: int getC() { return 1; }
 };
+
+// Don't warn about const auto types, because it may be impossible to make 
them non-const
+// without a significant semantics change. Since `auto` drops cv-qualifiers,
+// tests check `decltype(auto)`.
+decltype(auto) n16() {
+  static const int i = 42;
+  return i;
+}
+
+// Don't warn about `decltype()` types
+const int n17i = 1;
+decltype(n17i) n17() {
+  return 17;
+}
+
+// Do warn when on decltype types with the local const qualifier
+// `const decltype(auto)` won't compile, so check only `const decltype()`
+const decltype(n17i) n18() {
+  // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const decltype(n17i)
+  // CHECK-FIXES: decltype(n17i) n18() {
+  return 18;
+}
+
+// `volatile` modifier doesn't affect the checker
+volatile decltype(n17i) n19() {
+  return 19;
+}
+
+// Don't warn about `__typeof__()` types
+__typeof__(n17i) n20() {
+  return 20;
+}
+
+// Don't warn about `__typeof__(type)` types
+__typeof__(const int) n21() {
+  return 21;
+}
Index: clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
@@ -53,6 +53,18 @@
 
 namespace {
 
+AST_MATCHER(QualType, isLocalConstQualified) {
+  return Node.isLocalConstQualified();
+}
+
+AST_MATCHER(QualType, isTypeOfType) {
+  return isa(Node.getTypePtr());
+}
+
+AST_MATCHER(QualType, isTypeOfExprType) {
+  return isa(Node.getTypePtr());
+}
+
 struct CheckResult {
   // Source range of the relevant `const` token in the definition being 
checked.
   CharSourceRange ConstRange;
@@ -95,10 +107,14 @@
 
 void ConstReturnTypeCheck::registerMatchers(MatchFinder *Finder) {
   // Find all function definitions for which the return types are `const`
-  // qualified.
+  // qualified, ignoring decltype types.
+  auto NonLocalConstType = qualType(
+  unless(isLocalConstQualified()),
+  anyOf(decltypeType(), autoType(), isTypeOfType(), isTypeOfExprType()));
   Finder->addMatcher(
-  functionDecl(returns(isConstQualified()),
-   anyOf(isDefinition(), cxxMethodDecl(isPure(
+  functionDecl(
+  returns(allOf(isConstQualified(), unless(NonLocalConstType))),
+  anyOf(isDefinition(), cxxMethodDecl(isPure(
   .bind("func"),
   this);
 }


Index: clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s readability-const-return-type %t
+// RUN: %check_clang_tidy -std=c++14 %s readability-const-return-type %t
 
 //  p# = positive test
 //  n# = negative test
@@ -285,3 +285,40 @@
   // CHECK-MESSAGES: [[@LINE-1]]:3: warning: return type 'const int' is 'const'-qualified at the top level, which may reduce code readability without improving const correctness
   // CHECK-NOT-FIXES: int getC() { return 1; }
 };
+
+// Don't warn about const auto types, because it may be impossible to make them non-const
+// without a significant semantics change. Since `auto` drops cv-qualifiers,
+// tests check `decltype(auto)`.
+decltype(auto) n16() {
+  static const int i = 42;
+  return i;
+}
+
+// Don't warn about `decltype()` types
+const int n17i = 1;
+decltype(n17i) n17() {
+  return 17;
+}
+
+// Do warn when on decltype types with the local const qualifier
+// `const decltype(auto)` won't compile, so check only `const decltype()`
+const decltype(n17i) n18() {
+

[PATCH] D119792: [Clang] [P2025] Analyze only potential scopes for NRVO

2022-03-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

In D119792#3389126 , @erichkeane 
wrote:

> So P2025  has not successfully made it 
> through EWG, so this would have to be under a 'flag'.  Also, I believe this 
> will end up being applied to C++23, so it would have to be under a C++23 
> flag, even when we make it a default behavior.

I felt like this particular patch don't really need to wait until the paper 
make it to C++XX.

**RVO** (unnamed return value optimization), a simpler optimization, has been 
used for a very very long time, before they made it mandatory in C++17 
(effectively just describing the status quo in the Standard).

The paper contains an exhaustive set of NRVO use-cases. **13** out of **20** 
cases are already implemented in Clang, and the current patch makes it **17** 
out of **20**. I could send a patch without mentioning the paper at all, but it 
would be harder to track progress.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119792/new/

https://reviews.llvm.org/D119792

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119792: [Clang] [P2025] Analyze only potential scopes for NRVO

2022-03-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

Let me explain a bit more =)

The optimizations from this patch are allowed by the Standard (always have been 
allowed). So there is no need to restrict it under a flag or C++ version.

@erichkeane your comment indeed would be applicable if I allowed NRVO for 
non-movable types, that is currently prohibited by the Standard, but allowed in 
the proposal. Luckily my patch doesn't do this.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119792/new/

https://reviews.llvm.org/D119792

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D118743: [clang-tidy] Add `modernize-use-inline-const-variables-in-headers` check

2022-03-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 416347.
Izaron marked 7 inline comments as done.
Izaron added a comment.
Herald added a project: All.

Fix issues


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D118743/new/

https://reviews.llvm.org/D118743

Files:
  clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
  clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
  
clang-tools-extra/clang-tidy/modernize/UseInlineConstVariablesInHeadersCheck.cpp
  clang-tools-extra/clang-tidy/modernize/UseInlineConstVariablesInHeadersCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/docs/clang-tidy/checks/modernize-use-inline-const-variables-in-headers.rst
  
clang-tools-extra/test/clang-tidy/checkers/modernize-use-inline-const-variables-in-headers.hpp

Index: clang-tools-extra/test/clang-tidy/checkers/modernize-use-inline-const-variables-in-headers.hpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-use-inline-const-variables-in-headers.hpp
@@ -0,0 +1,43 @@
+// RUN: %check_clang_tidy %s -std=c++17 modernize-use-inline-const-variables-in-headers %t
+
+const int ConstFoo = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: global constant 'ConstFoo' should be marked as 'inline' [modernize-use-inline-const-variables-in-headers]
+// CHECK-FIXES: {{^}}inline const int ConstFoo = 1;{{$}}
+
+namespace N {
+constexpr int NamespaceFoo = 1;
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: global constant 'NamespaceFoo' should be marked as 'inline' [modernize-use-inline-const-variables-in-headers]
+// CHECK-FIXES: {{^}}inline constexpr int NamespaceFoo = 1;{{$}}
+} // namespace N
+
+extern const int ExternFoo;
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: global constant 'ExternFoo' should be converted to C++17 'inline variable' [modernize-use-inline-const-variables-in-headers]
+
+struct S {
+  // no warning: the variable is not at file scope
+  static const int StructFoo = 1;
+};
+
+// no warning: non-const global variables have external linkage
+int NonConstFoo = 1;
+
+// no warning: volatile global variables have external linkage
+const volatile int VolatileFoo = 1;
+
+// no warning: templates and their instantiations have external linkage
+template 
+const auto TemplateFoo = sizeof(T);
+
+// no warning: already fixed
+inline const int InlineFoo = 1;
+
+// no warning: C has no 'inline variables'
+extern "C" {
+const int CFoo0 = 1;
+}
+extern "C" const int CFoo1 = 1;
+
+// no warning: 'inline' is invisible when within an unnamed namespace
+namespace {
+const int AnonNamespaceFoo = 1;
+} // namespace
Index: clang-tools-extra/docs/clang-tidy/checks/modernize-use-inline-const-variables-in-headers.rst
===
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/modernize-use-inline-const-variables-in-headers.rst
@@ -0,0 +1,69 @@
+.. title:: clang-tidy - modernize-use-inline-const-variables-in-headers
+
+modernize-use-inline-const-variables-in-headers
+===
+
+
+Suggests switching to C++17 ``inline variables`` for non-inline const
+variable definitions and extern const variable declarations in header files.
+Non-inline const variables make a separate instance of the variable for each
+translation unit that includes the header, which can lead to subtle violation
+of the ODR. Extern const variables are a deprecated way to define a constant
+since C++17.
+
+.. code-block:: c++
+
+   // Foo.h
+   const int ConstFoo = 1; // Warning: should be marked as 'inline'
+
+   namespace N {
+ constexpr int NamespaceFoo = 1; // Warning: should be marked as 'inline'
+   }
+
+   extern const int ExternFoo; // Warning: should be converted to C++17 'inline variable'
+
+   struct S {
+ static const int StructFoo = 1; // OK: the variable is not at file scope
+   };
+
+   int NonConstFoo = 1; // No warning: non-const global variables have external linkage
+
+   const volatile int VolatileFoo = 1; // No warning: volatile global variables have external linkage
+
+   template
+   const auto TemplateFoo = sizeof(T); // OK: templates and their instantiations have external linkage
+
+   inline const int InlineFoo = 1; // no warning: already fixed
+
+   // No warning: C has no 'inline variables'
+   extern "C" {
+ const int CFoo0 = 1;
+   }
+   extern "C" const int CFoo1 = 1;
+
+   // No warning: 'inline' is invisible when within an unnamed namespace
+   namespace {
+ const int AnonNamespaceFoo = 1;
+   }
+
+Options
+---
+
+.. option:: HeaderFileExtensions
+
+   A comma-separated list of filename extensions of header files (the filename
+   extensions should not include "." prefix). Default is `h,hh,hpp,hxx`.
+   For header files without an extension, use an empty string (if there are no
+   other desired extensions) or leave an

[PATCH] D118743: [clang-tidy] Add `modernize-use-inline-const-variables-in-headers` check

2022-03-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/modernize/UseInlineConstVariablesInHeadersCheck.cpp:64-68
+  unless(hasType(isVolatileQualified())), // non-volatile
+  unless(isTemplateVariable()),   // non-template
+  unless(isVarInline()),  // non-inline
+  unless(isExternC()),   // not "extern C" variable
+  unless(isInAnonymousNamespace())); // not within an anonymous namespace

LegalizeAdulthood wrote:
> Comment: Why don't we have a variadic `unless(...)` matcher?
> 
> Is there any utility to reordering these `unless()` clauses in
> order of "most likely encountered first" to get an early out
> when matching?
Thanks, it is more convenient!

> reordering these unless() clauses in order of "most likely encountered first" 
I reordered them based on my own approximal estimation. We could make a 
benchmark to observe the impact of different orders, but it goes beyond this 
patch.



Comment at: 
clang-tools-extra/clang-tidy/modernize/UseInlineConstVariablesInHeadersCheck.h:19
+
+/// Finds non-extern non-inline function and variable definitions in header
+/// files, which can lead to potential ODR violations.

LegalizeAdulthood wrote:
> This block comment mentions functions, but the documentation only mentions 
> variables.
Oops, that's a typo: of course there are nothing abouth functions anywhere in 
the checker.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D118743/new/

https://reviews.llvm.org/D118743

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D118743: [clang-tidy] Add `modernize-use-inline-const-variables-in-headers` check

2022-03-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

In D118743#3290591 , 
@LegalizeAdulthood wrote:

> You've probably had this check in development for some time, but
> we just updated the documentation for contributing to clang-tidy
> and it might help to go over it for your new check to see if there
> is anything that stands out.
> https://clang.llvm.org/extra/clang-tidy/Contributing.html

Thanks, this is excellent documentation! I learned a plenty of new things.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D118743/new/

https://reviews.llvm.org/D118743

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119792: [Clang] [P2025] Analyze only potential scopes for NRVO

2022-03-18 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added inline comments.



Comment at: clang/include/clang/Sema/Scope.h:518
 
   void addNRVOCandidate(VarDecl *VD) {
+// every candidate except VD is "spoiled" now, remove them from the set

ChuanqiXu wrote:
> Firstly I am wondering why here doesn't check `NRVO.getInt()` to shortcut 
> directly. But later I found it would change the logic in 
> `::mergeNRVOIntoParent`:
> ```
> void Scope::mergeNRVOIntoParent() {
>   if (VarDecl *Candidate = NRVO.getPointer()) {
> if (isDeclScope(Candidate))
>   Candidate->setNRVOVariable(true);
>   }
>   ...
> ```
> 
> It would set NRVO for the candidate in NRVO if it is in current scope. With 
> the context of `addNRVOCandidate` here, I could judge that the change would 
> be:
> ```
> X test(bool B) {
>   X x; // before: no nrvo, after: no nrvo (same)
>   if (B)
> return x;
>   X y; // before: no nrvo, after: nrvo (better)
>   return y; // Now NRVO.getInt()==true and NRVO.getPointer() == y;
> }
> ```
> 
> Yeah, the behavior is still 'right'. `y` should be NRVO in this case. But the 
> implementation smell bad, if `NRVO.getInt()` is true, we shouldn't do any 
> thing. I am not sure if I state my points well. I mean the implementation 
> might be correct, but it is hard to understand, read and maintain. It'd 
> better to make the reader avoid doing mathmatics when reading the codes.
> I am not sure if I state my points well. I mean the implementation might be 
> correct, but it is hard to understand, read and maintain. It'd better to make 
> the reader avoid doing mathmatics when reading the codes.
I agree that it is really hard to understand and needs to be polished. It took 
long time for me to construct the code that won't break.

I think that one of the sources of the complexity is the `NRVO` variable itself.
If we could change
```
llvm::PointerIntPair NRVO;
```
to something like
```
VarDecl *NRVOCandidate;
bool InvalidatesParentNRVOCandidates;
```
And maybe rename `setNoNRVO()` to smth like `invalidateNRVOCandidates` and so 
on.

What do you think?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119792/new/

https://reviews.llvm.org/D119792

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D122075: [clang-tidy] Skip parentheses in `readability-make-member-function-const`

2022-03-19 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: mgehre-amd, njames93, aaron.ballman.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a project: All.
Izaron requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

The checker should ignore parentheses when looking whether the
function should be marked as `const`.

Fixes https://github.com/llvm/llvm-project/issues/52838


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D122075

Files:
  clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
@@ -40,6 +40,12 @@
 return ConstM;
   }
 
+  int read_fields_in_parentheses() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 
'read_fields_in_parentheses' can be made const
+// CHECK-FIXES: {{^}}  int read_fields_in_parentheses() const {
+return (this)->M + (Struct.M) + ((this->ConstM));
+  }
+
   void call_const_member() {
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member' can 
be made const
 // CHECK-FIXES: {{^}}  void call_const_member() const {
Index: clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
@@ -66,6 +66,15 @@
 return Parents.begin()->get();
   }
 
+  const Stmt *getParentStmt(const Expr *E) { return getParent(E); }
+
+  const Expr *getParentExpr(const Expr *E) {
+const Expr *Parent = getParent(E);
+while (isa_and_nonnull(Parent))
+  Parent = getParent(Parent);
+return Parent;
+  }
+
   bool VisitUnresolvedMemberExpr(const UnresolvedMemberExpr *) {
 // An UnresolvedMemberExpr might resolve to a non-const non-static
 // member function.
@@ -103,7 +112,7 @@
 if (!QT.isConstQualified())
   return false; // Stop traversal.
 
-const auto *Parent = getParent(Cast);
+const auto *Parent = getParentStmt(Cast);
 if (!Parent)
   return false; // Stop traversal.
 
@@ -140,7 +149,7 @@
   return true;
 }
 
-const auto *Parent = getParent(Member);
+const auto *Parent = getParentExpr(Member);
 
 if (const auto *Cast = dyn_cast_or_null(Parent)) {
   // A read access to a member is safe when the member either
@@ -167,12 +176,12 @@
   bool VisitCXXThisExpr(const CXXThisExpr *E) {
 Usage = Const;
 
-const auto *Parent = getParent(E);
+const auto *Parent = getParentExpr(E);
 
 // Look through deref of this.
 if (const auto *UnOp = dyn_cast_or_null(Parent)) {
   if (UnOp->getOpcode() == UO_Deref) {
-Parent = getParent(UnOp);
+Parent = getParentExpr(UnOp);
   }
 }
 


Index: clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
@@ -40,6 +40,12 @@
 return ConstM;
   }
 
+  int read_fields_in_parentheses() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_fields_in_parentheses' can be made const
+// CHECK-FIXES: {{^}}  int read_fields_in_parentheses() const {
+return (this)->M + (Struct.M) + ((this->ConstM));
+  }
+
   void call_const_member() {
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member' can be made const
 // CHECK-FIXES: {{^}}  void call_const_member() const {
Index: clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
@@ -66,6 +66,15 @@
 return Parents.begin()->get();
   }
 
+  const Stmt *getParentStmt(const Expr *E) { return getParent(E); }
+
+  const Expr *getParentExpr(const Expr *E) {
+const Expr *Parent = getParent(E);
+while (isa_and_nonnull(Parent))
+  Parent = getParent(Parent);
+return Parent;
+  }
+
   bool VisitUnresolvedMemberExpr(const UnresolvedMemberExpr *) {
 // An UnresolvedMemberExpr might resolve to a non-const non-static
 // member function.
@@ -103,7 +112,7 @@
 if (!QT.isConstQualified())
   return false; // Stop traversal

[PATCH] D122078: [clang-tidy] Ignore concepts in `misc-redundant-expression`

2022-03-19 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: hokein, njames93, aaron.ballman.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a project: All.
Izaron requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

The checker should ignore requirement expressions inside concept
definitions, because redundant expressions still make sense here

Fixes https://github.com/llvm/llvm-project/issues/54114


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D122078

Files:
  clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-redundant-expression.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s misc-redundant-expression %t -- -- -fno-delayed-template-parsing
+// RUN: %check_clang_tidy %s misc-redundant-expression -std=c++20 %t -- -- -fno-delayed-template-parsing
 
 typedef __INT64_TYPE__ I64;
 
@@ -807,3 +807,13 @@
 };
 
 } // namespace no_crash
+
+namespace concepts {
+// redundant expressions inside concepts make sense, ignore them
+template 
+concept TestConcept = requires(I i) {
+  {i - i};
+  {i && i};
+  {i ? i : i};
+};
+} // namespace concepts
Index: clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -10,6 +10,7 @@
 #include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
@@ -438,6 +439,8 @@
   return Node.isIntegerConstantExpr(Finder->getASTContext());
 }
 
+AST_MATCHER(Expr, isRequiresExpr) { return isa(Node); }
+
 AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
   return areEquivalentExpr(Node.getLHS(), Node.getRHS());
 }
@@ -831,6 +834,7 @@
 
   const auto BannedIntegerLiteral =
   integerLiteral(expandedByMacro(KnownBannedMacroNames));
+  const auto BannedAncestor = expr(isRequiresExpr());
 
   // Binary with equivalent operands, like (X != 2 && X != 2).
   Finder->addMatcher(
@@ -846,7 +850,8 @@
unless(hasType(realFloatingPointType())),
unless(hasEitherOperand(hasType(realFloatingPointType(,
unless(hasLHS(AnyLiteralExpr)),
-   unless(hasDescendant(BannedIntegerLiteral)))
+   unless(hasDescendant(BannedIntegerLiteral)),
+   unless(hasAncestor(BannedAncestor)))
.bind("binary")),
   this);
 
@@ -859,7 +864,8 @@
  unless(isInTemplateInstantiation()),
  unless(binaryOperatorIsInMacro()),
  // TODO: if the banned macros are themselves duplicated
- unless(hasDescendant(BannedIntegerLiteral)))
+ unless(hasDescendant(BannedIntegerLiteral)),
+ unless(hasAncestor(BannedAncestor)))
   .bind("nested-duplicates"),
   this);
 
@@ -869,7 +875,8 @@
conditionalOperator(expressionsAreEquivalent(),
// Filter noisy false positives.
unless(conditionalOperatorIsInMacro()),
-   unless(isInTemplateInstantiation()))
+   unless(isInTemplateInstantiation()),
+   unless(hasAncestor(BannedAncestor)))
.bind("cond")),
   this);
 
@@ -882,7 +889,8 @@
 ">=", "&&", "||", "="),
parametersAreEquivalent(),
// Filter noisy false positives.
-   unless(isMacro()), unless(isInTemplateInstantiation()))
+   unless(isMacro()), unless(isInTemplateInstantiation()),
+   unless(hasAncestor(BannedAncestor)))
.bind("call")),
   this);
 
@@ -892,7 +900,8 @@
   hasAnyOverloadedOperatorName("|", "&", "||", "&&", "^"),
   nestedParametersAreEquivalent(), argumentCountIs(2),
   // Filter noisy false positives.
-  unless(isMacro()), unless(isInTemplateInstantiation()))
+  unless(isMacro()), unless(isInTemplateInstantiation()),
+  unless(hasAncestor(BannedAncestor)))
   .bind("nested-duplicates"),
   this);
 
@@ -909,7 +918,8 @@
binaryOperator(hasAnyOperatorName("|", "&")

[PATCH] D122075: [clang-tidy] Skip parentheses in `readability-make-member-function-const`

2022-03-21 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 416870.
Izaron added a comment.

Fixed as suggested by njames93. Thank you!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122075/new/

https://reviews.llvm.org/D122075

Files:
  clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
@@ -40,6 +40,12 @@
 return ConstM;
   }
 
+  int read_fields_in_parentheses() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 
'read_fields_in_parentheses' can be made const
+// CHECK-FIXES: {{^}}  int read_fields_in_parentheses() const {
+return (this)->M + (Struct.M) + ((this->ConstM));
+  }
+
   void call_const_member() {
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member' can 
be made const
 // CHECK-FIXES: {{^}}  void call_const_member() const {
Index: clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
@@ -66,6 +66,13 @@
 return Parents.begin()->get();
   }
 
+  const Expr *getParentExprIgnoreParens(const Expr *E) {
+const Expr *Parent = getParent(E);
+while (isa_and_nonnull(Parent))
+  Parent = getParent(Parent);
+return Parent;
+  }
+
   bool VisitUnresolvedMemberExpr(const UnresolvedMemberExpr *) {
 // An UnresolvedMemberExpr might resolve to a non-const non-static
 // member function.
@@ -140,7 +147,7 @@
   return true;
 }
 
-const auto *Parent = getParent(Member);
+const auto *Parent = getParentExprIgnoreParens(Member);
 
 if (const auto *Cast = dyn_cast_or_null(Parent)) {
   // A read access to a member is safe when the member either
@@ -167,12 +174,12 @@
   bool VisitCXXThisExpr(const CXXThisExpr *E) {
 Usage = Const;
 
-const auto *Parent = getParent(E);
+const auto *Parent = getParentExprIgnoreParens(E);
 
 // Look through deref of this.
 if (const auto *UnOp = dyn_cast_or_null(Parent)) {
   if (UnOp->getOpcode() == UO_Deref) {
-Parent = getParent(UnOp);
+Parent = getParentExprIgnoreParens(UnOp);
   }
 }
 


Index: clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
@@ -40,6 +40,12 @@
 return ConstM;
   }
 
+  int read_fields_in_parentheses() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_fields_in_parentheses' can be made const
+// CHECK-FIXES: {{^}}  int read_fields_in_parentheses() const {
+return (this)->M + (Struct.M) + ((this->ConstM));
+  }
+
   void call_const_member() {
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member' can be made const
 // CHECK-FIXES: {{^}}  void call_const_member() const {
Index: clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
@@ -66,6 +66,13 @@
 return Parents.begin()->get();
   }
 
+  const Expr *getParentExprIgnoreParens(const Expr *E) {
+const Expr *Parent = getParent(E);
+while (isa_and_nonnull(Parent))
+  Parent = getParent(Parent);
+return Parent;
+  }
+
   bool VisitUnresolvedMemberExpr(const UnresolvedMemberExpr *) {
 // An UnresolvedMemberExpr might resolve to a non-const non-static
 // member function.
@@ -140,7 +147,7 @@
   return true;
 }
 
-const auto *Parent = getParent(Member);
+const auto *Parent = getParentExprIgnoreParens(Member);
 
 if (const auto *Cast = dyn_cast_or_null(Parent)) {
   // A read access to a member is safe when the member either
@@ -167,12 +174,12 @@
   bool VisitCXXThisExpr(const CXXThisExpr *E) {
 Usage = Const;
 
-const auto *Parent = getParent(E);
+const auto *Parent = getParentExprIgnoreParens(E);
 
 // Look through deref of this.
 if (const auto *UnOp = dyn_cast_or_null(Parent)) {
   if (UnOp->getOpcode() == UO_Deref) {
-Parent = getParent(UnOp);
+Parent = getParentExprIgnoreParens(UnOp);
 

[PATCH] D122075: [clang-tidy] Skip parentheses in `readability-make-member-function-const`

2022-03-21 Thread Evgeny Shulgin via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGfc354d375232: [clang-tidy] Skip parentheses in 
`readability-make-member-function-const` (authored by Izaron).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122075/new/

https://reviews.llvm.org/D122075

Files:
  clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
  
clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
===
--- 
clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
+++ 
clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
@@ -40,6 +40,12 @@
 return ConstM;
   }
 
+  int read_fields_in_parentheses() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 
'read_fields_in_parentheses' can be made const
+// CHECK-FIXES: {{^}}  int read_fields_in_parentheses() const {
+return (this)->M + (Struct.M) + ((this->ConstM));
+  }
+
   void call_const_member() {
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member' can 
be made const
 // CHECK-FIXES: {{^}}  void call_const_member() const {
Index: clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
@@ -66,6 +66,13 @@
 return Parents.begin()->get();
   }
 
+  const Expr *getParentExprIgnoreParens(const Expr *E) {
+const Expr *Parent = getParent(E);
+while (isa_and_nonnull(Parent))
+  Parent = getParent(Parent);
+return Parent;
+  }
+
   bool VisitUnresolvedMemberExpr(const UnresolvedMemberExpr *) {
 // An UnresolvedMemberExpr might resolve to a non-const non-static
 // member function.
@@ -140,7 +147,7 @@
   return true;
 }
 
-const auto *Parent = getParent(Member);
+const auto *Parent = getParentExprIgnoreParens(Member);
 
 if (const auto *Cast = dyn_cast_or_null(Parent)) {
   // A read access to a member is safe when the member either
@@ -167,12 +174,12 @@
   bool VisitCXXThisExpr(const CXXThisExpr *E) {
 Usage = Const;
 
-const auto *Parent = getParent(E);
+const auto *Parent = getParentExprIgnoreParens(E);
 
 // Look through deref of this.
 if (const auto *UnOp = dyn_cast_or_null(Parent)) {
   if (UnOp->getOpcode() == UO_Deref) {
-Parent = getParent(UnOp);
+Parent = getParentExprIgnoreParens(UnOp);
   }
 }
 


Index: clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-make-member-function-const.cpp
@@ -40,6 +40,12 @@
 return ConstM;
   }
 
+  int read_fields_in_parentheses() {
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_fields_in_parentheses' can be made const
+// CHECK-FIXES: {{^}}  int read_fields_in_parentheses() const {
+return (this)->M + (Struct.M) + ((this->ConstM));
+  }
+
   void call_const_member() {
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member' can be made const
 // CHECK-FIXES: {{^}}  void call_const_member() const {
Index: clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
@@ -66,6 +66,13 @@
 return Parents.begin()->get();
   }
 
+  const Expr *getParentExprIgnoreParens(const Expr *E) {
+const Expr *Parent = getParent(E);
+while (isa_and_nonnull(Parent))
+  Parent = getParent(Parent);
+return Parent;
+  }
+
   bool VisitUnresolvedMemberExpr(const UnresolvedMemberExpr *) {
 // An UnresolvedMemberExpr might resolve to a non-const non-static
 // member function.
@@ -140,7 +147,7 @@
   return true;
 }
 
-const auto *Parent = getParent(Member);
+const auto *Parent = getParentExprIgnoreParens(Member);
 
 if (const auto *Cast = dyn_cast_or_null(Parent)) {
   // A read access to a member is safe when the member either
@@ -167,12 +174,12 @@
   bool VisitCXXThisExpr(const CXXThisExpr *E) {
 Usage = Const;
 
-const auto *Parent = getParent(E);
+const auto *Parent = getParentExprIgnoreParens(E);
 
 // Look through deref of this.
 if (const auto *UnOp = dyn_cast_or_null(Parent)) {
   if (UnOp->getOpcode() == UO_Deref)

[PATCH] D118922: [ASTMatchers] The `isInline` matcher now accepts inline variables

2022-02-03 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: klimek, aaron.ballman.
Izaron requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Inline variables is a feature from C++17. It makes sense
to extend the `isInline` matcher in order to support corresponding varDecls.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D118922

Files:
  clang/docs/LibASTMatchersReference.html
  clang/docs/ReleaseNotes.rst
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp
  clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1455,6 +1455,23 @@
   "int main() { int x = 3; auto f = [vd=x]() { return vd; }; }", M));
 }
 
+TEST_P(ASTMatchersTest, IsInline) {
+  if (!GetParam().isCXX() && !GetParam().isC99OrLater())
+return;
+  EXPECT_TRUE(matches("void g(); inline void f();",
+  functionDecl(isInline(), hasName("f";
+
+  if (!GetParam().isCXX())
+return;
+  EXPECT_TRUE(matches("namespace n { inline namespace m {} }",
+  namespaceDecl(isInline(), hasName("m";
+
+  if (!GetParam().isCXX17OrLater())
+return;
+  EXPECT_TRUE(matches("inline constexpr int i = 1;",
+  varDecl(isInline(), hasName("i";
+}
+
 TEST_P(ASTMatchersTest, StorageDuration) {
   StringRef T =
   "void f() { int x; static int y; } int a;static int b;extern int c;";
Index: clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp
===
--- clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp
@@ -192,13 +192,6 @@
   llvm::ValueIs(TK_IgnoreUnlessSpelledInSource));
 }
 
-TEST(IsInlineMatcher, IsInline) {
-  EXPECT_TRUE(matches("void g(); inline void f();",
-  functionDecl(isInline(), hasName("f";
-  EXPECT_TRUE(matches("namespace n { inline namespace m {} }",
-  namespaceDecl(isInline(), hasName("m";
-}
-
 // FIXME: Figure out how to specify paths so the following tests pass on
 // Windows.
 #ifndef _WIN32
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -7673,25 +7673,29 @@
   return InnerMatcher.matches(*ES.getExpr(), Finder, Builder);
 }
 
-/// Matches function and namespace declarations that are marked with
+/// Matches variable, function and namespace declarations that are marked with
 /// the inline keyword.
 ///
 /// Given
 /// \code
+///   inline constexpr int i = 1;
 ///   inline void f();
 ///   void g();
 ///   namespace n {
 ///   inline namespace m {}
 ///   }
 /// \endcode
+/// varDecl(isInline()) will match ::i.
 /// functionDecl(isInline()) will match ::f().
 /// namespaceDecl(isInline()) will match n::m.
 AST_POLYMORPHIC_MATCHER(isInline,
-AST_POLYMORPHIC_SUPPORTED_TYPES(NamespaceDecl,
-FunctionDecl)) {
+AST_POLYMORPHIC_SUPPORTED_TYPES(VarDecl, FunctionDecl,
+NamespaceDecl)) {
   // This is required because the spelling of the function used to determine
   // whether inline is specified or not differs between the polymorphic types.
-  if (const auto *FD = dyn_cast(&Node))
+  if (const auto *VD = dyn_cast(&Node))
+return VD->isInline();
+  else if (const auto *FD = dyn_cast(&Node))
 return FD->isInlineSpecified();
   else if (const auto *NSD = dyn_cast(&Node))
 return NSD->isInline();
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -135,6 +135,8 @@
 AST Matchers
 
 
+- The ``isInline`` matcher now accepts inline variable declarations.
+
 clang-format
 
 
Index: clang/docs/LibASTMatchersReference.html
===
--- clang/docs/LibASTMatchersReference.html
+++ clang/docs/LibASTMatchersReference.html
@@ -4310,15 +4310,17 @@
 
 
 MatcherFunctionDecl>isInline
-Matches function and namespace declarations that are marked with
+Matches variable, function and namespace declarations that are marked with
 the inline keyword.
 
 Given
+  inline constexpr int i = 1;
   inline void f();
   void g();
   namespace n {
   inline namespace m {}
   }
+varDecl(isInline()) will match ::i.
 functionDecl(isInline()) w

[PATCH] D118922: [ASTMatchers] The `isInline` matcher now accepts inline variables

2022-02-03 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

I am planning to reuse this matcher in my new checker 
(https://reviews.llvm.org/D118743, under development now), removing this line:

  AST_MATCHER(VarDecl, isVarInline) { return Node.isInline(); }

//P.S. If this review is eventually approved, kindly please merge the commit on 
my behalf =) As I don't have merge access. My name is Evgeny Shulgin and email 
is izaronpl...@gmail.com. Sorry for inconvenience!//


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D118922/new/

https://reviews.llvm.org/D118922

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D118922: [ASTMatchers] The `isInline` matcher now accepts inline variables

2022-02-03 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added inline comments.



Comment at: clang/unittests/ASTMatchers/ASTMatchersInternalTest.cpp:195-201
-TEST(IsInlineMatcher, IsInline) {
-  EXPECT_TRUE(matches("void g(); inline void f();",
-  functionDecl(isInline(), hasName("f";
-  EXPECT_TRUE(matches("namespace n { inline namespace m {} }",
-  namespaceDecl(isInline(), hasName("m";
-}
-

Isn't this test equivalent to the new one I wrote in the other file? The 
difference between `TEST` and `TEST_P` I see is that the latter one allows you 
to check C++17 code, while the former does not. So I decided to have all checks 
in one place.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D118922/new/

https://reviews.llvm.org/D118922

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D118922: [ASTMatchers] The `isInline` matcher now accepts inline variables

2022-02-04 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron abandoned this revision.
Izaron added a comment.

In D118922#3296542 , @njames93 wrote:

> I had the same idea in D118900 

Wow! That's a curious coincidence. I'm closing my PR =) Let it be your version 
as the earlier one.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D118922/new/

https://reviews.llvm.org/D118922

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D118900: [ASTMatchers] Expand isInline matcher to VarDecl

2022-02-04 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

Thanks for the matcher! I'm planning to reuse it in my checker (D118743 
). Looking forward to seeing this commit 
merged.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D118900/new/

https://reviews.llvm.org/D118900

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D118900: [ASTMatchers] Expand isInline matcher to VarDecl

2022-02-04 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added inline comments.



Comment at: clang/docs/LibASTMatchersReference.html:5736
+MatcherVarDecl>isInline
+Matches function and 
namespace declarations that are marked with
+the inline keyword.

> Matches function and namespace declarations
Could it be something like
> Matches variable, function and namespace declarations
?

Also, maybe it worth to mention the checker in release notes? In 
`clang/docs/ReleaseNotes.rst`


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D118900/new/

https://reviews.llvm.org/D118900

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D118900: [ASTMatchers] Expand isInline matcher to VarDecl

2022-02-04 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added inline comments.



Comment at: clang/docs/LibASTMatchersReference.html:5736
+MatcherVarDecl>isInline
+Matches function and 
namespace declarations that are marked with
+the inline keyword.

Izaron wrote:
> > Matches function and namespace declarations
> Could it be something like
> > Matches variable, function and namespace declarations
> ?
> 
> Also, maybe it worth to mention the checker in release notes? In 
> `clang/docs/ReleaseNotes.rst`
(The matcher, not checker, of course)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D118900/new/

https://reviews.llvm.org/D118900

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119095: [clang] Fix redundant functional cast in ConstantExpr

2022-02-06 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: aaron.ballman, cor3ntin.
Izaron requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

When removing nested ConstantExprs, the tree transformer
doesn't remove redundant CXXFunctionalCasts that were created
"above" consteval constructors. After a while it generates a call
to a constructor, therefore violating the C++17 mandatory copy
elision rule.

Fixes https://github.com/llvm/llvm-project/issues/53244
and https://github.com/llvm/llvm-project/issues/53245


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D119095

Files:
  clang/lib/Sema/SemaExpr.cpp
  clang/test/SemaCXX/cxx2a-consteval.cpp


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,45 @@
 
 } // namespace unevaluated
 
+namespace mandatory_copy_elision {
+
+struct A {
+  consteval A() {}
+  consteval A(const A &);
+  consteval A(A &&);
+  consteval void f() {}
+};
+
+struct B {
+  consteval B() {}
+  consteval B(const B &) = delete;
+  consteval B(B &&) = delete;
+  consteval void f() {}
+};
+
+struct C {
+  consteval C() {}
+  consteval void f() {}
+
+private:
+  consteval C(const C &){};
+  consteval C(C &&){};
+};
+
+void test() {
+  { A{}.f(); }
+  { A{A{}}.f(); }
+  { A{A{A{A{A{A{A{A{.f(); }
+  { B{}.f(); }
+  { B{B{}}.f(); }
+  { B{B{B{B{B{B{B{B{.f(); }
+  { C{}.f(); }
+  { C{C{}}.f(); }
+  { C{C{C{C{C{C{C{C{.f(); }
+}
+
+} // namespace mandatory_copy_elision
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -16796,6 +16796,14 @@
   DRSet.erase(cast(E->getCallee()->IgnoreImplicit()));
   return Base::TransformCXXOperatorCallExpr(E);
 }
+/// Delete extra no-op functional casts to avoid calling a constructor
+ExprResult TransformCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
+  auto *CE = dyn_cast(E->getSubExpr());
+  if (E->getCastKind() != CK_NoOp || !CE || !CE->isImmediateInvocation())
+return Base::TransformCXXFunctionalCastExpr(E);
+  RemoveImmediateInvocation(CE);
+  return Base::TransformExpr(CE->getSubExpr());
+}
 /// Base::TransformInitializer skip ConstantExpr so we need to visit them
 /// here.
 ExprResult TransformInitializer(Expr *Init, bool NotCopyInit) {


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,45 @@
 
 } // namespace unevaluated
 
+namespace mandatory_copy_elision {
+
+struct A {
+  consteval A() {}
+  consteval A(const A &);
+  consteval A(A &&);
+  consteval void f() {}
+};
+
+struct B {
+  consteval B() {}
+  consteval B(const B &) = delete;
+  consteval B(B &&) = delete;
+  consteval void f() {}
+};
+
+struct C {
+  consteval C() {}
+  consteval void f() {}
+
+private:
+  consteval C(const C &){};
+  consteval C(C &&){};
+};
+
+void test() {
+  { A{}.f(); }
+  { A{A{}}.f(); }
+  { A{A{A{A{A{A{A{A{.f(); }
+  { B{}.f(); }
+  { B{B{}}.f(); }
+  { B{B{B{B{B{B{B{B{.f(); }
+  { C{}.f(); }
+  { C{C{}}.f(); }
+  { C{C{C{C{C{C{C{C{.f(); }
+}
+
+} // namespace mandatory_copy_elision
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -16796,6 +16796,14 @@
   DRSet.erase(cast(E->getCallee()->IgnoreImplicit()));
   return Base::TransformCXXOperatorCallExpr(E);
 }
+/// Delete extra no-op functional casts to avoid calling a constructor
+ExprResult TransformCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
+  auto *CE = dyn_cast(E->getSubExpr());
+  if (E->getCastKind() != CK_NoOp || !CE || !CE->isImmediateInvocation())
+return Base::TransformCXXFunctionalCastExpr(E);
+  RemoveImmediateInvocation(CE);
+  return Base::TransformExpr(CE->getSubExpr());
+}
 /// Base::TransformInitializer skip ConstantExpr so we need to visit them
 /// here.
 ExprResult TransformInitializer(Expr *Init, bool NotCopyInit) {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119095: [clang] Fix redundant functional cast in ConstantExpr

2022-02-06 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

There are some godbolt links in the github issues.

Expression `A{}.f();` generates the call of the move constructor from nowhere 
as well - https://godbolt.org/z/MceYedKzj

With the patch this node (that lives inside an another `ConstantExpr` node):

  MemberExpr 0x5e48b3d8 '' .f 0x5e48aa98
  `-MaterializeTemporaryExpr 0x5e48b3c0 'struct A' xvalue
`-CXXFunctionalCastExpr 0x5e48b398 'struct A' functional cast to struct 
A 
  `-ConstantExpr 0x5e48b200 'struct A'
`-CXXTemporaryObjectExpr 0x5e48b1d0 'struct A' 'void (void)' list

transforms to this:

  MemberExpr 0x5e48b3d8 '' .f 0x5e48aa98
  `-MaterializeTemporaryExpr 0x5e48b3c0 'struct A' xvalue
`-CXXTemporaryObjectExpr 0x5e48b1d0 'struct A' 'void (void)' list

I reviewed other github issues about consteval. This patch doesn't fix other 
known issues as I checked.

//P.S. If this review is eventually approved, kindly please merge the commit on 
my behalf =) As I don't have merge access. My name is `Evgeny Shulgin` and 
email is `izaronpl...@gmail.com`. Sorry for inconvenience!//


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119095/new/

https://reviews.llvm.org/D119095

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119098: [clang-tidy] Ignore variable template partial specializations in `misc-definitions-in-headers`

2022-02-06 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: njames93, hokein, LegalizeAdulthood.
Herald added subscribers: carlosgalvezp, xazax.hun.
Izaron requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Variable template partial specializations are inline and can't lead
to ODR-violations. The checker now ignores them.

Fixes https://github.com/llvm/llvm-project/issues/53519


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D119098

Files:
  clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/misc-definitions-in-headers.hpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/misc-definitions-in-headers.hpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-definitions-in-headers.hpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-definitions-in-headers.hpp
@@ -193,6 +193,16 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: full function template 
specialization 'f12' defined in a header file;
 // CHECK-FIXES: inline const int f12() { return 0; }
 
+template 
+constexpr bool f13 = false;
+
+template 
+constexpr bool f13 = true; // OK: template partial specialization
+
+template <>
+constexpr bool f13 = false;
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: variable 'f13' defined 
in a header file;
+
 int main() {}
 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'main' defined in a 
header file;
 // CHECK-FIXES: {{^}}int main() {
Index: clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
@@ -149,6 +149,9 @@
 // Ignore inline variables.
 if (VD->isInline())
   return;
+// Ignore partial specializations.
+if (isa(VD))
+  return;
 
 diag(VD->getLocation(),
  "variable %0 defined in a header file; "


Index: clang-tools-extra/test/clang-tidy/checkers/misc-definitions-in-headers.hpp
===
--- clang-tools-extra/test/clang-tidy/checkers/misc-definitions-in-headers.hpp
+++ clang-tools-extra/test/clang-tidy/checkers/misc-definitions-in-headers.hpp
@@ -193,6 +193,16 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: full function template specialization 'f12' defined in a header file;
 // CHECK-FIXES: inline const int f12() { return 0; }
 
+template 
+constexpr bool f13 = false;
+
+template 
+constexpr bool f13 = true; // OK: template partial specialization
+
+template <>
+constexpr bool f13 = false;
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: variable 'f13' defined in a header file;
+
 int main() {}
 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'main' defined in a header file;
 // CHECK-FIXES: {{^}}int main() {
Index: clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/DefinitionsInHeadersCheck.cpp
@@ -149,6 +149,9 @@
 // Ignore inline variables.
 if (VD->isInline())
   return;
+// Ignore partial specializations.
+if (isa(VD))
+  return;
 
 diag(VD->getLocation(),
  "variable %0 defined in a header file; "
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119098: [clang-tidy] Ignore variable template partial specializations in `misc-definitions-in-headers`

2022-02-06 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

A copy-pasted message below, as usual =)

//If this review is eventually approved, kindly please merge the commit on my 
behalf =) As I don't have merge access. My name is `Evgeny Shulgin` and email 
is `izaronpl...@gmail.com`. Sorry for inconvenience!//


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119098/new/

https://reviews.llvm.org/D119098

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119375: [Clang][Sema] Do not evaluate value-dependent immediate invocations

2022-02-09 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: aaron.ballman, cor3ntin.
Izaron requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Value-dependent ConstantExprs are not meant to be evaluated.
There is an assert in Expr::EvaluateAsConstantExpr that ensures this condition.
But before this patch the method was called without prior check.

Fixes https://github.com/llvm/llvm-project/issues/52768


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D119375

Files:
  clang/lib/Sema/SemaExpr.cpp
  clang/test/SemaCXX/cxx2a-consteval.cpp


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,26 @@
 
 } // namespace unevaluated
 
+namespace value_dependent {
+
+consteval int foo(int x) {
+  return x;
+}
+
+template  constexpr int bar() {
+  return foo(X);
+}
+
+template  constexpr int baz() {
+  constexpr int t = sizeof(T);
+  return foo(t);
+}
+
+static_assert(bar<15>() == 15);
+static_assert(baz() == sizeof(int));
+
+} // namespace value_dependent
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -16728,7 +16728,10 @@
   ConstantExpr::getStorageKind(Decl->getReturnType().getTypePtr(),
getASTContext()),
   /*IsImmediateInvocation*/ true);
-  ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
+  /// Value-dependent constant expression are not meant to be calculated.
+  /// Each template instantiation will calculate its own value later.
+  if (!Res->isValueDependent())
+ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
   return Res;
 }
 


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,26 @@
 
 } // namespace unevaluated
 
+namespace value_dependent {
+
+consteval int foo(int x) {
+  return x;
+}
+
+template  constexpr int bar() {
+  return foo(X);
+}
+
+template  constexpr int baz() {
+  constexpr int t = sizeof(T);
+  return foo(t);
+}
+
+static_assert(bar<15>() == 15);
+static_assert(baz() == sizeof(int));
+
+} // namespace value_dependent
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -16728,7 +16728,10 @@
   ConstantExpr::getStorageKind(Decl->getReturnType().getTypePtr(),
getASTContext()),
   /*IsImmediateInvocation*/ true);
-  ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
+  /// Value-dependent constant expression are not meant to be calculated.
+  /// Each template instantiation will calculate its own value later.
+  if (!Res->isValueDependent())
+ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
   return Res;
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119375: [Clang][Sema] Do not evaluate value-dependent immediate invocations

2022-02-09 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

The assert that I mentioned in the summary: 
https://github.com/llvm/llvm-project/blob/main/clang/lib/AST/ExprConstant.cpp#L14969
(Although `assert`s are deleted in release builds, one can check the violation 
by `llvm::errs() << isValueDependent() << "\n";` in the method)

I think I have found the right place to check the condition, right after 
creating the `ConstantExpr` object.

//P.S. If this review is eventually approved, kindly please merge the commit on 
my behalf =) As I don't have merge access. My name is `Evgeny Shulgin` and 
email is `izaronpl...@gmail.com`. Sorry for inconvenience!//


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119375/new/

https://reviews.llvm.org/D119375

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119375: [Clang][Sema] Do not evaluate value-dependent immediate invocations

2022-02-10 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 407449.
Izaron added a comment.

Fix comment


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119375/new/

https://reviews.llvm.org/D119375

Files:
  clang/lib/Sema/SemaExpr.cpp
  clang/test/SemaCXX/cxx2a-consteval.cpp


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,26 @@
 
 } // namespace unevaluated
 
+namespace value_dependent {
+
+consteval int foo(int x) {
+  return x;
+}
+
+template  constexpr int bar() {
+  return foo(X);
+}
+
+template  constexpr int baz() {
+  constexpr int t = sizeof(T);
+  return foo(t);
+}
+
+static_assert(bar<15>() == 15);
+static_assert(baz() == sizeof(int));
+
+} // namespace value_dependent
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -16747,7 +16747,10 @@
   ConstantExpr::getStorageKind(Decl->getReturnType().getTypePtr(),
getASTContext()),
   /*IsImmediateInvocation*/ true);
-  ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
+  /// Value-dependent constant expressions should not be immediately
+  /// evaluated until they are instantiated.
+  if (!Res->isValueDependent())
+ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
   return Res;
 }
 


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,26 @@
 
 } // namespace unevaluated
 
+namespace value_dependent {
+
+consteval int foo(int x) {
+  return x;
+}
+
+template  constexpr int bar() {
+  return foo(X);
+}
+
+template  constexpr int baz() {
+  constexpr int t = sizeof(T);
+  return foo(t);
+}
+
+static_assert(bar<15>() == 15);
+static_assert(baz() == sizeof(int));
+
+} // namespace value_dependent
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -16747,7 +16747,10 @@
   ConstantExpr::getStorageKind(Decl->getReturnType().getTypePtr(),
getASTContext()),
   /*IsImmediateInvocation*/ true);
-  ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
+  /// Value-dependent constant expressions should not be immediately
+  /// evaluated until they are instantiated.
+  if (!Res->isValueDependent())
+ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
   return Res;
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119375: [Clang][Sema] Do not evaluate value-dependent immediate invocations

2022-02-10 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron marked an inline comment as done.
Izaron added inline comments.



Comment at: clang/lib/Sema/SemaExpr.cpp:16731
   /*IsImmediateInvocation*/ true);
-  ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
+  /// Value-dependent constant expression are not meant to be calculated.
+  /// Each template instantiation will calculate its own value later.

cor3ntin wrote:
> I'd say something like
> 
> /// Value-dependent constant expressionS should not be immediately
> // evaluated until they are instantiated.
Sure, thanks! I'm bad at writing comments =)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119375/new/

https://reviews.llvm.org/D119375

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119375: [Clang][Sema] Do not evaluate value-dependent immediate invocations

2022-02-10 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 407564.
Izaron added a comment.

Add test comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119375/new/

https://reviews.llvm.org/D119375

Files:
  clang/lib/Sema/SemaExpr.cpp
  clang/test/SemaCXX/cxx2a-consteval.cpp


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,32 @@
 
 } // namespace unevaluated
 
+namespace value_dependent {
+
+consteval int foo(int x) {
+  return x;
+}
+
+template  constexpr int bar() {
+  // Previously this call was rejected as value-dependent constant expressions
+  // can't be immediately evaluated. Now we show that we don't immediately
+  // evaluate them until they are instantiated.
+  return foo(X);
+}
+
+template  constexpr int baz() {
+  constexpr int t = sizeof(T);
+  // Previously this call was rejected as `t` is value-dependent and its value
+  // is unknown until the function is instantiated. Now we show that we don't
+  // reject such calls.
+  return foo(t);
+}
+
+static_assert(bar<15>() == 15);
+static_assert(baz() == sizeof(int));
+
+} // namespace value_dependent
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -16747,7 +16747,10 @@
   ConstantExpr::getStorageKind(Decl->getReturnType().getTypePtr(),
getASTContext()),
   /*IsImmediateInvocation*/ true);
-  ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
+  /// Value-dependent constant expressions should not be immediately
+  /// evaluated until they are instantiated.
+  if (!Res->isValueDependent())
+ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
   return Res;
 }
 


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,32 @@
 
 } // namespace unevaluated
 
+namespace value_dependent {
+
+consteval int foo(int x) {
+  return x;
+}
+
+template  constexpr int bar() {
+  // Previously this call was rejected as value-dependent constant expressions
+  // can't be immediately evaluated. Now we show that we don't immediately
+  // evaluate them until they are instantiated.
+  return foo(X);
+}
+
+template  constexpr int baz() {
+  constexpr int t = sizeof(T);
+  // Previously this call was rejected as `t` is value-dependent and its value
+  // is unknown until the function is instantiated. Now we show that we don't
+  // reject such calls.
+  return foo(t);
+}
+
+static_assert(bar<15>() == 15);
+static_assert(baz() == sizeof(int));
+
+} // namespace value_dependent
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -16747,7 +16747,10 @@
   ConstantExpr::getStorageKind(Decl->getReturnType().getTypePtr(),
getASTContext()),
   /*IsImmediateInvocation*/ true);
-  ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
+  /// Value-dependent constant expressions should not be immediately
+  /// evaluated until they are instantiated.
+  if (!Res->isValueDependent())
+ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
   return Res;
 }
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119470: [clang-tidy] Don't check decltype return types in `readability-const-return-type`

2022-02-10 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: aaron.ballman, alexfh.
Herald added subscribers: carlosgalvezp, xazax.hun.
Izaron requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

The checker removes `const`s that are superfluos and badly affect
readability. `decltype(auto)`/`decltype(expr)` are often const-qualified, but
have no effect on readability and usually can't stop being const-qualified
without significant code change.

Fixes https://github.com/llvm/llvm-project/issues/52890


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D119470

Files:
  clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
  clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp


Index: 
clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s readability-const-return-type %t
+// RUN: %check_clang_tidy -std=c++14 %s readability-const-return-type %t
 
 //  p# = positive test
 //  n# = negative test
@@ -271,3 +271,25 @@
 
 int **const * n_multiple_ptr();
 int *const & n_pointer_ref();
+
+// Don't warn about const auto types, because it may be impossible to make 
them non-const
+// without a significant semantics change. Since `auto` drops cv-qualifiers,
+// tests check `decltype(auto)`.
+decltype(auto) n16() {
+  static const int i = 42;
+  return i;
+}
+
+// Don't warn about `decltype()` types as well
+const int n17i = 1;
+decltype(n17i) n17() {
+  return 17;
+}
+
+// Do warn when on decltype types with the local const qualifier
+// `const decltype(auto)` won't compile, so check only `const decltype()`
+const decltype(n17i) n18() {
+  // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const decltype(n17i)
+  // CHECK-FIXES: decltype(n17i) n18() {
+  return 18;
+}
Index: clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
@@ -53,6 +53,10 @@
 
 namespace {
 
+AST_MATCHER(QualType, isLocalConstQualified) {
+  return Node.isLocalConstQualified();
+}
+
 struct CheckResult {
   // Source range of the relevant `const` token in the definition being 
checked.
   CharSourceRange ConstRange;
@@ -95,9 +99,14 @@
 
 void ConstReturnTypeCheck::registerMatchers(MatchFinder *Finder) {
   // Find all function definitions for which the return types are `const`
-  // qualified.
+  // qualified, ignoring decltype types.
+  const auto NonLocalConstDecltypeType = qualType(
+  unless(isLocalConstQualified()), anyOf(decltypeType(), autoType()));
   Finder->addMatcher(
-  functionDecl(returns(isConstQualified()), isDefinition()).bind("func"),
+  functionDecl(
+  returns(allOf(isConstQualified(), 
unless(NonLocalConstDecltypeType))),
+  isDefinition())
+  .bind("func"),
   this);
 }
 


Index: clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
===
--- clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/readability-const-return-type.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s readability-const-return-type %t
+// RUN: %check_clang_tidy -std=c++14 %s readability-const-return-type %t
 
 //  p# = positive test
 //  n# = negative test
@@ -271,3 +271,25 @@
 
 int **const * n_multiple_ptr();
 int *const & n_pointer_ref();
+
+// Don't warn about const auto types, because it may be impossible to make them non-const
+// without a significant semantics change. Since `auto` drops cv-qualifiers,
+// tests check `decltype(auto)`.
+decltype(auto) n16() {
+  static const int i = 42;
+  return i;
+}
+
+// Don't warn about `decltype()` types as well
+const int n17i = 1;
+decltype(n17i) n17() {
+  return 17;
+}
+
+// Do warn when on decltype types with the local const qualifier
+// `const decltype(auto)` won't compile, so check only `const decltype()`
+const decltype(n17i) n18() {
+  // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const decltype(n17i)
+  // CHECK-FIXES: decltype(n17i) n18() {
+  return 18;
+}
Index: clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
===
--- clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
+++ clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp
@@ -53,6 +53,10 @@
 
 namespace {
 
+AST_MATCHER(QualType, isLocalConstQualified) {
+  return Node.isLocalConstQualified();
+}
+
 struct Check

[PATCH] D119470: [clang-tidy] Don't check decltype return types in `readability-const-return-type`

2022-02-10 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

I think we don't need to update the docs
(https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html)
Because a user would expect this behaviour.

//If this review is eventually approved, kindly please merge the commit on my 
behalf =) As I don't have merge access. My name is `Evgeny Shulgin` and email 
is `izaronpl...@gmail.com`. Sorry for inconvenience!//


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119470/new/

https://reviews.llvm.org/D119470

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119646: [clang] Allow consteval functions in default arguments

2022-02-12 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: aaron.ballman, erichkeane, andreasfertig.
Herald added a subscriber: kristof.beyls.
Izaron requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

We should not mark a function as "referenced" if we call it within a
ConstantExpr, because the expression will be folded to a value in LLVM IR.
To prevent emitting consteval function declarations, we should not "jump over"
a ConstantExpr when it is a top-level ParmVarDecl's subexpression.

Fixes https://github.com/llvm/llvm-project/issues/48230


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D119646

Files:
  clang/lib/AST/Decl.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/test/SemaCXX/cxx2a-consteval.cpp


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,27 @@
 
 } // namespace unevaluated
 
+namespace default_argument {
+
+// Previously calls of consteval functions in default arguments were rejected.
+// Now we show that we don't reject such calls.
+consteval int foo() { return 1; }
+consteval int bar(int i = foo()) { return i * i; }
+
+struct Test1 {
+  Test1(int i = bar(13)) {}
+  void v(int i = bar(13) * 2 + bar(15)) {}
+};
+Test1 t1;
+
+struct Test2 {
+  constexpr Test2(int i = bar()) {}
+  constexpr void v(int i = bar(bar(bar(foo() {}
+};
+Test2 t2;
+
+} // namespace default_argument
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -18964,6 +18964,12 @@
 Inherited::Visit(E);
   }
 
+  void VisitConstantExpr(ConstantExpr *E) {
+// Don't mark declarations within a ConstantExpression, as this expression
+// will be evaluated and folded to a value.
+return;
+  }
+
   void VisitDeclRefExpr(DeclRefExpr *E) {
 // If we were asked not to visit local variables, don't.
 if (SkipLocalVariables) {
Index: clang/lib/AST/Decl.cpp
===
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -2813,7 +2813,8 @@
 
   Expr *Arg = getInit();
   if (auto *E = dyn_cast_or_null(Arg))
-return E->getSubExpr();
+if (!isa(E))
+  return E->getSubExpr();
 
   return Arg;
 }


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,27 @@
 
 } // namespace unevaluated
 
+namespace default_argument {
+
+// Previously calls of consteval functions in default arguments were rejected.
+// Now we show that we don't reject such calls.
+consteval int foo() { return 1; }
+consteval int bar(int i = foo()) { return i * i; }
+
+struct Test1 {
+  Test1(int i = bar(13)) {}
+  void v(int i = bar(13) * 2 + bar(15)) {}
+};
+Test1 t1;
+
+struct Test2 {
+  constexpr Test2(int i = bar()) {}
+  constexpr void v(int i = bar(bar(bar(foo() {}
+};
+Test2 t2;
+
+} // namespace default_argument
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -18964,6 +18964,12 @@
 Inherited::Visit(E);
   }
 
+  void VisitConstantExpr(ConstantExpr *E) {
+// Don't mark declarations within a ConstantExpression, as this expression
+// will be evaluated and folded to a value.
+return;
+  }
+
   void VisitDeclRefExpr(DeclRefExpr *E) {
 // If we were asked not to visit local variables, don't.
 if (SkipLocalVariables) {
Index: clang/lib/AST/Decl.cpp
===
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -2813,7 +2813,8 @@
 
   Expr *Arg = getInit();
   if (auto *E = dyn_cast_or_null(Arg))
-return E->getSubExpr();
+if (!isa(E))
+  return E->getSubExpr();
 
   return Arg;
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119651: [clang] Fix evaluation context type for consteval function calls in instantiations

2022-02-12 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: aaron.ballman, erichkeane, rsmith.
Izaron requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

When instantiating a VarDecl initializing sub-AST, the evaluation
context was only PotentiallyEvaluated, even if we are inside a consteval
function. It dictated clang to construct a redundant ConstantExpr node, which
could be not evaluable.

Fixes https://github.com/llvm/llvm-project/issues/51182
and https://github.com/llvm/llvm-project/issues/52648


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D119651

Files:
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/test/SemaCXX/cxx2a-consteval.cpp


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,23 @@
 
 } // namespace unevaluated
 
+namespace templated {
+
+consteval int f(int v) {
+  return v;
+}
+
+template 
+consteval int g(T a) {
+  // Previously this call was rejected due to incorrect evaluation context 
type in instantiations. Now we show that this call is OK.
+  int n = f(a);
+  return n;
+}
+
+static_assert(g(100) == 100);
+
+} // namespace templated
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5326,8 +5326,13 @@
 Var->setImplicitlyInline();
 
   if (OldVar->getInit()) {
-EnterExpressionEvaluationContext Evaluated(
-*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
+ExpressionEvaluationContext Context =
+ExpressionEvaluationContext::PotentiallyEvaluated;
+// If current context is constant evaluated, the variable initializer
+// context is also constant evaluated
+if (isConstantEvaluated())
+  Context = ExpressionEvaluationContext::ConstantEvaluated;
+EnterExpressionEvaluationContext Evaluated(*this, Context, Var);
 
 // Instantiate the initializer.
 ExprResult Init;


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,23 @@
 
 } // namespace unevaluated
 
+namespace templated {
+
+consteval int f(int v) {
+  return v;
+}
+
+template 
+consteval int g(T a) {
+  // Previously this call was rejected due to incorrect evaluation context type in instantiations. Now we show that this call is OK.
+  int n = f(a);
+  return n;
+}
+
+static_assert(g(100) == 100);
+
+} // namespace templated
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5326,8 +5326,13 @@
 Var->setImplicitlyInline();
 
   if (OldVar->getInit()) {
-EnterExpressionEvaluationContext Evaluated(
-*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
+ExpressionEvaluationContext Context =
+ExpressionEvaluationContext::PotentiallyEvaluated;
+// If current context is constant evaluated, the variable initializer
+// context is also constant evaluated
+if (isConstantEvaluated())
+  Context = ExpressionEvaluationContext::ConstantEvaluated;
+EnterExpressionEvaluationContext Evaluated(*this, Context, Var);
 
 // Instantiate the initializer.
 ExprResult Init;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119651: [clang] Fix evaluation context type for consteval function calls in instantiations

2022-02-12 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 408220.
Izaron added a comment.

(Fast test comment 80 character line fix)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119651/new/

https://reviews.llvm.org/D119651

Files:
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/test/SemaCXX/cxx2a-consteval.cpp


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,24 @@
 
 } // namespace unevaluated
 
+namespace templated {
+
+consteval int f(int v) {
+  return v;
+}
+
+template 
+consteval int g(T a) {
+  // Previously this call was rejected due to incorrect evaluation context
+  // type in instantiations. Now we show that this call is OK.
+  int n = f(a);
+  return n;
+}
+
+static_assert(g(100) == 100);
+
+} // namespace templated
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5326,8 +5326,13 @@
 Var->setImplicitlyInline();
 
   if (OldVar->getInit()) {
-EnterExpressionEvaluationContext Evaluated(
-*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
+ExpressionEvaluationContext Context =
+ExpressionEvaluationContext::PotentiallyEvaluated;
+// If current context is constant evaluated, the variable initializer
+// context is also constant evaluated
+if (isConstantEvaluated())
+  Context = ExpressionEvaluationContext::ConstantEvaluated;
+EnterExpressionEvaluationContext Evaluated(*this, Context, Var);
 
 // Instantiate the initializer.
 ExprResult Init;


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,24 @@
 
 } // namespace unevaluated
 
+namespace templated {
+
+consteval int f(int v) {
+  return v;
+}
+
+template 
+consteval int g(T a) {
+  // Previously this call was rejected due to incorrect evaluation context
+  // type in instantiations. Now we show that this call is OK.
+  int n = f(a);
+  return n;
+}
+
+static_assert(g(100) == 100);
+
+} // namespace templated
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5326,8 +5326,13 @@
 Var->setImplicitlyInline();
 
   if (OldVar->getInit()) {
-EnterExpressionEvaluationContext Evaluated(
-*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
+ExpressionEvaluationContext Context =
+ExpressionEvaluationContext::PotentiallyEvaluated;
+// If current context is constant evaluated, the variable initializer
+// context is also constant evaluated
+if (isConstantEvaluated())
+  Context = ExpressionEvaluationContext::ConstantEvaluated;
+EnterExpressionEvaluationContext Evaluated(*this, Context, Var);
 
 // Instantiate the initializer.
 ExprResult Init;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119646: [clang] Allow consteval functions in default arguments

2022-02-13 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

In D119646#3317473 , @cor3ntin wrote:

> There is also https://reviews.llvm.org/D74130 which tries to address the same 
> issue in a very different way.
> I don't really understand the different approaches yet.

Thanks! I spent some time researching this review (but tbh I don't fully 
understand it yet too). I can say why this patch seems to be so different.

The author aims to make this snippet working

  consteval int f1() { return 0; }
  consteval auto g() { return f1; }
  consteval int h(int (*p)() = g()) { return p(); } // should work

That is, they want to make usable pointers to consteval function in default 
arguments. My patch doesn't compile this code now (the behaviour is same as in 
trunk).
As far as I see, the main problem is that the evaluation of ParmVarDecl's 
ConstantExpr is "isolated" from the evaluation of the consteval function body. 
Therefore the pointer "breaks the constexpr wall" and "falls out" to run-time, 
that's illegal. I'm not sure if my explanation is clear...

I wonder if it could be a different pull request later if someone will want to 
make pointers working? The review you mentioned is 2 years old, pretty massive 
and still has failing tests.




Comment at: clang/lib/AST/Decl.cpp:2816
   if (auto *E = dyn_cast_or_null(Arg))
-return E->getSubExpr();
+if (!isa(E))
+  return E->getSubExpr();

erichkeane wrote:
> So what is happening here?  I would still expect us to give the proper 
> default-arg in this case?  What subtly am I missing?
If we have nested ConstantExprs within the default argument expression, like 
here
```
consteval int Fun(int x) { return x; }

struct Test {
  Test(int loc = Fun(1) * 3 + Fun(2)) {}
  // or, for example, Test(int loc = 0 + Fun(4));
};
```
Then the patch fixes it fine with just `void VisitConstantExpr...` (the snippet 
where you said //"This part makes sense to me."//).

The AST for ParmVarDecl looks like this - [[ 
https://gist.githubusercontent.com/Izaron/7b49d4814a04d16c8014d973bd397ac4/raw/fd5948ca164a381ed13950f04934cb19f847141d/nested.ast
 | snippet on gist.github.com ]]. Clang will fold the ConstantExprs.

---

However, if the ConstantExpr is top-level, that is, the code looks like this:
```
struct Test {
  Test(int loc = Fun(4)) {}
};
```
Then the AST looks like this - [[ 
https://gist.githubusercontent.com/Izaron/dec1f3f0b62769c8fe4f4cb961c211d7/raw/79c5b9364e93de7ebc3d905f87162e000c6e695b/top-level.ast
 | snippet on gist.github.com ]].

There are some places in the code where we call `ParmVarDecl::getDefaultArg()` 
(CodeGen/etc.) The callee will "jump over" the ConstantExpr (since it is 
derived from FullExpr) and give you the nested CallExpr. That's quite incorrent 
because we aren't going to evaluate this CallExpr in run-time. For example, if 
we don't patch this place, the CodeGen will declare `Fun` at LLVM IR, and 
everything breaks.

So I decided that we shouldn't "jump over" ConstantExpr, otherwise it 
incorrectly says to the caller that we are supposed to calculate it in run-time.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119646/new/

https://reviews.llvm.org/D119646

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119651: [clang] Fix evaluation context type for consteval function calls in instantiations

2022-02-13 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

> Should we maybe always treat `PotentiallyEvaluated` as `ConstantEvaluated` in 
> constant evaluated contexts? could that work ?

Indeed, within this patch we can prevent similars bugs to appear. I researched 
other places where a new context is pushed, and haven't find other bugs, but 
nevertheless.
In my subjective opinion, the architecture of `ExprEvalContext` is pretty 
fragile... We could add an assert before this line 
,
 ensuring that we don't push a (runtime) evaluated context after an immediate 
context. Or should we just don't push the new context in this case?... I wonder 
what is better, can't say right now =(

In D119651#3317458 , @cor3ntin wrote:

> There seems to be quite a number of consteval related issues still - 
> https://reviews.llvm.org/D113859 is very similar - yet completely unrelated -
>
> This patch does look okay to me, in so far as it fixes this issue, in a way 
> that seems sensible to me. I'm just wondering if there are similar issues in 
> other places...

BTW after looking at consteval-related issues on github 
, 
I've made four bite-sized patches. The issues are indeed completely unrelated 
to each other and do not have common source of errors.

https://reviews.llvm.org/D119095 Extra constructor call - a fix in 
`RemoveNestedImmediateInvocation`.
https://reviews.llvm.org/D119375 Trying to evaluate value-dependent 
ConstantExpr - a fix in `CheckForImmediateInvocation` (approved)
https://reviews.llvm.org/D119646 Trying to mark declarations as "referenced" 
inside a ConstantExpr in default arguments - a fix in the custom def. arg. AST 
visitor.
https://reviews.llvm.org/D119651 (This patch) a `PotentiallyEvaluated` context 
is created within a `ConstantEvaluated` context - remove where we do this.

As far as I see, the consteval bugs rarely have common source... They mostly 
require ad-hoc solutions.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119651/new/

https://reviews.llvm.org/D119651

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119792: [Clang] [P2025] Analyze only potential scopes for NRVO

2022-02-14 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: lebedev.ri, rsmith.
Izaron requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Before the patch we calculated the NRVO candidate looking at the
variable's whole enclosing scope. The research in [P2025 
] shows that looking
at the variable's potential scope is better and covers more cases where NRVO
would be safe and desirable.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D119792

Files:
  clang/include/clang/Sema/Scope.h
  clang/test/CodeGenCXX/nrvo.cpp

Index: clang/test/CodeGenCXX/nrvo.cpp
===
--- clang/test/CodeGenCXX/nrvo.cpp
+++ clang/test/CodeGenCXX/nrvo.cpp
@@ -166,88 +166,19 @@
 
 // CHECK-LABEL: @_Z5test3b(
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
-// CHECK-NEXT:br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-// CHECK:   if.then:
 // CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]]
-// CHECK-NEXT:br label [[RETURN:%.*]]
-// CHECK:   if.end:
-// CHECK-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
-// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
-// CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
-// CHECK-NEXT:call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
-// CHECK-NEXT:call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
-// CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
-// CHECK-NEXT:br label [[RETURN]]
-// CHECK:   return:
 // CHECK-NEXT:ret void
 //
-// CHECK-EH-03-LABEL: @_Z5test3b(
-// CHECK-EH-03-NEXT:  entry:
-// CHECK-EH-03-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
-// CHECK-EH-03-NEXT:br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-// CHECK-EH-03:   if.then:
-// CHECK-EH-03-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]])
-// CHECK-EH-03-NEXT:br label [[RETURN:%.*]]
-// CHECK-EH-03:   if.end:
-// CHECK-EH-03-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
-// CHECK-EH-03-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]]
-// CHECK-EH-03-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-// CHECK-EH-03-NEXT:invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-// CHECK-EH-03-NEXT:to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
-// CHECK-EH-03:   invoke.cont:
-// CHECK-EH-03-NEXT:call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-// CHECK-EH-03-NEXT:call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]]
-// CHECK-EH-03-NEXT:br label [[RETURN]]
-// CHECK-EH-03:   lpad:
-// CHECK-EH-03-NEXT:[[TMP1:%.*]] = landingpad { i8*, i32 }
-// CHECK-EH-03-NEXT:cleanup
-// CHECK-EH-03-NEXT:invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-// CHECK-EH-03-NEXT:to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
-// CHECK-EH-03:   invoke.cont1:
-// CHECK-EH-03-NEXT:call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]]
-// CHECK-EH-03-NEXT:resume { i8*, i32 } [[TMP1]]
-// CHECK-EH-03:   return:
-// CHECK-EH-03-NEXT:ret void
-// CHECK-EH-03:   terminate.lpad:
-// CHECK-EH-03-NEXT:[[TMP2:%.*]] = landingpad { i8*, i32 }
-// CHECK-EH-03-NEXT:catch i8* null
-// CHECK-EH-03-NEXT:[[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0
-// CHECK-EH-03-NEXT:call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]]
-// CHECK-EH-03-NEXT:unreachable
-//
-// CHECK-EH-11-LABEL: @_Z5test3b(
-// CHECK-EH-11-NEXT:  entry:
-// CHECK-EH-11-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
-// CHECK-EH-11-NEXT:br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-// CHECK-EH-11:   if.then:
-// CHECK-EH-11-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]])
-// CHECK-EH-11-NEXT:br label [[RETURN:%.*]]
-// CHECK-EH-11:   if.end:
-// CHECK-EH-11-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
-// CHECK-EH-11-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]]
-// CHECK-EH-11-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 d

[PATCH] D119792: [Clang] [P2025] Analyze only potential scopes for NRVO

2022-02-14 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

There is a nice proposal (P2025) Guaranteed copy elision for return variables 
 by 
**Anton Zhilin**. The poll on the proposal showed that its ideas are very 
welcome: link to cplusplus/papers github 
. 
Although the proposal is not yet accepted into the Standard in its current 
wording, some ideas are still good and can be implemented "in advance".

> This proposal aims to provide guaranteed copy elision for common cases of 
> local variables being returned from a function, a.k.a. "guaranteed NRVO".

С++ сompiler implementations determine by their own rules whether there will be 
a NRVO (since it is not a required optimization). The proposal contains a 
collection of common cases of local variables being returned where copy elision 
is safe and makes senses and therefore is desirable to do.

The main requirement (omitting details for language-lawyers) is that:

> Copy elision is guaranteed for return x; if every return "seen" by x is 
> return x;

"seen by `x`" means here "all non-discarded return statements in `x`'s 
potential scope". There are more details in the proposal.

The collection of common cases contains 20 examples: §4.1. Examples 
.
Here is the current status of these examples:

- [OK] 13 out of 20 examples are working in Clang as expected.
- [FAIL] 13th example: should be considered separately (as part of fixing 
consteval code)
- [FAIL] 14th example: should be considered separately (as I haven't looked yet 
how `CXXCatchStmt` works).
- [FAIL] 18th example: is unfixable now because of Clang's architecture: my 
comment on the issue 
.
- **[OK with the patch]** 7th, 8th, 11th, 15th example: are working with this 
patch.

In order to make the last group of 4 examples working, there is a need to 
rewrite the logic for calculating the NRVO candidate.
The `clang::Scope` class has methods `void AddDecl(Decl *D)`, `void 
addNRVOCandidate(VarDecl *VD)`, `void setNoNRVO()`, that are called in the 
order of the scope's parsing.

- `void AddDecl(Decl *D)` is called when there is a new `Decl *D` in the scope. 
The `D`'s potential scope starts now.
- `void addNRVOCandidate(VarDecl *VD)` is called when there is a `return 
` in the scope or when a children scope has successfully 
calculated its single NRVO candidate.
- `void setNoNRVO()` is called when there is a `return ` in 
the scope or when a children scope is telling us to drop our NRVO candidates 
(nevertheless, the children scope now can still succesfully calculated the NRVO 
candidate).

We need to have a set of "unspoiled variables" to find the NRVO candidate 
effectively (yeah, introducing some made up terminology...) A variable is 
"unspoiled" if it is not forbidden to be the NRVO candidate yet. An `AddDecl` 
call adds the variable to this set. An `addNRVOCandidate` call "spoils" every 
variable except `VD`. A `setNoNRVO` "spoils" every variable. Only an "unspoiled 
variable" may be the NRVO candidate.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119792/new/

https://reviews.llvm.org/D119792

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119792: [Clang] [P2025] Analyze only potential scopes for NRVO

2022-02-14 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

Cases that show the difference (they're covered in tests, though do we need an 
AST test as well?):

  X test(bool B) {
if (B) {
  X y; // before: nrvo, after: nrvo (same)
  return y;
}
X x; // before: no nrvo, after: nrvo (better)
return x;
  }

  X test(bool B) {
X x; // before: no nrvo, after: no nrvo (same)
if (B)
  return x;
X y; // before: no nrvo, after: nrvo (better)
return y;
  }

  X test(bool A, bool B) {
{
  {
X x; // before: nrvo, after: nrvo (same)
if (A)
  return x;
  }
  X y; // before: no nrvo, after: nrvo (better)
  if (B)
return y;
}
X z;
retur n z; // before: no nrvo, after: nrvo (better)
  }


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119792/new/

https://reviews.llvm.org/D119792

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119792: [Clang] [P2025] Analyze only potential scopes for NRVO

2022-02-15 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 408999.
Izaron added a comment.

Fix Scope::dumpImpl with more precise log


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119792/new/

https://reviews.llvm.org/D119792

Files:
  clang/include/clang/Sema/Scope.h
  clang/lib/Sema/Scope.cpp
  clang/test/CodeGenCXX/nrvo.cpp

Index: clang/test/CodeGenCXX/nrvo.cpp
===
--- clang/test/CodeGenCXX/nrvo.cpp
+++ clang/test/CodeGenCXX/nrvo.cpp
@@ -166,88 +166,19 @@
 
 // CHECK-LABEL: @_Z5test3b(
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
-// CHECK-NEXT:br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-// CHECK:   if.then:
 // CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]]
-// CHECK-NEXT:br label [[RETURN:%.*]]
-// CHECK:   if.end:
-// CHECK-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
-// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
-// CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
-// CHECK-NEXT:call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
-// CHECK-NEXT:call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
-// CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
-// CHECK-NEXT:br label [[RETURN]]
-// CHECK:   return:
 // CHECK-NEXT:ret void
 //
-// CHECK-EH-03-LABEL: @_Z5test3b(
-// CHECK-EH-03-NEXT:  entry:
-// CHECK-EH-03-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
-// CHECK-EH-03-NEXT:br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-// CHECK-EH-03:   if.then:
-// CHECK-EH-03-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]])
-// CHECK-EH-03-NEXT:br label [[RETURN:%.*]]
-// CHECK-EH-03:   if.end:
-// CHECK-EH-03-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
-// CHECK-EH-03-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]]
-// CHECK-EH-03-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-// CHECK-EH-03-NEXT:invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-// CHECK-EH-03-NEXT:to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
-// CHECK-EH-03:   invoke.cont:
-// CHECK-EH-03-NEXT:call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-// CHECK-EH-03-NEXT:call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]]
-// CHECK-EH-03-NEXT:br label [[RETURN]]
-// CHECK-EH-03:   lpad:
-// CHECK-EH-03-NEXT:[[TMP1:%.*]] = landingpad { i8*, i32 }
-// CHECK-EH-03-NEXT:cleanup
-// CHECK-EH-03-NEXT:invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-// CHECK-EH-03-NEXT:to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
-// CHECK-EH-03:   invoke.cont1:
-// CHECK-EH-03-NEXT:call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]]
-// CHECK-EH-03-NEXT:resume { i8*, i32 } [[TMP1]]
-// CHECK-EH-03:   return:
-// CHECK-EH-03-NEXT:ret void
-// CHECK-EH-03:   terminate.lpad:
-// CHECK-EH-03-NEXT:[[TMP2:%.*]] = landingpad { i8*, i32 }
-// CHECK-EH-03-NEXT:catch i8* null
-// CHECK-EH-03-NEXT:[[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0
-// CHECK-EH-03-NEXT:call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]]
-// CHECK-EH-03-NEXT:unreachable
-//
-// CHECK-EH-11-LABEL: @_Z5test3b(
-// CHECK-EH-11-NEXT:  entry:
-// CHECK-EH-11-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
-// CHECK-EH-11-NEXT:br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
-// CHECK-EH-11:   if.then:
-// CHECK-EH-11-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]])
-// CHECK-EH-11-NEXT:br label [[RETURN:%.*]]
-// CHECK-EH-11:   if.end:
-// CHECK-EH-11-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
-// CHECK-EH-11-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]]
-// CHECK-EH-11-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-// CHECK-EH-11-NEXT:invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
-// CHECK-EH-11-NEXT:to label [[INVOKE_CONT:%.*]] unwin

[PATCH] D119651: [clang] Fix evaluation context type for consteval function calls in instantiations

2022-02-15 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 409035.
Izaron added a comment.

I've added an assert that will prevent similar bugs. Let's look if we're good 
with this one?
Here is the list of eval contexts:
https://github.com/llvm/llvm-project/blob/87b218b42b14e392aa0363a413d440b77bf04bd4/clang/include/clang/Sema/Sema.h#L1191-L1239
Should we also check for `PotentiallyEvaluatedIfUsed` or it is too much?
Looks like only two eval contexts from the list may be evaluated in run-time.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119651/new/

https://reviews.llvm.org/D119651

Files:
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/test/SemaCXX/cxx2a-consteval.cpp


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,24 @@
 
 } // namespace unevaluated
 
+namespace templated {
+
+consteval int f(int v) {
+  return v;
+}
+
+template 
+consteval int g(T a) {
+  // Previously this call was rejected due to incorrect evaluation context
+  // type in instantiations. Now we show that this call is OK.
+  int n = f(a);
+  return n;
+}
+
+static_assert(g(100) == 100);
+
+} // namespace templated
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5326,8 +5326,13 @@
 Var->setImplicitlyInline();
 
   if (OldVar->getInit()) {
-EnterExpressionEvaluationContext Evaluated(
-*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
+ExpressionEvaluationContext Context =
+ExpressionEvaluationContext::PotentiallyEvaluated;
+// If current context is constant evaluated, the variable initializer
+// context is also constant evaluated
+if (isConstantEvaluated())
+  Context = ExpressionEvaluationContext::ConstantEvaluated;
+EnterExpressionEvaluationContext Evaluated(*this, Context, Var);
 
 // Instantiate the initializer.
 ExprResult Init;
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -16637,6 +16637,11 @@
 ExpressionEvaluationContextRecord::ExpressionKind ExprContext) {
   ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup,
 LambdaContextDecl, ExprContext);
+  assert(
+  !(ExprEvalContexts.back().Context ==
+ExpressionEvaluationContext::PotentiallyEvaluated &&
+ExprEvalContexts[ExprEvalContexts.size() - 2].isConstantEvaluated()) &&
+  "Can't have an evaluated context within an unevaluated context!");
 
   // Discarded statements and immediate contexts nested in other
   // discarded statements or immediate context are themselves


Index: clang/test/SemaCXX/cxx2a-consteval.cpp
===
--- clang/test/SemaCXX/cxx2a-consteval.cpp
+++ clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -613,6 +613,24 @@
 
 } // namespace unevaluated
 
+namespace templated {
+
+consteval int f(int v) {
+  return v;
+}
+
+template 
+consteval int g(T a) {
+  // Previously this call was rejected due to incorrect evaluation context
+  // type in instantiations. Now we show that this call is OK.
+  int n = f(a);
+  return n;
+}
+
+static_assert(g(100) == 100);
+
+} // namespace templated
+
 namespace PR50779 {
 struct derp {
   int b = 0;
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5326,8 +5326,13 @@
 Var->setImplicitlyInline();
 
   if (OldVar->getInit()) {
-EnterExpressionEvaluationContext Evaluated(
-*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
+ExpressionEvaluationContext Context =
+ExpressionEvaluationContext::PotentiallyEvaluated;
+// If current context is constant evaluated, the variable initializer
+// context is also constant evaluated
+if (isConstantEvaluated())
+  Context = ExpressionEvaluationContext::ConstantEvaluated;
+EnterExpressionEvaluationContext Evaluated(*this, Context, Var);
 
 // Instantiate the initializer.
 ExprResult Init;
Index: clang/lib/Sema/SemaExpr.cpp
===
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -16637,6 +16637,11 @@
 ExpressionEvaluationContextRecord::ExpressionKind ExprContext) {
   ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup,
  

[PATCH] D119792: [Clang] [P2025] Analyze only potential scopes for NRVO

2022-02-15 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

In D119792#3324354 , @Quuxplusone 
wrote:

> I think it would be an extremely good idea to commit all 20 of these test 
> cases to clang/test/CodeGenCXX/, with their current behavior, as a 
> preliminary patch. Then, D119792  can more 
> clearly show (1) what behavior it's changing, (2) what behavior it's keeping 
> the same, and (3) the fact that it's not regressing any behavior.  Also, 
> you'll help future-maintainers by giving them some extra test cases that have 
> already been identified as interesting, even if you personally aren't 
> changing behavior related to those particular test cases.
>
> (I recently took the same tactic with D119772 
>  as a preliminary for D119184 
>  + D119778 
> , and it was very helpful, at least to me. 
> :))

That's a superb idea, thanks! I will soon add all the cases to 
`clang/test/CodeGenCXX/nrvo.cpp` in an isolated patch. It indeed will 
explicitly show improvements in future patches and prevent silent NRVO 
regression.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119792/new/

https://reviews.llvm.org/D119792

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119927: [Clang] [P2025] More exhaustive tests for NRVO

2022-02-16 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: mizvekov, Quuxplusone, sammccall, rsmith, doug.gregor.
Izaron requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This is a preliminary patch ahead of D119792  
(I'll rebase that one on top of this).
This shows what Clang's _current_ behaviour is for calculating NRVO in various
common cases. Then, in D119792  (and future 
patches), I'll be able to demostrate
exactly how LLVM IR for each of these cases changes.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D119927

Files:
  clang/test/CodeGenCXX/nrvo.cpp

Index: clang/test/CodeGenCXX/nrvo.cpp
===
--- clang/test/CodeGenCXX/nrvo.cpp
+++ clang/test/CodeGenCXX/nrvo.cpp
@@ -1,13 +1,14 @@
 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
 // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -o - %s | FileCheck %s
 // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++03 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-03 %s
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++11 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-11 %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++11 -DCXX11 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-11 %s
 
 // Test code generation for the named return value optimization.
 class X {
 public:
   X();
   X(const X&);
+  X(const volatile X &);
   ~X();
 };
 
@@ -19,6 +20,9 @@
   }
 };
 
+void ConsumeX(X x);
+extern X OuterX;
+
 // CHECK-LABEL: @_Z5test0v(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5:[0-9]+]]
@@ -411,7 +415,7 @@
   try {
 may_throw();
   } catch (X x) {
-return x;
+return x; // FIXME: we should NRVO this variable.
   }
 }
 #endif
@@ -536,3 +540,1230 @@
 Y test9() {
   Y::f();
 }
+
+// CHECK-LABEL: @_Z6test10b(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
+// CHECK-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
+// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
+// CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
+// CHECK-NEXT:br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+// CHECK:   if.then:
+// CHECK-NEXT:call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
+// CHECK-NEXT:br label [[CLEANUP:%.*]]
+// CHECK:   if.else:
+// CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]]
+// CHECK-NEXT:br label [[CLEANUP]]
+// CHECK:   cleanup:
+// CHECK-NEXT:call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
+// CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
+// CHECK-NEXT:ret void
+//
+// CHECK-EH-03-LABEL: @_Z6test10b(
+// CHECK-EH-03-NEXT:  entry:
+// CHECK-EH-03-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
+// CHECK-EH-03-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
+// CHECK-EH-03-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]]
+// CHECK-EH-03-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
+// CHECK-EH-03-NEXT:br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+// CHECK-EH-03:   if.then:
+// CHECK-EH-03-NEXT:invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
+// CHECK-EH-03-NEXT:to label [[CLEANUP:%.*]] unwind label [[LPAD:%.*]]
+// CHECK-EH-03:   lpad:
+// CHECK-EH-03-NEXT:[[TMP1:%.*]] = landingpad { i8*, i32 }
+// CHECK-EH-03-NEXT:cleanup
+// CHECK-EH-03-NEXT:invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
+// CHECK-EH-03-NEXT:to label [[INVOKE_CONT2:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
+// CHECK-EH-03:   if.else:
+// CHECK-EH-03-NEXT:invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
+// CHECK-EH-03-NEXT:to label [[CLEANUP]] unwind label [[LPAD]]
+// CHECK-EH-03:   cleanup:
+// CHECK-EH-03-NEXT:call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
+// CHECK-EH-03-NEXT:call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]]

[PATCH] D119792: [Clang] [P2025] Analyze only potential scopes for NRVO

2022-02-16 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

This review will wait for D119927  to be 
merged, as it adds more tests.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119792/new/

https://reviews.llvm.org/D119792

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119651: [clang] Fix evaluation context type for consteval function calls in instantiations

2022-02-16 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

After an investigation in GDB I can say that the assert seems to be wrong. 
Since Clang instantiates classes and functions "on the fly" where appropriate, 
we indeed can get a run-time evaluation context after a compile-time evaluation 
context. I was sure that evaluation contexts were made to represent a clean 
hierarchy of context, because they're interrelated, but the case with 
instantiations confuses me.

This code ...

  template
  struct good_struct {
  // we are in run-time eval context!
  static consteval int evalconst() {
  // we are in compile-time eval context!
  return N * N;
  }
  
  void foo();
  void bar();
  };
  
  //int good_struct_100 = good_struct<100>::evalconst();
  //int good_struct_200 = good_struct<200>::evalconst();
  
  consteval int consteval_foo() {
  // we are in compile-time eval context!
  return good_struct<100>::evalconst();
  }
  
  template::evalconst()>
  constexpr int templated_foo() {
  return N;
  }

... hits the assert two times, unless we uncomment the lines with 
`good_struct_100` and `good_struct_200`. That's because Clang instantiates the 
classes when it "sees" them, straight from consteval/template contexts. I 
couldn't come up with a correct code that breaks though.

I am now less sure if the patch (without the assert) is acceptable, what if the 
concept of "evaluation contexts" needs a revision?..


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119651/new/

https://reviews.llvm.org/D119651

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119927: [Clang] [P2025] More exhaustive tests for NRVO

2022-02-16 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 409374.
Izaron added a comment.

Thanks! Yes I should've write comments that are understandable not only for me 
=)
I added comments to the existing tests as well.
Though NRVO attribute is bound to the variable, I'm also more comfortable to 
place comments in the "return" lines, as it is looks somewhat more clear.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119927/new/

https://reviews.llvm.org/D119927

Files:
  clang/test/CodeGenCXX/nrvo.cpp

Index: clang/test/CodeGenCXX/nrvo.cpp
===
--- clang/test/CodeGenCXX/nrvo.cpp
+++ clang/test/CodeGenCXX/nrvo.cpp
@@ -1,13 +1,14 @@
 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
 // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -o - %s | FileCheck %s
 // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++03 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-03 %s
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++11 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-11 %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++11 -DCXX11 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-11 %s
 
 // Test code generation for the named return value optimization.
 class X {
 public:
   X();
   X(const X&);
+  X(const volatile X &);
   ~X();
 };
 
@@ -19,6 +20,9 @@
   }
 };
 
+void ConsumeX(X x);
+extern X OuterX;
+
 // CHECK-LABEL: @_Z5test0v(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5:[0-9]+]]
@@ -32,7 +36,7 @@
 X test0() {
   X x;
 
-  return x;
+  return x; // NRVO happens
 }
 
 // CHECK-LABEL: @_Z5test1b(
@@ -48,8 +52,8 @@
 X test1(bool B) {
   X x;
   if (B)
-return (x);
-  return x;
+return (x); // NRVO happens
+  return x; // NRVO happens
 }
 
 // CHECK-LABEL: @_Z5test2b(
@@ -155,13 +159,11 @@
 // CHECK-EH-11-NEXT:resume { i8*, i32 } [[DOTPN]]
 //
 X test2(bool B) {
-  // No NRVO.
-
   X x;
   X y;
   if (B)
-return y;
-  return x;
+return y; // NRVO is impossible
+  return x;   // NRVO is impossible
 }
 
 // CHECK-LABEL: @_Z5test3b(
@@ -245,11 +247,10 @@
 X test3(bool B) {
   if (B) {
 X y;
-return y;
+return y; // NRVO happens
   }
-  // FIXME: we should NRVO this variable too.
   X x;
-  return x;
+  return x; // FIXME: NRVO could happen, but doesn't
 }
 
 extern "C" void exit(int) throw();
@@ -291,7 +292,7 @@
   {
 X x;
 if (B)
-  return x;
+  return x; // NRVO happens
   }
   exit(1);
 }
@@ -411,7 +412,7 @@
   try {
 may_throw();
   } catch (X x) {
-return x;
+return x; // FIXME: NRVO could happen, but doesn't
   }
 }
 #endif
@@ -476,7 +477,7 @@
 //
 X test6() {
   X a __attribute__((aligned(8)));
-  return a;
+  return a; // NRVO is impossible
 }
 
 // CHECK-LABEL: @_Z5test7b(
@@ -492,7 +493,7 @@
 X test7(bool b) {
   if (b) {
 X x;
-return x;
+return x; // NRVO happens
   }
   return X();
 }
@@ -510,10 +511,10 @@
 X test8(bool b) {
   if (b) {
 X x;
-return x;
+return x; // NRVO happens
   } else {
 X y;
-return y;
+return y; // NRVO happens
   }
 }
 
@@ -536,3 +537,1227 @@
 Y test9() {
   Y::f();
 }
+
+// CHECK-LABEL: @_Z6test10b(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
+// CHECK-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
+// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
+// CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
+// CHECK-NEXT:br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+// CHECK:   if.then:
+// CHECK-NEXT:call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
+// CHECK-NEXT:br label [[CLEANUP:%.*]]
+// CHECK:   if.else:
+// CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]]
+// CHECK-NEXT:br label [[CLEANUP]]
+// CHECK:   cleanup:
+// CHECK-NEXT:call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
+// CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
+// CHECK-NEXT:ret void
+//
+// CHECK-EH-03-LABEL: @_Z6test10b(
+// CHECK-EH-03-NEXT:  entry:
+// CHECK-EH-03-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
+// CHECK-EH-03-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
+// CHECK-EH-03-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]

[PATCH] D119927: [Clang] [P2025] More exhaustive tests for NRVO

2022-02-16 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 409389.
Izaron added a comment.

I placed links to corresponding p2025 examples.

Some of the examples are reasonably absent from the test, such as 1st (RVO, not 
NRVO), 13th (consteval methods are not getting to LLVM IR), 17th (there are no 
NRVOs for non-class types in Clang), etc.

The 19th example (about volatiles) is massive and has three corresponding 
functions in the test.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119927/new/

https://reviews.llvm.org/D119927

Files:
  clang/test/CodeGenCXX/nrvo.cpp

Index: clang/test/CodeGenCXX/nrvo.cpp
===
--- clang/test/CodeGenCXX/nrvo.cpp
+++ clang/test/CodeGenCXX/nrvo.cpp
@@ -1,13 +1,14 @@
 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
 // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -o - %s | FileCheck %s
 // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++03 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-03 %s
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++11 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-11 %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++11 -DCXX11 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-11 %s
 
 // Test code generation for the named return value optimization.
 class X {
 public:
   X();
   X(const X&);
+  X(const volatile X &);
   ~X();
 };
 
@@ -19,6 +20,9 @@
   }
 };
 
+void ConsumeX(X x);
+extern X OuterX;
+
 // CHECK-LABEL: @_Z5test0v(
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5:[0-9]+]]
@@ -29,10 +33,9 @@
 // CHECK-EH-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]])
 // CHECK-EH-NEXT:ret void
 //
-X test0() {
+X test0() { // http://wg21.link/p2025r2#ex-2
   X x;
-
-  return x;
+  return x; // NRVO happens
 }
 
 // CHECK-LABEL: @_Z5test1b(
@@ -48,8 +51,8 @@
 X test1(bool B) {
   X x;
   if (B)
-return (x);
-  return x;
+return (x); // NRVO happens
+  return x; // NRVO happens
 }
 
 // CHECK-LABEL: @_Z5test2b(
@@ -155,13 +158,11 @@
 // CHECK-EH-11-NEXT:resume { i8*, i32 } [[DOTPN]]
 //
 X test2(bool B) {
-  // No NRVO.
-
   X x;
   X y;
   if (B)
-return y;
-  return x;
+return y; // NRVO is impossible
+  return x;   // NRVO is impossible
 }
 
 // CHECK-LABEL: @_Z5test3b(
@@ -242,14 +243,13 @@
 // CHECK-EH-11:   return:
 // CHECK-EH-11-NEXT:ret void
 //
-X test3(bool B) {
+X test3(bool B) { // http://wg21.link/p2025r2#ex-4
   if (B) {
 X y;
-return y;
+return y; // NRVO happens
   }
-  // FIXME: we should NRVO this variable too.
   X x;
-  return x;
+  return x; // FIXME: NRVO could happen, but doesn't
 }
 
 extern "C" void exit(int) throw();
@@ -291,7 +291,7 @@
   {
 X x;
 if (B)
-  return x;
+  return x; // NRVO happens
   }
   exit(1);
 }
@@ -407,11 +407,11 @@
 // CHECK-EH-11-NEXT:call void @__clang_call_terminate(i8* [[TMP10]]) #[[ATTR8:[0-9]+]]
 // CHECK-EH-11-NEXT:unreachable
 //
-X test5() {
+X test5() { // http://wg21.link/p2025r2#ex-14
   try {
 may_throw();
   } catch (X x) {
-return x;
+return x; // FIXME: NRVO could happen, but doesn't
   }
 }
 #endif
@@ -476,7 +476,7 @@
 //
 X test6() {
   X a __attribute__((aligned(8)));
-  return a;
+  return a; // NRVO is impossible
 }
 
 // CHECK-LABEL: @_Z5test7b(
@@ -492,7 +492,7 @@
 X test7(bool b) {
   if (b) {
 X x;
-return x;
+return x; // NRVO happens
   }
   return X();
 }
@@ -510,10 +510,10 @@
 X test8(bool b) {
   if (b) {
 X x;
-return x;
+return x; // NRVO happens
   } else {
 X y;
-return y;
+return y; // NRVO happens
   }
 }
 
@@ -536,3 +536,1227 @@
 Y test9() {
   Y::f();
 }
+
+// CHECK-LABEL: @_Z6test10b(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:[[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
+// CHECK-NEXT:[[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0
+// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
+// CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
+// CHECK-NEXT:br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+// CHECK:   if.then:
+// CHECK-NEXT:call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]]
+// CHECK-NEXT:br label [[CLEANUP:%.*]]
+// CHECK:   if.else:
+// CHECK-NEXT:call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]]
+// CHECK-NEXT:br label [[CLEANUP]]
+// CHECK

[PATCH] D119927: [Clang] [P2025] More exhaustive tests for NRVO

2022-02-16 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron marked an inline comment as done.
Izaron added inline comments.



Comment at: clang/test/CodeGenCXX/nrvo.cpp:165
   if (B)
-return y;
-  return x;
+return y; // NRVO is impossible
+  return x;   // NRVO is impossible

Quuxplusone wrote:
> Technically, because `B` is a constant throughout this function, we probably 
> //could// do NRVO here by hoisting the condition as if by
> ```
> X x;
> if (B) { X y; return y; } // NRVO is possible here
> X y; return x; // NRVO is impossible
> ```
> Whether we //should// is another question. :) Also, changing `bool B` to 
> `const bool& B` would defeat my idea.
I have been thinking on "sorting" variables within the scope to get the optimal 
NRVO condition (right after seeing `test2`), but didn't come up with anything =(

I guess that it's not legal at all, because initializing constructors (unlike 
copy/move constructors) tend to have meaningful actions (starting a timer, 
etc.), and many things will break badly if we will shift the declarations as we 
want.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119927/new/

https://reviews.llvm.org/D119927

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119927: [Clang] [P2025] More exhaustive tests for NRVO

2022-02-16 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron marked an inline comment as done.
Izaron added a comment.

@Quuxplusone Thanks for reviewing the patch! We can wait some time if someone 
else wants to take a look. Though I doubt if there may be major complaints on 
extendind the tests (especially with comments and references to a proposal).

Let me copy-paste here a standard disclaimer =) Should've done it right away, 
but I forgot about it.

//P.S. If this review is eventually approved, kindly please merge the commit on 
my behalf =) As I don't have merge access. My name is `Evgeny Shulgin` and 
email is `izaronpl...@gmail.com`. Sorry for inconvenience!//


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119927/new/

https://reviews.llvm.org/D119927

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119375: [Clang][Sema] Do not evaluate value-dependent immediate invocations

2022-02-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

A friendly ping =) Seems like I don't have write access, so unfortunately I 
have to ask people to merge commits on my behalf. Let me copy-paste the usual 
comment of my reviews:

//P.S. If this review is eventually approved, kindly please merge the commit on 
my behalf =) As I don't have merge access. My name is `Evgeny Shulgin` and 
email is `izaronpl...@gmail.com`. Sorry for inconvenience!//


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119375/new/

https://reviews.llvm.org/D119375

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D119792: [Clang] [P2025] Analyze only potential scopes for NRVO

2022-07-18 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

Hi!

Unfortunately I don't have time to finish this pull request, so please feel 
free to take it and get it done =)

(You may reuse the code from this PR or write a completely new implementation)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D119792/new/

https://reviews.llvm.org/D119792

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136022: [clang] Add time profile for constant evaluation

2022-10-19 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 469096.
Izaron marked 4 inline comments as done.
Izaron added a comment.

Add time profiler test.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136022/new/

https://reviews.llvm.org/D136022

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/unittests/CMakeLists.txt
  clang/unittests/Support/CMakeLists.txt
  clang/unittests/Support/TimeProfilerTest.cpp

Index: clang/unittests/Support/TimeProfilerTest.cpp
===
--- /dev/null
+++ clang/unittests/Support/TimeProfilerTest.cpp
@@ -0,0 +1,198 @@
+//===- unittests/Support/TimeProfilerTest.cpp -===//
+//
+// 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 "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/PreprocessorOptions.h"
+
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/TimeProfiler.h"
+
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+
+// Should be called before testing.
+void setupProfiler() {
+  timeTraceProfilerInitialize(/*TimeTraceGranularity=*/0, "test");
+}
+
+// Should be called after `compileFromString()`.
+// Returns profiler's JSON dump.
+std::string teardownProfiler() {
+  SmallVector SmallVec;
+  raw_svector_ostream OS(SmallVec);
+  timeTraceProfilerWrite(OS);
+  timeTraceProfilerCleanup();
+  return OS.str().str();
+}
+
+// Returns true if code compiles successfully.
+// We only parse AST here. This is enough for constexpr evaluation.
+bool compileFromString(StringRef Code) {
+  CompilerInstance Compiler;
+  Compiler.createDiagnostics();
+
+  auto Invocation = std::make_shared();
+  Invocation->getPreprocessorOpts().addRemappedFile(
+  "test.cc", MemoryBuffer::getMemBuffer(Code).release());
+  const char *Args[] = {"-std=c++20", "test.cc"};
+  CompilerInvocation::CreateFromArgs(*Invocation, Args,
+ Compiler.getDiagnostics());
+  Compiler.setInvocation(std::move(Invocation));
+
+  class TestFrontendAction : public ASTFrontendAction {
+  private:
+std::unique_ptr CreateASTConsumer(CompilerInstance &CI,
+   StringRef InFile) override {
+  return std::make_unique();
+}
+  } Action;
+  return Compiler.ExecuteAction(Action);
+}
+
+// Returns pretty-printed trace graph.
+std::string buildTraceGraph(StringRef Json) {
+  struct EventRecord {
+int64_t TimestampBegin;
+int64_t TimestampEnd;
+StringRef Name;
+StringRef Detail;
+  };
+  std::vector Events;
+
+  // Parse `EventRecord`s from JSON dump.
+  Expected Root = json::parse(Json);
+  if (!Root)
+return "";
+  for (json::Value &TraceEventValue :
+   *Root->getAsObject()->getArray("traceEvents")) {
+json::Object *TraceEventObj = TraceEventValue.getAsObject();
+
+int64_t TimestampBegin = *TraceEventObj->getInteger("ts");
+int64_t TimestampEnd = TimestampBegin + *TraceEventObj->getInteger("dur");
+StringRef Name = *TraceEventObj->getString("name");
+StringRef Detail = "";
+if (json::Object *Args = TraceEventObj->getObject("args"))
+  Detail = Args->getString("detail").value_or("");
+
+// This is a "summary" event, like "Total PerformPendingInstantiations",
+// skip it
+if (TimestampBegin == 0)
+  continue;
+
+Events.emplace_back(
+EventRecord{TimestampBegin, TimestampEnd, Name, Detail});
+  }
+
+  // There can be nested events that are very fast, for example:
+  // {"name":"EvaluateAsBooleanCondition",... ,"ts":2380,"dur":1}
+  // {"name":"EvaluateAsRValue",... ,"ts":2380,"dur":1}
+  // Therefore we should reverse the events list, so that events that have
+  // started earlier are first in the list.
+  // Then do a stable sort, we need it for the trace graph.
+  std::reverse(Events.begin(), Events.end());
+  std::stable_sort(
+  Events.begin(), Events.end(), [](const auto &lhs, const auto &rhs) {
+return std::make_pair(lhs.TimestampBegin, lhs.TimestampEnd) <
+   std::make_pair(rhs.TimestampBegin, rhs.TimestampEnd);
+  });
+
+  std::stringstream Stream;
+  // Write a newline for better testing with multiline string literal.
+  Stream << "\n";
+
+  // Keep the current event stack.
+  std::stack EventStack;
+  for (const auto &Event : Events) {
+// Pop every event in the stack until meeting the parent event.
+while (!EventStack.empty()) {
+  bool InsideCurrentEvent =
+  Event.TimestampBegin >= EventStack.top()->TimestampBegin &&
+  Event.TimestampEnd <= EventStack.top()->TimestampEnd;
+  if (!InsideCurrentEvent)
+EventStack.pop();
+  else
+   

[PATCH] D136022: [clang] Add time profile for constant evaluation

2022-10-19 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

In D136022#3861245 , @jloser wrote:

> I'd like to see some tests through before I approve.

Thanks for the greenlight!

I added a test that compiles a chunk of code and then checks the time trace 
graph in a human-readable form.




Comment at: clang/lib/Sema/SemaDeclCXX.cpp:1740-1746
+  llvm::TimeTraceScope TimeScope("CheckConstexprFunctionDefinition", [&] {
+std::string Name;
+llvm::raw_string_ostream OS(Name);
+NewFD->getNameForDiagnostic(OS, Context.getPrintingPolicy(),
+/*Qualified=*/true);
+return Name;
+  });

aaron.ballman wrote:
> Huh, I'm a bit surprised that the checking in this function isn't dominated 
> by the time spent in `Expr::isPotentialConstantExpr()` -- if you add the time 
> tracing to all of the constant expression evaluation functions, do you still 
> need a time trace here in Sema?
Thanks! Removed trace here, added to `Expr::isPotentialConstantExpr()`. This 
method is called inside of `CheckConstexprFunctionDefinition` and really takes 
almost all the time.



Comment at: clang/lib/Sema/SemaExpr.cpp:17544
+  {
+llvm::TimeTraceScope TimeScope("EvaluateAsConstantExpr", [&] {
+  return CE->getSourceRange().printToString(SemaRef.getSourceManager());

aaron.ballman wrote:
> Why not push this down into `EvaluateAsConstantExpr()`? (Then the name you 
> give the scope will also be more accurate.)
Thanks! I wrote on this level because I didn't manage to get 
`SemaRef.getSourceManager()` without `SemaRef` (we pass down 
`SemaRef.getASTContext()`).

Anyway I found out that we can use `SemaRef.getASTContext().getSourceManager()` 
=)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136022/new/

https://reviews.llvm.org/D136022

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136022: [clang] Add time profile for constant evaluation

2022-10-19 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

The test doesn't cover exactly all new traces though. For example I couldn't 
write a code that runs into the `EvaluateAsInt` method 🤔

If you have an idea for some funky constexpr code that can be tested, please 
write here =)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136022/new/

https://reviews.llvm.org/D136022

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136022: [clang] Add time profile for constant evaluation

2022-10-19 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 469098.
Izaron added a comment.

Fix CMakeLists.txt


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136022/new/

https://reviews.llvm.org/D136022

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/unittests/CMakeLists.txt
  clang/unittests/Support/CMakeLists.txt
  clang/unittests/Support/TimeProfilerTest.cpp

Index: clang/unittests/Support/TimeProfilerTest.cpp
===
--- /dev/null
+++ clang/unittests/Support/TimeProfilerTest.cpp
@@ -0,0 +1,198 @@
+//===- unittests/Support/TimeProfilerTest.cpp -===//
+//
+// 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 "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/PreprocessorOptions.h"
+
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/TimeProfiler.h"
+
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+
+// Should be called before testing.
+void setupProfiler() {
+  timeTraceProfilerInitialize(/*TimeTraceGranularity=*/0, "test");
+}
+
+// Should be called after `compileFromString()`.
+// Returns profiler's JSON dump.
+std::string teardownProfiler() {
+  SmallVector SmallVec;
+  raw_svector_ostream OS(SmallVec);
+  timeTraceProfilerWrite(OS);
+  timeTraceProfilerCleanup();
+  return OS.str().str();
+}
+
+// Returns true if code compiles successfully.
+// We only parse AST here. This is enough for constexpr evaluation.
+bool compileFromString(StringRef Code) {
+  CompilerInstance Compiler;
+  Compiler.createDiagnostics();
+
+  auto Invocation = std::make_shared();
+  Invocation->getPreprocessorOpts().addRemappedFile(
+  "test.cc", MemoryBuffer::getMemBuffer(Code).release());
+  const char *Args[] = {"-std=c++20", "test.cc"};
+  CompilerInvocation::CreateFromArgs(*Invocation, Args,
+ Compiler.getDiagnostics());
+  Compiler.setInvocation(std::move(Invocation));
+
+  class TestFrontendAction : public ASTFrontendAction {
+  private:
+std::unique_ptr CreateASTConsumer(CompilerInstance &CI,
+   StringRef InFile) override {
+  return std::make_unique();
+}
+  } Action;
+  return Compiler.ExecuteAction(Action);
+}
+
+// Returns pretty-printed trace graph.
+std::string buildTraceGraph(StringRef Json) {
+  struct EventRecord {
+int64_t TimestampBegin;
+int64_t TimestampEnd;
+StringRef Name;
+StringRef Detail;
+  };
+  std::vector Events;
+
+  // Parse `EventRecord`s from JSON dump.
+  Expected Root = json::parse(Json);
+  if (!Root)
+return "";
+  for (json::Value &TraceEventValue :
+   *Root->getAsObject()->getArray("traceEvents")) {
+json::Object *TraceEventObj = TraceEventValue.getAsObject();
+
+int64_t TimestampBegin = *TraceEventObj->getInteger("ts");
+int64_t TimestampEnd = TimestampBegin + *TraceEventObj->getInteger("dur");
+StringRef Name = *TraceEventObj->getString("name");
+StringRef Detail = "";
+if (json::Object *Args = TraceEventObj->getObject("args"))
+  Detail = Args->getString("detail").value_or("");
+
+// This is a "summary" event, like "Total PerformPendingInstantiations",
+// skip it
+if (TimestampBegin == 0)
+  continue;
+
+Events.emplace_back(
+EventRecord{TimestampBegin, TimestampEnd, Name, Detail});
+  }
+
+  // There can be nested events that are very fast, for example:
+  // {"name":"EvaluateAsBooleanCondition",... ,"ts":2380,"dur":1}
+  // {"name":"EvaluateAsRValue",... ,"ts":2380,"dur":1}
+  // Therefore we should reverse the events list, so that events that have
+  // started earlier are first in the list.
+  // Then do a stable sort, we need it for the trace graph.
+  std::reverse(Events.begin(), Events.end());
+  std::stable_sort(
+  Events.begin(), Events.end(), [](const auto &lhs, const auto &rhs) {
+return std::make_pair(lhs.TimestampBegin, lhs.TimestampEnd) <
+   std::make_pair(rhs.TimestampBegin, rhs.TimestampEnd);
+  });
+
+  std::stringstream Stream;
+  // Write a newline for better testing with multiline string literal.
+  Stream << "\n";
+
+  // Keep the current event stack.
+  std::stack EventStack;
+  for (const auto &Event : Events) {
+// Pop every event in the stack until meeting the parent event.
+while (!EventStack.empty()) {
+  bool InsideCurrentEvent =
+  Event.TimestampBegin >= EventStack.top()->TimestampBegin &&
+  Event.TimestampEnd <= EventStack.top()->TimestampEnd;
+  if (!InsideCurrentEvent)
+EventStack.pop();
+  else
+break;
+}
+EventStack.push(&Event

[PATCH] D136022: [clang] Add time profile for constant evaluation

2022-10-20 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 469159.
Izaron added a comment.

Fix optionals with `value_or`


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136022/new/

https://reviews.llvm.org/D136022

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/unittests/CMakeLists.txt
  clang/unittests/Support/CMakeLists.txt
  clang/unittests/Support/TimeProfilerTest.cpp

Index: clang/unittests/Support/TimeProfilerTest.cpp
===
--- /dev/null
+++ clang/unittests/Support/TimeProfilerTest.cpp
@@ -0,0 +1,199 @@
+//===- unittests/Support/TimeProfilerTest.cpp -===//
+//
+// 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 "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/PreprocessorOptions.h"
+
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/TimeProfiler.h"
+
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+
+// Should be called before testing.
+void setupProfiler() {
+  timeTraceProfilerInitialize(/*TimeTraceGranularity=*/0, "test");
+}
+
+// Should be called after `compileFromString()`.
+// Returns profiler's JSON dump.
+std::string teardownProfiler() {
+  SmallVector SmallVec;
+  raw_svector_ostream OS(SmallVec);
+  timeTraceProfilerWrite(OS);
+  timeTraceProfilerCleanup();
+  return OS.str().str();
+}
+
+// Returns true if code compiles successfully.
+// We only parse AST here. This is enough for constexpr evaluation.
+bool compileFromString(StringRef Code) {
+  CompilerInstance Compiler;
+  Compiler.createDiagnostics();
+
+  auto Invocation = std::make_shared();
+  Invocation->getPreprocessorOpts().addRemappedFile(
+  "test.cc", MemoryBuffer::getMemBuffer(Code).release());
+  const char *Args[] = {"-std=c++20", "test.cc"};
+  CompilerInvocation::CreateFromArgs(*Invocation, Args,
+ Compiler.getDiagnostics());
+  Compiler.setInvocation(std::move(Invocation));
+
+  class TestFrontendAction : public ASTFrontendAction {
+  private:
+std::unique_ptr CreateASTConsumer(CompilerInstance &CI,
+   StringRef InFile) override {
+  return std::make_unique();
+}
+  } Action;
+  return Compiler.ExecuteAction(Action);
+}
+
+// Returns pretty-printed trace graph.
+std::string buildTraceGraph(StringRef Json) {
+  struct EventRecord {
+int64_t TimestampBegin;
+int64_t TimestampEnd;
+StringRef Name;
+StringRef Detail;
+  };
+  std::vector Events;
+
+  // Parse `EventRecord`s from JSON dump.
+  Expected Root = json::parse(Json);
+  if (!Root)
+return "";
+  for (json::Value &TraceEventValue :
+   *Root->getAsObject()->getArray("traceEvents")) {
+json::Object *TraceEventObj = TraceEventValue.getAsObject();
+
+int64_t TimestampBegin = TraceEventObj->getInteger("ts").value_or(0);
+int64_t TimestampEnd =
+TimestampBegin + TraceEventObj->getInteger("dur").value_or(0);
+StringRef Name = TraceEventObj->getString("name").value_or("");
+StringRef Detail = "";
+if (json::Object *Args = TraceEventObj->getObject("args"))
+  Detail = Args->getString("detail").value_or("");
+
+// This is a "summary" event, like "Total PerformPendingInstantiations",
+// skip it
+if (TimestampBegin == 0)
+  continue;
+
+Events.emplace_back(
+EventRecord{TimestampBegin, TimestampEnd, Name, Detail});
+  }
+
+  // There can be nested events that are very fast, for example:
+  // {"name":"EvaluateAsBooleanCondition",... ,"ts":2380,"dur":1}
+  // {"name":"EvaluateAsRValue",... ,"ts":2380,"dur":1}
+  // Therefore we should reverse the events list, so that events that have
+  // started earlier are first in the list.
+  // Then do a stable sort, we need it for the trace graph.
+  std::reverse(Events.begin(), Events.end());
+  std::stable_sort(
+  Events.begin(), Events.end(), [](const auto &lhs, const auto &rhs) {
+return std::make_pair(lhs.TimestampBegin, -lhs.TimestampEnd) <
+   std::make_pair(rhs.TimestampBegin, -rhs.TimestampEnd);
+  });
+
+  std::stringstream Stream;
+  // Write a newline for better testing with multiline string literal.
+  Stream << "\n";
+
+  // Keep the current event stack.
+  std::stack EventStack;
+  for (const auto &Event : Events) {
+// Pop every event in the stack until meeting the parent event.
+while (!EventStack.empty()) {
+  bool InsideCurrentEvent =
+  Event.TimestampBegin >= EventStack.top()->TimestampBegin &&
+  Event.TimestampEnd <= EventStack.top()->TimestampEnd;
+  if (!InsideCurrentEvent)
+EventStack.pop();
+ 

[PATCH] D136022: [clang] Add time profile for constant evaluation

2022-10-20 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added inline comments.



Comment at: clang/unittests/Support/TimeProfilerTest.cpp:197-198
+
+  // NOTE: If this test is failing, run this test with
+  // `llvm::errs() << TraceGraph;` and change the assert above.
+}

aaron.ballman wrote:
> This bit worries me because I suspect we'll get pretty wide variation between 
> test bots in the build lab. Do you have an idea of how likely it is that this 
> test will have different behavior depending on the machine?
I'd say, the test's outcome varies if behaviour of `CompilerInstance` varies. 
From my (imperfect) understanding of Clang/LLVM's architecture, its interface 
is pretty hermetic and we won't get inconsistent behaviour depending on the 
current machine as soon as we ran `Compiler.ExecuteAction(Action);`.
Since the code is machine-independents, I expect the same behaviour everywhere.

If we look on other tests, there are tests that seemingly take the machine's 
target triple 
https://github.com/llvm/llvm-project/blob/3fee9358baab54e4ed646a106297e7fb6f1b4cff/clang/unittests/CodeGen/TestCompiler.h#L40-L48
 to fill some info in `CompilerInstance`.

But this is not the case in our test. Seems like the AST parsing is 
machine-independent 😃 


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136022/new/

https://reviews.llvm.org/D136022

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136036: [Clang] Add __has_constexpr_builtin support

2022-10-21 Thread Evgeny Shulgin via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG5b567637e22b: [Clang] Add __has_constexpr_builtin support 
(authored by Izaron).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136036/new/

https://reviews.llvm.org/D136036

Files:
  clang/docs/LanguageExtensions.rst
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/Builtins.def
  clang/include/clang/Basic/Builtins.h
  clang/include/clang/Lex/Preprocessor.h
  clang/lib/AST/ExprConstant.cpp
  clang/lib/Lex/PPMacroExpansion.cpp
  clang/test/Preprocessor/feature_tests.cpp

Index: clang/test/Preprocessor/feature_tests.cpp
===
--- clang/test/Preprocessor/feature_tests.cpp
+++ clang/test/Preprocessor/feature_tests.cpp
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 %s -triple=i686-apple-darwin9 -verify -DVERIFY
-// expected-no-diagnostics
 
 #ifndef __has_feature
 #error Should have __has_feature
@@ -42,3 +41,29 @@
 #if __has_builtin(__builtin_insanity)
 #error Clang should not have this
 #endif
+
+// Check __has_constexpr_builtin
+#if  !__has_constexpr_builtin(__builtin_fmax) || \
+ !__has_constexpr_builtin(__builtin_fmin)
+#error Clang should have these constexpr builtins
+#endif
+
+#if  __has_constexpr_builtin(__builtin_cbrt)
+#error This builtin should not be constexpr in Clang
+#endif
+
+#if  __has_constexpr_builtin(__builtin_insanity)
+#error This is not a builtin in Clang
+#endif
+
+// expected-error@+1 {{missing '(' after '__has_constexpr_builtin'}} expected-error@+1 {{expected value}}
+#if __has_constexpr_builtin
+#endif
+
+// expected-error@+1 {{builtin feature check macro requires a parenthesized identifier}}
+#if  __has_constexpr_builtin("__builtin_fmax")
+#endif
+
+// expected-error@+1 {{too many arguments}}
+#if __has_constexpr_builtin(__builtin_fmax, __builtin_fmin)
+#endif
Index: clang/lib/Lex/PPMacroExpansion.cpp
===
--- clang/lib/Lex/PPMacroExpansion.cpp
+++ clang/lib/Lex/PPMacroExpansion.cpp
@@ -371,6 +371,8 @@
   Ident__has_feature  = RegisterBuiltinMacro(*this, "__has_feature");
   Ident__has_extension= RegisterBuiltinMacro(*this, "__has_extension");
   Ident__has_builtin  = RegisterBuiltinMacro(*this, "__has_builtin");
+  Ident__has_constexpr_builtin =
+  RegisterBuiltinMacro(*this, "__has_constexpr_builtin");
   Ident__has_attribute= RegisterBuiltinMacro(*this, "__has_attribute");
   if (!getLangOpts().CPlusPlus)
 Ident__has_c_attribute = RegisterBuiltinMacro(*this, "__has_c_attribute");
@@ -1735,6 +1737,18 @@
   .Default(false);
 }
   });
+  } else if (II == Ident__has_constexpr_builtin) {
+EvaluateFeatureLikeBuiltinMacro(
+OS, Tok, II, *this, false,
+[this](Token &Tok, bool &HasLexedNextToken) -> int {
+  IdentifierInfo *II = ExpectFeatureIdentifierInfo(
+  Tok, *this, diag::err_feature_check_malformed);
+  if (!II)
+return false;
+  unsigned BuiltinOp = II->getBuiltinID();
+  return BuiltinOp != 0 &&
+ this->getBuiltinInfo().isConstantEvaluated(BuiltinOp);
+});
   } else if (II == Ident__is_identifier) {
 EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false,
   [](Token &Tok, bool &HasLexedNextToken) -> int {
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -1954,8 +1954,8 @@
   return true;
 }
 
-/// Should this call expression be treated as a constant?
-static bool IsConstantCall(const CallExpr *E) {
+/// Should this call expression be treated as a no-op?
+static bool IsNoOpCall(const CallExpr *E) {
   unsigned Builtin = E->getBuiltinCallee();
   return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
   Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
@@ -2006,7 +2006,7 @@
   case Expr::ObjCBoxedExprClass:
 return cast(E)->isExpressibleAsConstantInitializer();
   case Expr::CallExprClass:
-return IsConstantCall(cast(E));
+return IsNoOpCall(cast(E));
   // For GCC compatibility, &&label has static storage duration.
   case Expr::AddrLabelExprClass:
 return true;
@@ -7405,6 +7405,12 @@
 
   bool ZeroInitialization(const Expr *E) { return Error(E); }
 
+  bool IsConstantEvaluatedBuiltinCall(const CallExpr *E) {
+unsigned BuiltinOp = E->getBuiltinCallee();
+return BuiltinOp != 0 &&
+   Info.Ctx.BuiltinInfo.isConstantEvaluated(BuiltinOp);
+  }
+
 public:
   ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {}
 
@@ -8317,7 +8323,12 @@
 }
 
 bool LValueExprEvaluator::VisitCallExpr(const CallExpr *E) {
+  if (!IsConstantEvaluatedBuiltinCall(E))
+return ExprEvaluatorBaseTy::VisitCallExpr(E);
+
   switch (E->getBuiltin

[PATCH] D136022: [clang] Add time profile for constant evaluation

2022-10-21 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 469771.
Izaron added a comment.

Mention this in the release notes. Thanks to Aaron for reviewing!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136022/new/

https://reviews.llvm.org/D136022

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/AST/ExprConstant.cpp
  clang/unittests/CMakeLists.txt
  clang/unittests/Support/CMakeLists.txt
  clang/unittests/Support/TimeProfilerTest.cpp

Index: clang/unittests/Support/TimeProfilerTest.cpp
===
--- /dev/null
+++ clang/unittests/Support/TimeProfilerTest.cpp
@@ -0,0 +1,199 @@
+//===- unittests/Support/TimeProfilerTest.cpp -===//
+//
+// 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 "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/PreprocessorOptions.h"
+
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/TimeProfiler.h"
+
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+
+// Should be called before testing.
+void setupProfiler() {
+  timeTraceProfilerInitialize(/*TimeTraceGranularity=*/0, "test");
+}
+
+// Should be called after `compileFromString()`.
+// Returns profiler's JSON dump.
+std::string teardownProfiler() {
+  SmallVector SmallVec;
+  raw_svector_ostream OS(SmallVec);
+  timeTraceProfilerWrite(OS);
+  timeTraceProfilerCleanup();
+  return OS.str().str();
+}
+
+// Returns true if code compiles successfully.
+// We only parse AST here. This is enough for constexpr evaluation.
+bool compileFromString(StringRef Code) {
+  CompilerInstance Compiler;
+  Compiler.createDiagnostics();
+
+  auto Invocation = std::make_shared();
+  Invocation->getPreprocessorOpts().addRemappedFile(
+  "test.cc", MemoryBuffer::getMemBuffer(Code).release());
+  const char *Args[] = {"-std=c++20", "test.cc"};
+  CompilerInvocation::CreateFromArgs(*Invocation, Args,
+ Compiler.getDiagnostics());
+  Compiler.setInvocation(std::move(Invocation));
+
+  class TestFrontendAction : public ASTFrontendAction {
+  private:
+std::unique_ptr CreateASTConsumer(CompilerInstance &CI,
+   StringRef InFile) override {
+  return std::make_unique();
+}
+  } Action;
+  return Compiler.ExecuteAction(Action);
+}
+
+// Returns pretty-printed trace graph.
+std::string buildTraceGraph(StringRef Json) {
+  struct EventRecord {
+int64_t TimestampBegin;
+int64_t TimestampEnd;
+StringRef Name;
+StringRef Detail;
+  };
+  std::vector Events;
+
+  // Parse `EventRecord`s from JSON dump.
+  Expected Root = json::parse(Json);
+  if (!Root)
+return "";
+  for (json::Value &TraceEventValue :
+   *Root->getAsObject()->getArray("traceEvents")) {
+json::Object *TraceEventObj = TraceEventValue.getAsObject();
+
+int64_t TimestampBegin = TraceEventObj->getInteger("ts").value_or(0);
+int64_t TimestampEnd =
+TimestampBegin + TraceEventObj->getInteger("dur").value_or(0);
+StringRef Name = TraceEventObj->getString("name").value_or("");
+StringRef Detail = "";
+if (json::Object *Args = TraceEventObj->getObject("args"))
+  Detail = Args->getString("detail").value_or("");
+
+// This is a "summary" event, like "Total PerformPendingInstantiations",
+// skip it
+if (TimestampBegin == 0)
+  continue;
+
+Events.emplace_back(
+EventRecord{TimestampBegin, TimestampEnd, Name, Detail});
+  }
+
+  // There can be nested events that are very fast, for example:
+  // {"name":"EvaluateAsBooleanCondition",... ,"ts":2380,"dur":1}
+  // {"name":"EvaluateAsRValue",... ,"ts":2380,"dur":1}
+  // Therefore we should reverse the events list, so that events that have
+  // started earlier are first in the list.
+  // Then do a stable sort, we need it for the trace graph.
+  std::reverse(Events.begin(), Events.end());
+  std::stable_sort(
+  Events.begin(), Events.end(), [](const auto &lhs, const auto &rhs) {
+return std::make_pair(lhs.TimestampBegin, -lhs.TimestampEnd) <
+   std::make_pair(rhs.TimestampBegin, -rhs.TimestampEnd);
+  });
+
+  std::stringstream Stream;
+  // Write a newline for better testing with multiline string literal.
+  Stream << "\n";
+
+  // Keep the current event stack.
+  std::stack EventStack;
+  for (const auto &Event : Events) {
+// Pop every event in the stack until meeting the parent event.
+while (!EventStack.empty()) {
+  bool InsideCurrentEvent =
+  Event.TimestampBegin >= EventStack.top()->TimestampBegin &&
+  Event.TimestampEnd <= EventStack.top()->TimestampEnd;

[PATCH] D136022: [clang] Add time profile for constant evaluation

2022-10-21 Thread Evgeny Shulgin via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG27d8eedd5a3c: [clang] Add time profile for constant 
evaluation (authored by Izaron).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136022/new/

https://reviews.llvm.org/D136022

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/AST/ExprConstant.cpp
  clang/unittests/CMakeLists.txt
  clang/unittests/Support/CMakeLists.txt
  clang/unittests/Support/TimeProfilerTest.cpp

Index: clang/unittests/Support/TimeProfilerTest.cpp
===
--- /dev/null
+++ clang/unittests/Support/TimeProfilerTest.cpp
@@ -0,0 +1,199 @@
+//===- unittests/Support/TimeProfilerTest.cpp -===//
+//
+// 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 "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/PreprocessorOptions.h"
+
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/TimeProfiler.h"
+
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+
+// Should be called before testing.
+void setupProfiler() {
+  timeTraceProfilerInitialize(/*TimeTraceGranularity=*/0, "test");
+}
+
+// Should be called after `compileFromString()`.
+// Returns profiler's JSON dump.
+std::string teardownProfiler() {
+  SmallVector SmallVec;
+  raw_svector_ostream OS(SmallVec);
+  timeTraceProfilerWrite(OS);
+  timeTraceProfilerCleanup();
+  return OS.str().str();
+}
+
+// Returns true if code compiles successfully.
+// We only parse AST here. This is enough for constexpr evaluation.
+bool compileFromString(StringRef Code) {
+  CompilerInstance Compiler;
+  Compiler.createDiagnostics();
+
+  auto Invocation = std::make_shared();
+  Invocation->getPreprocessorOpts().addRemappedFile(
+  "test.cc", MemoryBuffer::getMemBuffer(Code).release());
+  const char *Args[] = {"-std=c++20", "test.cc"};
+  CompilerInvocation::CreateFromArgs(*Invocation, Args,
+ Compiler.getDiagnostics());
+  Compiler.setInvocation(std::move(Invocation));
+
+  class TestFrontendAction : public ASTFrontendAction {
+  private:
+std::unique_ptr CreateASTConsumer(CompilerInstance &CI,
+   StringRef InFile) override {
+  return std::make_unique();
+}
+  } Action;
+  return Compiler.ExecuteAction(Action);
+}
+
+// Returns pretty-printed trace graph.
+std::string buildTraceGraph(StringRef Json) {
+  struct EventRecord {
+int64_t TimestampBegin;
+int64_t TimestampEnd;
+StringRef Name;
+StringRef Detail;
+  };
+  std::vector Events;
+
+  // Parse `EventRecord`s from JSON dump.
+  Expected Root = json::parse(Json);
+  if (!Root)
+return "";
+  for (json::Value &TraceEventValue :
+   *Root->getAsObject()->getArray("traceEvents")) {
+json::Object *TraceEventObj = TraceEventValue.getAsObject();
+
+int64_t TimestampBegin = TraceEventObj->getInteger("ts").value_or(0);
+int64_t TimestampEnd =
+TimestampBegin + TraceEventObj->getInteger("dur").value_or(0);
+StringRef Name = TraceEventObj->getString("name").value_or("");
+StringRef Detail = "";
+if (json::Object *Args = TraceEventObj->getObject("args"))
+  Detail = Args->getString("detail").value_or("");
+
+// This is a "summary" event, like "Total PerformPendingInstantiations",
+// skip it
+if (TimestampBegin == 0)
+  continue;
+
+Events.emplace_back(
+EventRecord{TimestampBegin, TimestampEnd, Name, Detail});
+  }
+
+  // There can be nested events that are very fast, for example:
+  // {"name":"EvaluateAsBooleanCondition",... ,"ts":2380,"dur":1}
+  // {"name":"EvaluateAsRValue",... ,"ts":2380,"dur":1}
+  // Therefore we should reverse the events list, so that events that have
+  // started earlier are first in the list.
+  // Then do a stable sort, we need it for the trace graph.
+  std::reverse(Events.begin(), Events.end());
+  std::stable_sort(
+  Events.begin(), Events.end(), [](const auto &lhs, const auto &rhs) {
+return std::make_pair(lhs.TimestampBegin, -lhs.TimestampEnd) <
+   std::make_pair(rhs.TimestampBegin, -rhs.TimestampEnd);
+  });
+
+  std::stringstream Stream;
+  // Write a newline for better testing with multiline string literal.
+  Stream << "\n";
+
+  // Keep the current event stack.
+  std::stack EventStack;
+  for (const auto &Event : Events) {
+// Pop every event in the stack until meeting the parent event.
+while (!EventStack.empty()) {
+  bool InsideCurrentEvent =
+  Event.TimestampBegin >= Ev

[PATCH] D136022: [clang] Add time profile for constant evaluation

2022-10-21 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added inline comments.



Comment at: clang/unittests/Support/TimeProfilerTest.cpp:11
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Lex/PreprocessorOptions.h"
+

thakis wrote:
> Why is this in clang/unittests/Support (a new binary to boot)? This doesn't 
> use any code form clang/lib/Support as far as I can tell.
It uses code from llvm/Support.

There are already tests with similar names: clang/unittest/CodeGen and 
llvm/unittests/CodeGen, both are pretty close in spirit.

So I decided to make clang/unittests/Support as a counterpart to 
llvm/unittests/Support. There is a time profiler test too - 
https://github.com/llvm/llvm-project/blob/main/llvm/unittests/Support/TimeProfilerTest.cpp


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136022/new/

https://reviews.llvm.org/D136022

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136022: [clang] Add time profile for constant evaluation

2022-10-22 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

In D136022#3877399 , @dyung wrote:

> Hi @Izaron, several of our internal tests that run tests using `-ftime-trace` 
> started crashing when run which I bisected back to your change. I have filed 
> issue #58551  for it, can 
> you take a look?

Hi! Thank you for filling the issue! I will fix it as soon as I can!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136022/new/

https://reviews.llvm.org/D136022

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136546: [clang][unittest] Resolve ClangSupportTest link time errors

2022-10-23 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

LGTM! I'm sorry that you had to fix CMakeLists.txt. It really "worked on my 
machine", I was running these commands:

  cmake --build build --target ClangSupportTests # build and link the binary
  ./build/tools/clang/unittests/Support/ClangSupportTests # run the binary


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136546/new/

https://reviews.llvm.org/D136546

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136546: [clang][unittest] Resolve ClangSupportTest link time errors

2022-10-23 Thread Evgeny Shulgin via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGe5032d89e44a: [clang][unittest] Resolve ClangSupportTest 
link time errors (authored by jmciver, committed by Izaron).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136546/new/

https://reviews.llvm.org/D136546

Files:
  clang/unittests/Support/CMakeLists.txt


Index: clang/unittests/Support/CMakeLists.txt
===
--- clang/unittests/Support/CMakeLists.txt
+++ clang/unittests/Support/CMakeLists.txt
@@ -8,5 +8,8 @@
 
 clang_target_link_libraries(ClangSupportTests
   PRIVATE
+  clangAST
+  clangBasic
   clangFrontend
+  clangSerialization
   )


Index: clang/unittests/Support/CMakeLists.txt
===
--- clang/unittests/Support/CMakeLists.txt
+++ clang/unittests/Support/CMakeLists.txt
@@ -8,5 +8,8 @@
 
 clang_target_link_libraries(ClangSupportTests
   PRIVATE
+  clangAST
+  clangBasic
   clangFrontend
+  clangSerialization
   )
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136549: [clang] Fix time profile in "isIntegerConstantExpr"

2022-10-23 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: dyung, aaron.ballman, jloser.
Herald added a project: All.
Izaron requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

The time profiler in `Expr::isIntegerConstantExpr` used to
call `Loc->printToString`, it was inconsistent with other time
profiles in the file and caused segfaults if `Loc` was `nullptr`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D136549

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/unittests/Support/TimeProfilerTest.cpp


Index: clang/unittests/Support/TimeProfilerTest.cpp
===
--- clang/unittests/Support/TimeProfilerTest.cpp
+++ clang/unittests/Support/TimeProfilerTest.cpp
@@ -37,14 +37,14 @@
 
 // Returns true if code compiles successfully.
 // We only parse AST here. This is enough for constexpr evaluation.
-bool compileFromString(StringRef Code) {
+bool compileFromString(StringRef Code, StringRef Standard, StringRef FileName) 
{
   CompilerInstance Compiler;
   Compiler.createDiagnostics();
 
   auto Invocation = std::make_shared();
   Invocation->getPreprocessorOpts().addRemappedFile(
-  "test.cc", MemoryBuffer::getMemBuffer(Code).release());
-  const char *Args[] = {"-std=c++20", "test.cc"};
+  FileName, MemoryBuffer::getMemBuffer(Code).release());
+  const char *Args[] = {Standard.data(), FileName.data()};
   CompilerInvocation::CreateFromArgs(*Invocation, Args,
  Compiler.getDiagnostics());
   Compiler.setInvocation(std::move(Invocation));
@@ -143,7 +143,7 @@
 
 } // namespace
 
-TEST(TimeProfilerTest, ConstantEvaluation) {
+TEST(TimeProfilerTest, ConstantEvaluationCxx20) {
   constexpr StringRef Code = R"(
 void print(double value);
 
@@ -172,7 +172,7 @@
 )";
 
   setupProfiler();
-  ASSERT_TRUE(compileFromString(Code));
+  ASSERT_TRUE(compileFromString(Code, "-std=c++20", "test.cc"));
   std::string Json = teardownProfiler();
   std::string TraceGraph = buildTraceGraph(Json);
   ASSERT_TRUE(TraceGraph == R"(
@@ -197,3 +197,25 @@
   // NOTE: If this test is failing, run this test with
   // `llvm::errs() << TraceGraph;` and change the assert above.
 }
+
+TEST(TimeProfilerTest, ConstantEvaluationC99) {
+  constexpr StringRef Code = R"(
+struct {
+  short quantval[4]; // 3rd line
+} value;
+)";
+
+  setupProfiler();
+  ASSERT_TRUE(compileFromString(Code, "-std=c99", "test.c"));
+  std::string Json = teardownProfiler();
+  std::string TraceGraph = buildTraceGraph(Json);
+  ASSERT_TRUE(TraceGraph == R"(
+Frontend
+| isIntegerConstantExpr ()
+| EvaluateKnownConstIntCheckOverflow ()
+| PerformPendingInstantiations
+)");
+
+  // NOTE: If this test is failing, run this test with
+  // `llvm::errs() << TraceGraph;` and change the assert above.
+}
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -15905,9 +15905,7 @@
   assert(!isValueDependent() &&
  "Expression evaluator can't be called on a dependent expression.");
 
-  llvm::TimeTraceScope TimeScope("isIntegerConstantExpr", [&] {
-return Loc->printToString(Ctx.getSourceManager());
-  });
+  ExprTimeTraceScope TimeScope(this, Ctx, "isIntegerConstantExpr");
 
   if (Ctx.getLangOpts().CPlusPlus11)
 return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, nullptr, Loc);


Index: clang/unittests/Support/TimeProfilerTest.cpp
===
--- clang/unittests/Support/TimeProfilerTest.cpp
+++ clang/unittests/Support/TimeProfilerTest.cpp
@@ -37,14 +37,14 @@
 
 // Returns true if code compiles successfully.
 // We only parse AST here. This is enough for constexpr evaluation.
-bool compileFromString(StringRef Code) {
+bool compileFromString(StringRef Code, StringRef Standard, StringRef FileName) {
   CompilerInstance Compiler;
   Compiler.createDiagnostics();
 
   auto Invocation = std::make_shared();
   Invocation->getPreprocessorOpts().addRemappedFile(
-  "test.cc", MemoryBuffer::getMemBuffer(Code).release());
-  const char *Args[] = {"-std=c++20", "test.cc"};
+  FileName, MemoryBuffer::getMemBuffer(Code).release());
+  const char *Args[] = {Standard.data(), FileName.data()};
   CompilerInvocation::CreateFromArgs(*Invocation, Args,
  Compiler.getDiagnostics());
   Compiler.setInvocation(std::move(Invocation));
@@ -143,7 +143,7 @@
 
 } // namespace
 
-TEST(TimeProfilerTest, ConstantEvaluation) {
+TEST(TimeProfilerTest, ConstantEvaluationCxx20) {
   constexpr StringRef Code = R"(
 void print(double value);
 
@@ -172,7 +172,7 @@
 )";
 
   setupProfiler();
-  ASSERT_TRUE(compileFromString(Code));
+  ASSERT_TRUE(compileFromString(Code, "-std=c++20", "test.cc"));
   std::string Json = teardownProfiler();
   std::string TraceGraph = buildTraceGraph(Json);
   ASSE

[PATCH] D136568: [Clang] Support constexpr builtin ilogb

2022-10-23 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: jcranmer-intel, aaron.ballman, cor3ntin, efriedma.
Herald added a subscriber: hiraditya.
Herald added a project: All.
Izaron requested review of this revision.
Herald added projects: clang, LLVM.
Herald added subscribers: llvm-commits, cfe-commits.

Support constexpr version of __builtin_ilogb and its variations.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D136568

Files:
  clang/docs/LanguageExtensions.rst
  clang/include/clang/Basic/Builtins.def
  clang/lib/AST/ExprConstant.cpp
  clang/test/Sema/constant-builtins-ilogb.cpp
  llvm/include/llvm/ADT/APFloat.h
  llvm/lib/Support/APFloat.cpp
  llvm/unittests/ADT/APFloatTest.cpp

Index: llvm/unittests/ADT/APFloatTest.cpp
===
--- llvm/unittests/ADT/APFloatTest.cpp
+++ llvm/unittests/ADT/APFloatTest.cpp
@@ -3250,46 +3250,99 @@
 }
 
 TEST(APFloatTest, ilogb) {
-  EXPECT_EQ(-1074, ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), false)));
-  EXPECT_EQ(-1074, ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), true)));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ep-1024")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ep-1023")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "-0x1.ep-1023")));
-  EXPECT_EQ(-51, ilogb(APFloat(APFloat::IEEEdouble(), "0x1p-51")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-1023")));
-  EXPECT_EQ(-2, ilogb(APFloat(APFloat::IEEEdouble(), "0x0.p-1")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.fffep-1023")));
-  EXPECT_EQ(1023, ilogb(APFloat::getLargest(APFloat::IEEEdouble(), false)));
-  EXPECT_EQ(1023, ilogb(APFloat::getLargest(APFloat::IEEEdouble(), true)));
-
-
-  EXPECT_EQ(0, ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+0")));
-  EXPECT_EQ(0, ilogb(APFloat(APFloat::IEEEsingle(), "-0x1p+0")));
-  EXPECT_EQ(42, ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+42")));
-  EXPECT_EQ(-42, ilogb(APFloat(APFloat::IEEEsingle(), "0x1p-42")));
-
-  EXPECT_EQ(APFloat::IEK_Inf,
-ilogb(APFloat::getInf(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(APFloat::IEK_Inf,
-ilogb(APFloat::getInf(APFloat::IEEEsingle(), true)));
-  EXPECT_EQ(APFloat::IEK_Zero,
-ilogb(APFloat::getZero(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(APFloat::IEK_Zero,
-ilogb(APFloat::getZero(APFloat::IEEEsingle(), true)));
-  EXPECT_EQ(APFloat::IEK_NaN,
-ilogb(APFloat::getNaN(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(APFloat::IEK_NaN,
-ilogb(APFloat::getSNaN(APFloat::IEEEsingle(), false)));
-
-  EXPECT_EQ(127, ilogb(APFloat::getLargest(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(127, ilogb(APFloat::getLargest(APFloat::IEEEsingle(), true)));
-
-  EXPECT_EQ(-149, ilogb(APFloat::getSmallest(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(-149, ilogb(APFloat::getSmallest(APFloat::IEEEsingle(), true)));
-  EXPECT_EQ(-126,
-ilogb(APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(-126,
-ilogb(APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true)));
+  int Result;
+
+  EXPECT_EQ(ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), false), Result),
+APFloat::opOK);
+  EXPECT_EQ(-1074, Result);
+  EXPECT_EQ(ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), true), Result),
+APFloat::opOK);
+  EXPECT_EQ(-1074, Result);
+  EXPECT_EQ(
+  ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ep-1024"), Result),
+  APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(
+  ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ep-1023"), Result),
+  APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(
+  ilogb(APFloat(APFloat::IEEEdouble(), "-0x1.ep-1023"), Result),
+  APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEdouble(), "0x1p-51"), Result),
+APFloat::opOK);
+  EXPECT_EQ(-51, Result);
+  EXPECT_EQ(
+  ilogb(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-1023"), Result),
+  APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEdouble(), "0x0.p-1"), Result),
+APFloat::opOK);
+  EXPECT_EQ(-2, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEdouble(), "0x1.fffep-1023"), Result),
+APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(ilogb(APFloat::getLargest(APFloat::IEEEdouble(), false), Result),
+APFloat::opOK);
+  EXPECT_EQ(1023, Result);
+  EXPECT_EQ(ilogb(APFloat::getLargest(APFloat::IEEEdouble(), true), Result),
+APFloat::opOK);
+  EXPECT_EQ(1023, Result);
+
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+0"), Result),
+APFloat::opOK);
+  EXPECT_EQ(0, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEsingle(), "-0x1p+0"), Result),
+APFloat::opOK);
+

[PATCH] D136568: [Clang] Support constexpr builtin ilogb

2022-10-23 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

This patch is similar to `__bultin_fmax`: https://reviews.llvm.org/D134369

The constexpr version of ilogb matches the libc realization, this is verified 
with the same tests:
https://github.com/llvm/llvm-project/blob/main/libc/test/src/math/ILogbTest.h

  test_special_numbers -> ILOGB_TEST_SPECIAL_NUMBERS
  test_powers_of_two -> ILOGB_TEST_POWERS_OF_TWO
  test_some_integers -> ILOGB_TEST_SOME_INTEGERS

https://eel.is/c++draft/library.c#3 says that a floating-point exception other 
than `FE_INEXACT` causes it to not be a constant expression.
I check it with small `ilog` function refactoring and the new function 
`isConstantOpStatus`.

The online documentation (https://en.cppreference.com/w/cpp/numeric/math/ilogb) 
says:

  1. If the correct result is greater than INT_MAX or smaller than INT_MIN, 
FE_INVALID is raised.
  2. If arg is ±0, ±∞, or NaN, FE_INVALID is raised.
  3. In all other cases, the result is exact (FE_INEXACT is never raised) and 
the current rounding mode is ignored

The first point seemingly never occur, because llvm's `ilogb` return type is 
`int`.
The second point is handled as expected (`APFloatTest.cpp` checks it)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136568/new/

https://reviews.llvm.org/D136568

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136549: [clang] Fix time profile in "isIntegerConstantExpr"

2022-10-23 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron marked 2 inline comments as done.
Izaron added inline comments.



Comment at: clang/lib/AST/ExprConstant.cpp:15908
 
-  llvm::TimeTraceScope TimeScope("isIntegerConstantExpr", [&] {
-return Loc->printToString(Ctx.getSourceManager());
-  });
+  ExprTimeTraceScope TimeScope(this, Ctx, "isIntegerConstantExpr");
 

jloser wrote:
> **Question** This looks like the right fix for this call site.  Are the other 
> two uses of `llvm::TimeTraceScope` as a local variable subject to similar 
> problems? I don't think so since we don't try to get the location explicitly, 
> but want to confirm.
That's a good question! We use custom `llvm::TimeTraceScope` in three places:

```
isPotentialConstantExpr
EvaluateAsInitializer
EvaluateWithSubstitution
```

The problem with `isIntegerConstantExpr` (which I fixed in this patch) was that 
the `Loc` was `nullptr` (and there were no tests that would catch it).

The three functions with custom time traces use either `const VarDecl *VD` or 
`const FunctionDecl *FD`. These variables are surely not `nullptr` because the 
methods bravely use them (`VD->doSmth()`/`FD->doSmth()`).

Also our unit test covers `isPotentialConstantExpr` and `EvaluateAsInitializer` 
(you can see them in `ASSERT_TRUE`).
So I think there is no obvious problems that I can think of =)



Comment at: clang/unittests/Support/TimeProfilerTest.cpp:209
+  setupProfiler();
+  ASSERT_TRUE(compileFromString(Code, "-std=c99", "test.c"));
+  std::string Json = teardownProfiler();

jloser wrote:
> **Question** Is adding the ability to plumb the standards mode just useful 
> for this bug fix in the sense of reducing the trace graph output of the AST?
This is useful for bug fix, because some `ExprConstant.cpp` methods are called 
only for C code (not for C++ code). C and C++ have a somewhat different 
constant evaluations.

The segfault in `Expr::isIntegerConstantExpr` was only discoverable when 
compiling C code, because there is a explicit condition for calling this method 
only for C code:
https://github.com/llvm/llvm-project/blob/08d1c43c7023a2e955c43fbf4c3f1635f91521e0/clang/lib/Sema/SemaExpr.cpp#L17318


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136549/new/

https://reviews.llvm.org/D136549

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136549: [clang] Fix time profile in "isIntegerConstantExpr"

2022-10-23 Thread Evgeny Shulgin via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG2bb50a55b0f5: [clang] Fix time profile in 
"isIntegerConstantExpr" (authored by Izaron).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136549/new/

https://reviews.llvm.org/D136549

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/unittests/Support/TimeProfilerTest.cpp


Index: clang/unittests/Support/TimeProfilerTest.cpp
===
--- clang/unittests/Support/TimeProfilerTest.cpp
+++ clang/unittests/Support/TimeProfilerTest.cpp
@@ -37,14 +37,14 @@
 
 // Returns true if code compiles successfully.
 // We only parse AST here. This is enough for constexpr evaluation.
-bool compileFromString(StringRef Code) {
+bool compileFromString(StringRef Code, StringRef Standard, StringRef FileName) 
{
   CompilerInstance Compiler;
   Compiler.createDiagnostics();
 
   auto Invocation = std::make_shared();
   Invocation->getPreprocessorOpts().addRemappedFile(
-  "test.cc", MemoryBuffer::getMemBuffer(Code).release());
-  const char *Args[] = {"-std=c++20", "test.cc"};
+  FileName, MemoryBuffer::getMemBuffer(Code).release());
+  const char *Args[] = {Standard.data(), FileName.data()};
   CompilerInvocation::CreateFromArgs(*Invocation, Args,
  Compiler.getDiagnostics());
   Compiler.setInvocation(std::move(Invocation));
@@ -143,7 +143,7 @@
 
 } // namespace
 
-TEST(TimeProfilerTest, ConstantEvaluation) {
+TEST(TimeProfilerTest, ConstantEvaluationCxx20) {
   constexpr StringRef Code = R"(
 void print(double value);
 
@@ -172,7 +172,7 @@
 )";
 
   setupProfiler();
-  ASSERT_TRUE(compileFromString(Code));
+  ASSERT_TRUE(compileFromString(Code, "-std=c++20", "test.cc"));
   std::string Json = teardownProfiler();
   std::string TraceGraph = buildTraceGraph(Json);
   ASSERT_TRUE(TraceGraph == R"(
@@ -197,3 +197,25 @@
   // NOTE: If this test is failing, run this test with
   // `llvm::errs() << TraceGraph;` and change the assert above.
 }
+
+TEST(TimeProfilerTest, ConstantEvaluationC99) {
+  constexpr StringRef Code = R"(
+struct {
+  short quantval[4]; // 3rd line
+} value;
+)";
+
+  setupProfiler();
+  ASSERT_TRUE(compileFromString(Code, "-std=c99", "test.c"));
+  std::string Json = teardownProfiler();
+  std::string TraceGraph = buildTraceGraph(Json);
+  ASSERT_TRUE(TraceGraph == R"(
+Frontend
+| isIntegerConstantExpr ()
+| EvaluateKnownConstIntCheckOverflow ()
+| PerformPendingInstantiations
+)");
+
+  // NOTE: If this test is failing, run this test with
+  // `llvm::errs() << TraceGraph;` and change the assert above.
+}
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -15905,9 +15905,7 @@
   assert(!isValueDependent() &&
  "Expression evaluator can't be called on a dependent expression.");
 
-  llvm::TimeTraceScope TimeScope("isIntegerConstantExpr", [&] {
-return Loc->printToString(Ctx.getSourceManager());
-  });
+  ExprTimeTraceScope TimeScope(this, Ctx, "isIntegerConstantExpr");
 
   if (Ctx.getLangOpts().CPlusPlus11)
 return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, nullptr, Loc);


Index: clang/unittests/Support/TimeProfilerTest.cpp
===
--- clang/unittests/Support/TimeProfilerTest.cpp
+++ clang/unittests/Support/TimeProfilerTest.cpp
@@ -37,14 +37,14 @@
 
 // Returns true if code compiles successfully.
 // We only parse AST here. This is enough for constexpr evaluation.
-bool compileFromString(StringRef Code) {
+bool compileFromString(StringRef Code, StringRef Standard, StringRef FileName) {
   CompilerInstance Compiler;
   Compiler.createDiagnostics();
 
   auto Invocation = std::make_shared();
   Invocation->getPreprocessorOpts().addRemappedFile(
-  "test.cc", MemoryBuffer::getMemBuffer(Code).release());
-  const char *Args[] = {"-std=c++20", "test.cc"};
+  FileName, MemoryBuffer::getMemBuffer(Code).release());
+  const char *Args[] = {Standard.data(), FileName.data()};
   CompilerInvocation::CreateFromArgs(*Invocation, Args,
  Compiler.getDiagnostics());
   Compiler.setInvocation(std::move(Invocation));
@@ -143,7 +143,7 @@
 
 } // namespace
 
-TEST(TimeProfilerTest, ConstantEvaluation) {
+TEST(TimeProfilerTest, ConstantEvaluationCxx20) {
   constexpr StringRef Code = R"(
 void print(double value);
 
@@ -172,7 +172,7 @@
 )";
 
   setupProfiler();
-  ASSERT_TRUE(compileFromString(Code));
+  ASSERT_TRUE(compileFromString(Code, "-std=c++20", "test.cc"));
   std::string Json = teardownProfiler();
   std::string TraceGraph = buildTraceGraph(Json);
   ASSERT_TRUE(TraceGraph == R"(
@@ -197,3 +197,25 @@
   // NOTE: If this test is failing, run this test with
   // `llvm::errs() << TraceGraph;` and change the assert above.

[PATCH] D118743: [clang-tidy] Add `modernize-use-inline-const-variables-in-headers` check

2022-10-24 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

A friendly ping 🙂


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D118743/new/

https://reviews.llvm.org/D118743

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136568: [Clang] Support constexpr builtin ilogb

2022-10-26 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added inline comments.



Comment at: clang/lib/AST/ExprConstant.cpp:12452
+int Ilogb;
+if (APFloat::opStatus St = ilogb(F, Ilogb); !isConstantOpStatus(St))
+  return false;

aaron.ballman wrote:
> jcranmer-intel wrote:
> > `long double` is `ppc_fp128` on at least some PPC targets, and while I'm 
> > not entirely certain of what `ilogb` properly returns in the corner cases 
> > of the `ppc_fp128`, I'm not entirely confident that the implementation of 
> > `APFloat` is correct in those cases. I'd like someone with PPC background 
> > to comment in here.
> Paging @hubert.reinterpretcast for help finding a good person to comment on 
> the PPC questions.
@jcranmer-intel constexpr evaluation is quite machine-/target-independent. 
Clang evaluates it based on its **internal** representation of float variables.

[[ 
https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/llvm/include/llvm/ADT/APFloat.h#L1256
 | int ilogb ]] uses `Arg.getIEEE()`, that [[ 
https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/llvm/include/llvm/ADT/APFloat.h#L819-L825
 | returns Clang's internal float representation ]].

Whichever float semantics is being used, [[ 
https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/llvm/lib/Support/APFloat.cpp#L54-L61
 | minExponent and maxExponent are representable as APFloatBase::ExponentType 
]], which is `int32_t`:
```
/// A signed type to represent a floating point numbers unbiased exponent.
typedef int32_t ExponentType;
```

We already use `int ilogb` in some constexpr evaluation code: [[ 
https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/clang/lib/AST/ExprConstant.cpp#L14592
 | link ]], it is working correct because it is working on Clang's float 
representations.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136568/new/

https://reviews.llvm.org/D136568

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136568: [Clang] Support constexpr builtin ilogb

2022-10-26 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 470962.
Izaron added a comment.

Add test for min/max value. Fix comment for ilog.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136568/new/

https://reviews.llvm.org/D136568

Files:
  clang/docs/LanguageExtensions.rst
  clang/include/clang/Basic/Builtins.def
  clang/lib/AST/ExprConstant.cpp
  clang/test/Sema/constant-builtins-ilogb.cpp
  llvm/include/llvm/ADT/APFloat.h
  llvm/lib/Support/APFloat.cpp
  llvm/unittests/ADT/APFloatTest.cpp

Index: llvm/unittests/ADT/APFloatTest.cpp
===
--- llvm/unittests/ADT/APFloatTest.cpp
+++ llvm/unittests/ADT/APFloatTest.cpp
@@ -3250,46 +3250,99 @@
 }
 
 TEST(APFloatTest, ilogb) {
-  EXPECT_EQ(-1074, ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), false)));
-  EXPECT_EQ(-1074, ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), true)));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ep-1024")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ep-1023")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "-0x1.ep-1023")));
-  EXPECT_EQ(-51, ilogb(APFloat(APFloat::IEEEdouble(), "0x1p-51")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-1023")));
-  EXPECT_EQ(-2, ilogb(APFloat(APFloat::IEEEdouble(), "0x0.p-1")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.fffep-1023")));
-  EXPECT_EQ(1023, ilogb(APFloat::getLargest(APFloat::IEEEdouble(), false)));
-  EXPECT_EQ(1023, ilogb(APFloat::getLargest(APFloat::IEEEdouble(), true)));
-
-
-  EXPECT_EQ(0, ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+0")));
-  EXPECT_EQ(0, ilogb(APFloat(APFloat::IEEEsingle(), "-0x1p+0")));
-  EXPECT_EQ(42, ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+42")));
-  EXPECT_EQ(-42, ilogb(APFloat(APFloat::IEEEsingle(), "0x1p-42")));
-
-  EXPECT_EQ(APFloat::IEK_Inf,
-ilogb(APFloat::getInf(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(APFloat::IEK_Inf,
-ilogb(APFloat::getInf(APFloat::IEEEsingle(), true)));
-  EXPECT_EQ(APFloat::IEK_Zero,
-ilogb(APFloat::getZero(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(APFloat::IEK_Zero,
-ilogb(APFloat::getZero(APFloat::IEEEsingle(), true)));
-  EXPECT_EQ(APFloat::IEK_NaN,
-ilogb(APFloat::getNaN(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(APFloat::IEK_NaN,
-ilogb(APFloat::getSNaN(APFloat::IEEEsingle(), false)));
-
-  EXPECT_EQ(127, ilogb(APFloat::getLargest(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(127, ilogb(APFloat::getLargest(APFloat::IEEEsingle(), true)));
-
-  EXPECT_EQ(-149, ilogb(APFloat::getSmallest(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(-149, ilogb(APFloat::getSmallest(APFloat::IEEEsingle(), true)));
-  EXPECT_EQ(-126,
-ilogb(APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(-126,
-ilogb(APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true)));
+  int Result;
+
+  EXPECT_EQ(ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), false), Result),
+APFloat::opOK);
+  EXPECT_EQ(-1074, Result);
+  EXPECT_EQ(ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), true), Result),
+APFloat::opOK);
+  EXPECT_EQ(-1074, Result);
+  EXPECT_EQ(
+  ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ep-1024"), Result),
+  APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(
+  ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ep-1023"), Result),
+  APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(
+  ilogb(APFloat(APFloat::IEEEdouble(), "-0x1.ep-1023"), Result),
+  APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEdouble(), "0x1p-51"), Result),
+APFloat::opOK);
+  EXPECT_EQ(-51, Result);
+  EXPECT_EQ(
+  ilogb(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-1023"), Result),
+  APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEdouble(), "0x0.p-1"), Result),
+APFloat::opOK);
+  EXPECT_EQ(-2, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEdouble(), "0x1.fffep-1023"), Result),
+APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(ilogb(APFloat::getLargest(APFloat::IEEEdouble(), false), Result),
+APFloat::opOK);
+  EXPECT_EQ(1023, Result);
+  EXPECT_EQ(ilogb(APFloat::getLargest(APFloat::IEEEdouble(), true), Result),
+APFloat::opOK);
+  EXPECT_EQ(1023, Result);
+
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+0"), Result),
+APFloat::opOK);
+  EXPECT_EQ(0, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEsingle(), "-0x1p+0"), Result),
+APFloat::opOK);
+  EXPECT_EQ(0, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+42"), Result),
+APFloat::opOK);
+  EXPECT_EQ(42, Result);
+  EXPECT_EQ(ilogb(APFloat(APFlo

[PATCH] D136568: [Clang] Support constexpr builtin ilogb

2022-10-26 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron marked 2 inline comments as done.
Izaron added inline comments.



Comment at: clang/lib/AST/ExprConstant.cpp:12452
+int Ilogb;
+if (APFloat::opStatus St = ilogb(F, Ilogb); !isConstantOpStatus(St))
+  return false;

jcranmer-intel wrote:
> Izaron wrote:
> > aaron.ballman wrote:
> > > jcranmer-intel wrote:
> > > > `long double` is `ppc_fp128` on at least some PPC targets, and while 
> > > > I'm not entirely certain of what `ilogb` properly returns in the corner 
> > > > cases of the `ppc_fp128`, I'm not entirely confident that the 
> > > > implementation of `APFloat` is correct in those cases. I'd like someone 
> > > > with PPC background to comment in here.
> > > Paging @hubert.reinterpretcast for help finding a good person to comment 
> > > on the PPC questions.
> > @jcranmer-intel constexpr evaluation is quite machine-/target-independent. 
> > Clang evaluates it based on its **internal** representation of float 
> > variables.
> > 
> > [[ 
> > https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/llvm/include/llvm/ADT/APFloat.h#L1256
> >  | int ilogb ]] uses `Arg.getIEEE()`, that [[ 
> > https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/llvm/include/llvm/ADT/APFloat.h#L819-L825
> >  | returns Clang's internal float representation ]].
> > 
> > Whichever float semantics is being used, [[ 
> > https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/llvm/lib/Support/APFloat.cpp#L54-L61
> >  | minExponent and maxExponent are representable as 
> > APFloatBase::ExponentType ]], which is `int32_t`:
> > ```
> > /// A signed type to represent a floating point numbers unbiased exponent.
> > typedef int32_t ExponentType;
> > ```
> > 
> > We already use `int ilogb` in some constexpr evaluation code: [[ 
> > https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/clang/lib/AST/ExprConstant.cpp#L14592
> >  | link ]], it is working correct because it is working on Clang's float 
> > representations.
> > We already use `int ilogb` in some constexpr evaluation code: [[ 
> > https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/clang/lib/AST/ExprConstant.cpp#L14592
> >  | link ]], it is working correct because it is working on Clang's float 
> > representations.
> 
> `APFloat::getIEEE()`, if I'm following it correctly, only returns the details 
> of the high double in `ppc_fp128` floats, and I'm not sufficiently 
> well-versed in the `ppc_fp128` format to establish whether or not the low 
> double comes into play here. glibc seems to think that the low double comes 
> into play in at least one case: 
> https://github.com/bminor/glibc/blob/30891f35fa7da832b66d80d0807610df361851f3/sysdeps/ieee754/ldbl-128ibm/e_ilogbl.c
Thanks for the link to the glibc code! It helped me to understand the IEEE754 
standard better.

I did some research and it seems like AST supports a fixed set of float types, 
each working good with `ilogb`:
```
half (__fp16, only for OpenCL), float16, float, double, long double, float128
```
[[ 
https://github.com/llvm/llvm-project/blob/7846d590033e8d661198f4c00f56f46a4993c526/clang/lib/Sema/SemaExpr.cpp#L3911-L3931
 | link to SemaExpr.cpp ]]

It means that the constant evaluator doesn't deal with other float types 
including `ppc_fp128`.
If `ppc_fp128` was supported on the AST level, it would anyway come through 
type casting, and `__builtin_ilog` would deal with a value of a known 
type.

I checked the list of builtins - each builtin argument of float type also 
supports only common float types:
[[ 
https://github.com/llvm/llvm-project/blob/7846d590033e8d661198f4c00f56f46a4993c526/clang/include/clang/Basic/Builtins.def#L27-L31
 | link to Builtins.def 1 ]]
[[ 
https://github.com/llvm/llvm-project/blob/7846d590033e8d661198f4c00f56f46a4993c526/clang/include/clang/Basic/Builtins.def#L53-L54
 | link to Builtins.def 2 ]]


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136568/new/

https://reviews.llvm.org/D136568

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D136568: [Clang] Support constexpr builtin ilogb

2022-10-27 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 471101.
Izaron added a comment.

Deal with MSVC where sizeof(long double) == sizeof(double)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136568/new/

https://reviews.llvm.org/D136568

Files:
  clang/docs/LanguageExtensions.rst
  clang/include/clang/Basic/Builtins.def
  clang/lib/AST/ExprConstant.cpp
  clang/test/Sema/constant-builtins-ilogb.cpp
  llvm/include/llvm/ADT/APFloat.h
  llvm/lib/Support/APFloat.cpp
  llvm/unittests/ADT/APFloatTest.cpp

Index: llvm/unittests/ADT/APFloatTest.cpp
===
--- llvm/unittests/ADT/APFloatTest.cpp
+++ llvm/unittests/ADT/APFloatTest.cpp
@@ -3250,46 +3250,99 @@
 }
 
 TEST(APFloatTest, ilogb) {
-  EXPECT_EQ(-1074, ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), false)));
-  EXPECT_EQ(-1074, ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), true)));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ep-1024")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ep-1023")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "-0x1.ep-1023")));
-  EXPECT_EQ(-51, ilogb(APFloat(APFloat::IEEEdouble(), "0x1p-51")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-1023")));
-  EXPECT_EQ(-2, ilogb(APFloat(APFloat::IEEEdouble(), "0x0.p-1")));
-  EXPECT_EQ(-1023, ilogb(APFloat(APFloat::IEEEdouble(), "0x1.fffep-1023")));
-  EXPECT_EQ(1023, ilogb(APFloat::getLargest(APFloat::IEEEdouble(), false)));
-  EXPECT_EQ(1023, ilogb(APFloat::getLargest(APFloat::IEEEdouble(), true)));
-
-
-  EXPECT_EQ(0, ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+0")));
-  EXPECT_EQ(0, ilogb(APFloat(APFloat::IEEEsingle(), "-0x1p+0")));
-  EXPECT_EQ(42, ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+42")));
-  EXPECT_EQ(-42, ilogb(APFloat(APFloat::IEEEsingle(), "0x1p-42")));
-
-  EXPECT_EQ(APFloat::IEK_Inf,
-ilogb(APFloat::getInf(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(APFloat::IEK_Inf,
-ilogb(APFloat::getInf(APFloat::IEEEsingle(), true)));
-  EXPECT_EQ(APFloat::IEK_Zero,
-ilogb(APFloat::getZero(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(APFloat::IEK_Zero,
-ilogb(APFloat::getZero(APFloat::IEEEsingle(), true)));
-  EXPECT_EQ(APFloat::IEK_NaN,
-ilogb(APFloat::getNaN(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(APFloat::IEK_NaN,
-ilogb(APFloat::getSNaN(APFloat::IEEEsingle(), false)));
-
-  EXPECT_EQ(127, ilogb(APFloat::getLargest(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(127, ilogb(APFloat::getLargest(APFloat::IEEEsingle(), true)));
-
-  EXPECT_EQ(-149, ilogb(APFloat::getSmallest(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(-149, ilogb(APFloat::getSmallest(APFloat::IEEEsingle(), true)));
-  EXPECT_EQ(-126,
-ilogb(APFloat::getSmallestNormalized(APFloat::IEEEsingle(), false)));
-  EXPECT_EQ(-126,
-ilogb(APFloat::getSmallestNormalized(APFloat::IEEEsingle(), true)));
+  int Result;
+
+  EXPECT_EQ(ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), false), Result),
+APFloat::opOK);
+  EXPECT_EQ(-1074, Result);
+  EXPECT_EQ(ilogb(APFloat::getSmallest(APFloat::IEEEdouble(), true), Result),
+APFloat::opOK);
+  EXPECT_EQ(-1074, Result);
+  EXPECT_EQ(
+  ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ep-1024"), Result),
+  APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(
+  ilogb(APFloat(APFloat::IEEEdouble(), "0x1.ep-1023"), Result),
+  APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(
+  ilogb(APFloat(APFloat::IEEEdouble(), "-0x1.ep-1023"), Result),
+  APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEdouble(), "0x1p-51"), Result),
+APFloat::opOK);
+  EXPECT_EQ(-51, Result);
+  EXPECT_EQ(
+  ilogb(APFloat(APFloat::IEEEdouble(), "0x1.c60f120d9f87cp-1023"), Result),
+  APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEdouble(), "0x0.p-1"), Result),
+APFloat::opOK);
+  EXPECT_EQ(-2, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEdouble(), "0x1.fffep-1023"), Result),
+APFloat::opOK);
+  EXPECT_EQ(-1023, Result);
+  EXPECT_EQ(ilogb(APFloat::getLargest(APFloat::IEEEdouble(), false), Result),
+APFloat::opOK);
+  EXPECT_EQ(1023, Result);
+  EXPECT_EQ(ilogb(APFloat::getLargest(APFloat::IEEEdouble(), true), Result),
+APFloat::opOK);
+  EXPECT_EQ(1023, Result);
+
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+0"), Result),
+APFloat::opOK);
+  EXPECT_EQ(0, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEsingle(), "-0x1p+0"), Result),
+APFloat::opOK);
+  EXPECT_EQ(0, Result);
+  EXPECT_EQ(ilogb(APFloat(APFloat::IEEEsingle(), "0x1p+42"), Result),
+APFloat::opOK);
+  EXPECT_EQ(42, Result);
+  EXPECT_EQ(ilogb(APFl

[PATCH] D136568: [Clang] Support constexpr builtin ilogb

2022-10-27 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added inline comments.



Comment at: clang/lib/AST/ExprConstant.cpp:12452
+int Ilogb;
+if (APFloat::opStatus St = ilogb(F, Ilogb); !isConstantOpStatus(St))
+  return false;

majnemer wrote:
> Izaron wrote:
> > jcranmer-intel wrote:
> > > Izaron wrote:
> > > > aaron.ballman wrote:
> > > > > jcranmer-intel wrote:
> > > > > > `long double` is `ppc_fp128` on at least some PPC targets, and 
> > > > > > while I'm not entirely certain of what `ilogb` properly returns in 
> > > > > > the corner cases of the `ppc_fp128`, I'm not entirely confident 
> > > > > > that the implementation of `APFloat` is correct in those cases. I'd 
> > > > > > like someone with PPC background to comment in here.
> > > > > Paging @hubert.reinterpretcast for help finding a good person to 
> > > > > comment on the PPC questions.
> > > > @jcranmer-intel constexpr evaluation is quite 
> > > > machine-/target-independent. Clang evaluates it based on its 
> > > > **internal** representation of float variables.
> > > > 
> > > > [[ 
> > > > https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/llvm/include/llvm/ADT/APFloat.h#L1256
> > > >  | int ilogb ]] uses `Arg.getIEEE()`, that [[ 
> > > > https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/llvm/include/llvm/ADT/APFloat.h#L819-L825
> > > >  | returns Clang's internal float representation ]].
> > > > 
> > > > Whichever float semantics is being used, [[ 
> > > > https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/llvm/lib/Support/APFloat.cpp#L54-L61
> > > >  | minExponent and maxExponent are representable as 
> > > > APFloatBase::ExponentType ]], which is `int32_t`:
> > > > ```
> > > > /// A signed type to represent a floating point numbers unbiased 
> > > > exponent.
> > > > typedef int32_t ExponentType;
> > > > ```
> > > > 
> > > > We already use `int ilogb` in some constexpr evaluation code: [[ 
> > > > https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/clang/lib/AST/ExprConstant.cpp#L14592
> > > >  | link ]], it is working correct because it is working on Clang's 
> > > > float representations.
> > > > We already use `int ilogb` in some constexpr evaluation code: [[ 
> > > > https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/clang/lib/AST/ExprConstant.cpp#L14592
> > > >  | link ]], it is working correct because it is working on Clang's 
> > > > float representations.
> > > 
> > > `APFloat::getIEEE()`, if I'm following it correctly, only returns the 
> > > details of the high double in `ppc_fp128` floats, and I'm not 
> > > sufficiently well-versed in the `ppc_fp128` format to establish whether 
> > > or not the low double comes into play here. glibc seems to think that the 
> > > low double comes into play in at least one case: 
> > > https://github.com/bminor/glibc/blob/30891f35fa7da832b66d80d0807610df361851f3/sysdeps/ieee754/ldbl-128ibm/e_ilogbl.c
> > Thanks for the link to the glibc code! It helped me to understand the 
> > IEEE754 standard better.
> > 
> > I did some research and it seems like AST supports a fixed set of float 
> > types, each working good with `ilogb`:
> > ```
> > half (__fp16, only for OpenCL), float16, float, double, long double, 
> > float128
> > ```
> > [[ 
> > https://github.com/llvm/llvm-project/blob/7846d590033e8d661198f4c00f56f46a4993c526/clang/lib/Sema/SemaExpr.cpp#L3911-L3931
> >  | link to SemaExpr.cpp ]]
> > 
> > It means that the constant evaluator doesn't deal with other float types 
> > including `ppc_fp128`.
> > If `ppc_fp128` was supported on the AST level, it would anyway come through 
> > type casting, and `__builtin_ilog` would deal with a value of a 
> > known type.
> > 
> > I checked the list of builtins - each builtin argument of float type also 
> > supports only common float types:
> > [[ 
> > https://github.com/llvm/llvm-project/blob/7846d590033e8d661198f4c00f56f46a4993c526/clang/include/clang/Basic/Builtins.def#L27-L31
> >  | link to Builtins.def 1 ]]
> > [[ 
> > https://github.com/llvm/llvm-project/blob/7846d590033e8d661198f4c00f56f46a4993c526/clang/include/clang/Basic/Builtins.def#L53-L54
> >  | link to Builtins.def 2 ]]
> Won't long double map to ppc_fp128 for some targets?
Hi! It will map, but only **after** all the constant (constexpr) calculations 
are done (that is, after the AST parsing stage) - in the Codegen stage.

The Clang's constant evaluator itself never deals with ppc_fp128 and doesn't 
care about the target.
While parsing the AST, the constant evaluator works on the same level with it, 
providing calculated values to the AST being built on-the-fly. At the moment 
AST is built, constant evaluation is over.
The evaluator is target-independent and uses the internal representation for 
`long double`, in the form of emulated **80-bit (x86) format**.

The Codegen can map the AST's `long double` to `ppc_fp128` on some targets.
I

[PATCH] D136568: [Clang] Support constexpr builtin ilogb

2022-10-27 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added inline comments.



Comment at: clang/lib/AST/ExprConstant.cpp:12452
+int Ilogb;
+if (APFloat::opStatus St = ilogb(F, Ilogb); !isConstantOpStatus(St))
+  return false;

hubert.reinterpretcast wrote:
> hubert.reinterpretcast wrote:
> > hubert.reinterpretcast wrote:
> > > Izaron wrote:
> > > > majnemer wrote:
> > > > > Izaron wrote:
> > > > > > jcranmer-intel wrote:
> > > > > > > Izaron wrote:
> > > > > > > > aaron.ballman wrote:
> > > > > > > > > jcranmer-intel wrote:
> > > > > > > > > > `long double` is `ppc_fp128` on at least some PPC targets, 
> > > > > > > > > > and while I'm not entirely certain of what `ilogb` properly 
> > > > > > > > > > returns in the corner cases of the `ppc_fp128`, I'm not 
> > > > > > > > > > entirely confident that the implementation of `APFloat` is 
> > > > > > > > > > correct in those cases. I'd like someone with PPC 
> > > > > > > > > > background to comment in here.
> > > > > > > > > Paging @hubert.reinterpretcast for help finding a good person 
> > > > > > > > > to comment on the PPC questions.
> > > > > > > > @jcranmer-intel constexpr evaluation is quite 
> > > > > > > > machine-/target-independent. Clang evaluates it based on its 
> > > > > > > > **internal** representation of float variables.
> > > > > > > > 
> > > > > > > > [[ 
> > > > > > > > https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/llvm/include/llvm/ADT/APFloat.h#L1256
> > > > > > > >  | int ilogb ]] uses `Arg.getIEEE()`, that [[ 
> > > > > > > > https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/llvm/include/llvm/ADT/APFloat.h#L819-L825
> > > > > > > >  | returns Clang's internal float representation ]].
> > > > > > > > 
> > > > > > > > Whichever float semantics is being used, [[ 
> > > > > > > > https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/llvm/lib/Support/APFloat.cpp#L54-L61
> > > > > > > >  | minExponent and maxExponent are representable as 
> > > > > > > > APFloatBase::ExponentType ]], which is `int32_t`:
> > > > > > > > ```
> > > > > > > > /// A signed type to represent a floating point numbers 
> > > > > > > > unbiased exponent.
> > > > > > > > typedef int32_t ExponentType;
> > > > > > > > ```
> > > > > > > > 
> > > > > > > > We already use `int ilogb` in some constexpr evaluation code: 
> > > > > > > > [[ 
> > > > > > > > https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/clang/lib/AST/ExprConstant.cpp#L14592
> > > > > > > >  | link ]], it is working correct because it is working on 
> > > > > > > > Clang's float representations.
> > > > > > > > We already use `int ilogb` in some constexpr evaluation code: 
> > > > > > > > [[ 
> > > > > > > > https://github.com/llvm/llvm-project/blob/2e5bf4da99a2f8d3d4bb4f1a4d1ed968a01e8f02/clang/lib/AST/ExprConstant.cpp#L14592
> > > > > > > >  | link ]], it is working correct because it is working on 
> > > > > > > > Clang's float representations.
> > > > > > > 
> > > > > > > `APFloat::getIEEE()`, if I'm following it correctly, only returns 
> > > > > > > the details of the high double in `ppc_fp128` floats, and I'm not 
> > > > > > > sufficiently well-versed in the `ppc_fp128` format to establish 
> > > > > > > whether or not the low double comes into play here. glibc seems 
> > > > > > > to think that the low double comes into play in at least one 
> > > > > > > case: 
> > > > > > > https://github.com/bminor/glibc/blob/30891f35fa7da832b66d80d0807610df361851f3/sysdeps/ieee754/ldbl-128ibm/e_ilogbl.c
> > > > > > Thanks for the link to the glibc code! It helped me to understand 
> > > > > > the IEEE754 standard better.
> > > > > > 
> > > > > > I did some research and it seems like AST supports a fixed set of 
> > > > > > float types, each working good with `ilogb`:
> > > > > > ```
> > > > > > half (__fp16, only for OpenCL), float16, float, double, long 
> > > > > > double, float128
> > > > > > ```
> > > > > > [[ 
> > > > > > https://github.com/llvm/llvm-project/blob/7846d590033e8d661198f4c00f56f46a4993c526/clang/lib/Sema/SemaExpr.cpp#L3911-L3931
> > > > > >  | link to SemaExpr.cpp ]]
> > > > > > 
> > > > > > It means that the constant evaluator doesn't deal with other float 
> > > > > > types including `ppc_fp128`.
> > > > > > If `ppc_fp128` was supported on the AST level, it would anyway come 
> > > > > > through type casting, and `__builtin_ilog` would deal with 
> > > > > > a value of a known type.
> > > > > > 
> > > > > > I checked the list of builtins - each builtin argument of float 
> > > > > > type also supports only common float types:
> > > > > > [[ 
> > > > > > https://github.com/llvm/llvm-project/blob/7846d590033e8d661198f4c00f56f46a4993c526/clang/include/clang/Basic/Builtins.def#L27-L31
> > > > > >  | link to Builtins.def 1 ]]
> > > > > > [[ 
> > > > > > https://github.com/llvm/llvm-project/blob/7846d590033e8d661198f4c00f56f46a4993c526/clang/include/clang/Basic/Built

[PATCH] D122078: [clang-tidy] Ignore concepts in `misc-redundant-expression`

2022-09-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 460976.
Izaron added a comment.

Created redundant-expression-cxx20.cpp


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122078/new/

https://reviews.llvm.org/D122078

Files:
  clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression-cxx20.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression-cxx20.cpp
@@ -0,0 +1,11 @@
+// RUN: %check_clang_tidy %s misc-redundant-expression -std=c++20 %t -- -- -fno-delayed-template-parsing
+
+namespace concepts {
+// redundant expressions inside concepts make sense, ignore them
+template 
+concept TestConcept = requires(I i) {
+  {i - i};
+  {i && i};
+  {i ? i : i};
+};
+} // namespace concepts
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -149,6 +149,12 @@
   copy assignment operators with nonstandard return types. The check is restricted to
   c++11-or-later.
 
+- Improved :doc:`misc-redundant-expression `
+  check.
+
+  The check now skips concept definitions since redundant expressions still make sense
+  inside them.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -10,6 +10,7 @@
 #include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
@@ -440,6 +441,8 @@
   return Node.isIntegerConstantExpr(Finder->getASTContext());
 }
 
+AST_MATCHER(Expr, isRequiresExpr) { return isa(Node); }
+
 AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
   return areEquivalentExpr(Node.getLHS(), Node.getRHS());
 }
@@ -858,6 +861,7 @@
 
   const auto BannedIntegerLiteral =
   integerLiteral(expandedByMacro(KnownBannedMacroNames));
+  const auto BannedAncestor = expr(isRequiresExpr());
 
   // Binary with equivalent operands, like (X != 2 && X != 2).
   Finder->addMatcher(
@@ -873,7 +877,8 @@
unless(hasType(realFloatingPointType())),
unless(hasEitherOperand(hasType(realFloatingPointType(,
unless(hasLHS(AnyLiteralExpr)),
-   unless(hasDescendant(BannedIntegerLiteral)))
+   unless(hasDescendant(BannedIntegerLiteral)),
+   unless(hasAncestor(BannedAncestor)))
.bind("binary")),
   this);
 
@@ -886,7 +891,8 @@
  unless(isInTemplateInstantiation()),
  unless(binaryOperatorIsInMacro()),
  // TODO: if the banned macros are themselves duplicated
- unless(hasDescendant(BannedIntegerLiteral)))
+ unless(hasDescendant(BannedIntegerLiteral)),
+ unless(hasAncestor(BannedAncestor)))
   .bind("nested-duplicates"),
   this);
 
@@ -896,7 +902,8 @@
conditionalOperator(expressionsAreEquivalent(),
// Filter noisy false positives.
unless(conditionalOperatorIsInMacro()),
-   unless(isInTemplateInstantiation()))
+   unless(isInTemplateInstantiation()),
+   unless(hasAncestor(BannedAncestor)))
.bind("cond")),
   this);
 
@@ -909,7 +916,8 @@
 ">=", "&&", "||", "="),
parametersAreEquivalent(),
// Filter noisy false positives.
-   unless(isMacro()), unless(isInTemplateInstantiation()))
+   unless(isMacro()), unless(isInTemplateInstantiation()),
+   unless(hasAncestor(BannedAncestor)))
.bind("call")),
   this);
 
@@ -919,7 +927,8 @@
   hasAnyOverloadedOperatorName("|", "&", "||", "&&", "^"),
   nestedParametersAreEquivalent(), argumentCountIs(2),
   // Filter noisy false positives.
-  unless(isMacro()), unless(isInTemplateInstantiation()))
+  unless(isMacro()), unless(isInTemplateInstantiation()),
+  unless(hasAncestor(BannedAncestor)))
   .bind("nested-duplicates"),
   this);
 
@@ -936,7 +945,8 @@

[PATCH] D133887: [Clang] Support label at end of compound statement

2022-09-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 460987.
Izaron added a comment.

Change C2x implementation status and C2x release notes

Add an AST test


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133887/new/

https://reviews.llvm.org/D133887

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/lib/Parse/ParseStmt.cpp
  clang/test/AST/ast-dump-stmt.c
  clang/test/Parser/cxx2b-label.cpp
  clang/test/Parser/switch-recovery.cpp
  clang/www/c_status.html
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1456,7 +1456,7 @@
 
   Labels at the end of compound statements
   https://wg21.link/P2324R2";>P2324R2
-  No
+  Clang 16
 
 
   Delimited escape sequences
Index: clang/www/c_status.html
===
--- clang/www/c_status.html
+++ clang/www/c_status.html
@@ -763,7 +763,7 @@
 
   Free positioning of labels inside compound statements
   https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2508.pdf";>N2508
-  No
+  Clang 16
 
 
   Clarification request for C17 example of undefined behavior
Index: clang/test/Parser/switch-recovery.cpp
===
--- clang/test/Parser/switch-recovery.cpp
+++ clang/test/Parser/switch-recovery.cpp
@@ -160,14 +160,14 @@
 void missing_statement_case(int x) {
   switch (x) {
 case 1:
-case 0: // expected-error {{label at end of compound statement: expected statement}}
+case 0: // expected-error {{label at end of switch compound statement: expected statement}}
   }
 }
 
 void missing_statement_default(int x) {
   switch (x) {
 case 0:
-default: // expected-error {{label at end of compound statement: expected statement}}
+default: // expected-error {{label at end of switch compound statement: expected statement}}
   }
 }
 
@@ -179,7 +179,7 @@
 void pr19022_1a(int x) {
   switch(x) {
   case 1  // expected-error{{expected ':' after 'case'}} \
-  // expected-error{{label at end of compound statement: expected statement}}
+  // expected-error{{label at end of switch compound statement: expected statement}}
   }
 }
 
Index: clang/test/Parser/cxx2b-label.cpp
===
--- /dev/null
+++ clang/test/Parser/cxx2b-label.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx2b -std=c++2b -Wpre-c++2b-compat %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx20 -std=c++20 %s
+
+void foo() {
+label1:
+int x;
+label2:
+x = 1;
+label3: label4: label5:
+} // cxx20-warning {{label at end of compound statement is a C++2b extension}} \
+ cxx2b-warning {{label at end of compound statement is incompatible with C++ standards before C++2b}}
Index: clang/test/AST/ast-dump-stmt.c
===
--- clang/test/AST/ast-dump-stmt.c
+++ clang/test/AST/ast-dump-stmt.c
@@ -161,6 +161,10 @@
   // CHECK-NEXT: ImplicitCastExpr
   // CHECK-NEXT: ImplicitCastExpr
   // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}}  'void *' lvalue Var 0x{{[^ ]*}} 'ptr' 'void *'
+
+label3:
+  // CHECK-NEXT: LabelStmt 0x{{[^ ]*}}  'label3'
+  // CHECK-NEXT: NullStmt 0x{{[^ ]*}} 
 }
 
 void TestSwitch(int i) {
Index: clang/lib/Parse/ParseStmt.cpp
===
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -679,9 +679,12 @@
 
 /// ParseLabeledStatement - We have an identifier and a ':' after it.
 ///
+///   label:
+/// identifier ':'
+/// [GNU]   identifier ':' attributes[opt]
+///
 ///   labeled-statement:
-/// identifier ':' statement
-/// [GNU]   identifier ':' attributes[opt] statement
+/// label statement
 ///
 StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
  ParsedStmtContext StmtCtx) {
@@ -725,6 +728,14 @@
 }
   }
 
+  // The label may have no statement following it
+  if (SubStmt.isUnset() && Tok.is(tok::r_brace)) {
+Diag(Tok, getLangOpts().CPlusPlus2b
+  ? diag::warn_cxx20_compat_label_end_of_compound_statement
+  : diag::ext_label_end_of_compound_statement);
+SubStmt = Actions.ActOnNullStmt(ColonLoc);
+  }
+
   // If we've not parsed a statement yet, parse one now.
   if (!SubStmt.isInvalid() && !SubStmt.isUsable())
 SubStmt = ParseStatement(nullptr, StmtCtx);
@@ -873,8 +884,8 @@
 // another parsing error, so avoid producing extra diagnostics.
 if (ColonLoc.isValid()) {
   SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
-  Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
-<< FixItHint::CreateInsert

[PATCH] D133887: [Clang] Support label at end of compound statement

2022-09-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

> It should definitely be without warning in C23 mode and give an extension 
> warning in earlier modes.

@aaron.ballman we have this extension warning for pre-C++23:

  def ext_label_end_of_compound_statement : ExtWarn<
"label at end of compound statement is a C++2b extension">,
 InGroup;

Should I add a new warning for pre-C23? We could have two warnings for each 
language:

  ext_cxx_label_end_of_compound_statement
  ext_c_label_end_of_compound_statement


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133887/new/

https://reviews.llvm.org/D133887

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D122078: [clang-tidy] Ignore concepts in `misc-redundant-expression`

2022-09-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 460990.
Izaron added a comment.

The new file was failing with message

  CHECK-FIXES, CHECK-MESSAGES or CHECK-NOTES not found in the input

So I had to add an additional urrelevant check.
I added a check for consteval function (there were no such tests previously).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122078/new/

https://reviews.llvm.org/D122078

Files:
  clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression-cxx20.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression-cxx20.cpp
@@ -0,0 +1,17 @@
+// RUN: %check_clang_tidy %s misc-redundant-expression -std=c++20 %t -- -- -fno-delayed-template-parsing
+
+consteval int TestOperatorConfusion(int X) {
+  X = (X << 8) & 0xff;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: ineffective bitwise and operation
+  return X;
+}
+
+namespace concepts {
+// redundant expressions inside concepts make sense, ignore them
+template 
+concept TestConcept = requires(I i) {
+  {i - i};
+  {i && i};
+  {i ? i : i};
+};
+} // namespace concepts
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -149,6 +149,12 @@
   copy assignment operators with nonstandard return types. The check is restricted to
   c++11-or-later.
 
+- Improved :doc:`misc-redundant-expression `
+  check.
+
+  The check now skips concept definitions since redundant expressions still make sense
+  inside them.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -10,6 +10,7 @@
 #include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
@@ -440,6 +441,8 @@
   return Node.isIntegerConstantExpr(Finder->getASTContext());
 }
 
+AST_MATCHER(Expr, isRequiresExpr) { return isa(Node); }
+
 AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
   return areEquivalentExpr(Node.getLHS(), Node.getRHS());
 }
@@ -858,6 +861,7 @@
 
   const auto BannedIntegerLiteral =
   integerLiteral(expandedByMacro(KnownBannedMacroNames));
+  const auto BannedAncestor = expr(isRequiresExpr());
 
   // Binary with equivalent operands, like (X != 2 && X != 2).
   Finder->addMatcher(
@@ -873,7 +877,8 @@
unless(hasType(realFloatingPointType())),
unless(hasEitherOperand(hasType(realFloatingPointType(,
unless(hasLHS(AnyLiteralExpr)),
-   unless(hasDescendant(BannedIntegerLiteral)))
+   unless(hasDescendant(BannedIntegerLiteral)),
+   unless(hasAncestor(BannedAncestor)))
.bind("binary")),
   this);
 
@@ -886,7 +891,8 @@
  unless(isInTemplateInstantiation()),
  unless(binaryOperatorIsInMacro()),
  // TODO: if the banned macros are themselves duplicated
- unless(hasDescendant(BannedIntegerLiteral)))
+ unless(hasDescendant(BannedIntegerLiteral)),
+ unless(hasAncestor(BannedAncestor)))
   .bind("nested-duplicates"),
   this);
 
@@ -896,7 +902,8 @@
conditionalOperator(expressionsAreEquivalent(),
// Filter noisy false positives.
unless(conditionalOperatorIsInMacro()),
-   unless(isInTemplateInstantiation()))
+   unless(isInTemplateInstantiation()),
+   unless(hasAncestor(BannedAncestor)))
.bind("cond")),
   this);
 
@@ -909,7 +916,8 @@
 ">=", "&&", "||", "="),
parametersAreEquivalent(),
// Filter noisy false positives.
-   unless(isMacro()), unless(isInTemplateInstantiation()))
+   unless(isMacro()), unless(isInTemplateInstantiation()),
+   unless(hasAncestor(BannedAncestor)))
.bind("call")),
   this);
 
@@ -919,7 +927,8 @@
   hasAnyOverloadedOperatorName("|", "&", "||", "&&", "^"),
   nestedParametersAreEquiva

[PATCH] D133887: [Clang] Support label at end of compound statement

2022-09-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 461002.
Izaron added a comment.

Add diagnostics for C language


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133887/new/

https://reviews.llvm.org/D133887

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/lib/Parse/ParseStmt.cpp
  clang/test/AST/ast-dump-stmt.c
  clang/test/Parser/c2x-label.c
  clang/test/Parser/cxx2b-label.cpp
  clang/test/Parser/switch-recovery.cpp
  clang/www/c_status.html
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1456,7 +1456,7 @@
 
   Labels at the end of compound statements
   https://wg21.link/P2324R2";>P2324R2
-  No
+  Clang 16
 
 
   Delimited escape sequences
Index: clang/www/c_status.html
===
--- clang/www/c_status.html
+++ clang/www/c_status.html
@@ -763,7 +763,7 @@
 
   Free positioning of labels inside compound statements
   https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2508.pdf";>N2508
-  No
+  Clang 16
 
 
   Clarification request for C17 example of undefined behavior
Index: clang/test/Parser/switch-recovery.cpp
===
--- clang/test/Parser/switch-recovery.cpp
+++ clang/test/Parser/switch-recovery.cpp
@@ -160,14 +160,14 @@
 void missing_statement_case(int x) {
   switch (x) {
 case 1:
-case 0: // expected-error {{label at end of compound statement: expected statement}}
+case 0: // expected-error {{label at end of switch compound statement: expected statement}}
   }
 }
 
 void missing_statement_default(int x) {
   switch (x) {
 case 0:
-default: // expected-error {{label at end of compound statement: expected statement}}
+default: // expected-error {{label at end of switch compound statement: expected statement}}
   }
 }
 
@@ -179,7 +179,7 @@
 void pr19022_1a(int x) {
   switch(x) {
   case 1  // expected-error{{expected ':' after 'case'}} \
-  // expected-error{{label at end of compound statement: expected statement}}
+  // expected-error{{label at end of switch compound statement: expected statement}}
   }
 }
 
Index: clang/test/Parser/cxx2b-label.cpp
===
--- /dev/null
+++ clang/test/Parser/cxx2b-label.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx2b -std=c++2b -Wpre-c++2b-compat %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx20 -std=c++20 %s
+
+void foo() {
+label1:
+int x;
+label2:
+x = 1;
+label3: label4: label5:
+} // cxx20-warning {{label at end of compound statement is a C++2b extension}} \
+ cxx2b-warning {{label at end of compound statement is incompatible with C++ standards before C++2b}}
Index: clang/test/Parser/c2x-label.c
===
--- /dev/null
+++ clang/test/Parser/c2x-label.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c17 -Wc2x-compat -verify=c17 %s
+// RUN: %clang_cc1 -fsyntax-only -std=c2x -Wpre-c2x-compat -verify=c2x %s
+
+// c2x-no-diagnostics
+
+void foo() {
+int x;
+label1:
+x = 1;
+label2: label3: label4:
+} // c17-warning {{label at end of compound statement is a C2x extension}}
Index: clang/test/AST/ast-dump-stmt.c
===
--- clang/test/AST/ast-dump-stmt.c
+++ clang/test/AST/ast-dump-stmt.c
@@ -161,6 +161,10 @@
   // CHECK-NEXT: ImplicitCastExpr
   // CHECK-NEXT: ImplicitCastExpr
   // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}}  'void *' lvalue Var 0x{{[^ ]*}} 'ptr' 'void *'
+
+label3:
+  // CHECK-NEXT: LabelStmt 0x{{[^ ]*}}  'label3'
+  // CHECK-NEXT: NullStmt 0x{{[^ ]*}} 
 }
 
 void TestSwitch(int i) {
Index: clang/lib/Parse/ParseStmt.cpp
===
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -679,9 +679,12 @@
 
 /// ParseLabeledStatement - We have an identifier and a ':' after it.
 ///
+///   label:
+/// identifier ':'
+/// [GNU]   identifier ':' attributes[opt]
+///
 ///   labeled-statement:
-/// identifier ':' statement
-/// [GNU]   identifier ':' attributes[opt] statement
+/// label statement
 ///
 StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
  ParsedStmtContext StmtCtx) {
@@ -725,6 +728,18 @@
 }
   }
 
+  // The label may have no statement following it
+  if (SubStmt.isUnset() && Tok.is(tok::r_brace)) {
+if (getLangOpts().CPlusPlus) {
+  Diag(Tok, getLangOpts().CPlusPlus2b
+? diag::warn_cxx20_compat_label_end_of_compound_statement
+: diag::ext_cxx_label_end_of_comp

[PATCH] D122078: [clang-tidy] Ignore concepts in `misc-redundant-expression`

2022-09-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 461003.
Izaron added a comment.

Fix test with `count 0`, thanks to @njames93 !


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122078/new/

https://reviews.llvm.org/D122078

Files:
  clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression-cxx20.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression-cxx20.cpp
===
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/misc/redundant-expression-cxx20.cpp
@@ -0,0 +1,14 @@
+// RUN: clang-tidy %s -checks=-*,misc-redundant-expression -- -std=c++20 | count 0
+
+// Note: this test expects no diagnostics, but FileCheck cannot handle that,
+// hence the use of | count 0.
+
+namespace concepts {
+// redundant expressions inside concepts make sense, ignore them
+template 
+concept TestConcept = requires(I i) {
+  {i - i};
+  {i && i};
+  {i ? i : i};
+};
+} // namespace concepts
Index: clang-tools-extra/docs/ReleaseNotes.rst
===
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -149,6 +149,12 @@
   copy assignment operators with nonstandard return types. The check is restricted to
   c++11-or-later.
 
+- Improved :doc:`misc-redundant-expression `
+  check.
+
+  The check now skips concept definitions since redundant expressions still make sense
+  inside them.
+
 Removed checks
 ^^
 
Index: clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
===
--- clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
+++ clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -10,6 +10,7 @@
 #include "../utils/Matchers.h"
 #include "../utils/OptionsUtils.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
@@ -440,6 +441,8 @@
   return Node.isIntegerConstantExpr(Finder->getASTContext());
 }
 
+AST_MATCHER(Expr, isRequiresExpr) { return isa(Node); }
+
 AST_MATCHER(BinaryOperator, operandsAreEquivalent) {
   return areEquivalentExpr(Node.getLHS(), Node.getRHS());
 }
@@ -858,6 +861,7 @@
 
   const auto BannedIntegerLiteral =
   integerLiteral(expandedByMacro(KnownBannedMacroNames));
+  const auto BannedAncestor = expr(isRequiresExpr());
 
   // Binary with equivalent operands, like (X != 2 && X != 2).
   Finder->addMatcher(
@@ -873,7 +877,8 @@
unless(hasType(realFloatingPointType())),
unless(hasEitherOperand(hasType(realFloatingPointType(,
unless(hasLHS(AnyLiteralExpr)),
-   unless(hasDescendant(BannedIntegerLiteral)))
+   unless(hasDescendant(BannedIntegerLiteral)),
+   unless(hasAncestor(BannedAncestor)))
.bind("binary")),
   this);
 
@@ -886,7 +891,8 @@
  unless(isInTemplateInstantiation()),
  unless(binaryOperatorIsInMacro()),
  // TODO: if the banned macros are themselves duplicated
- unless(hasDescendant(BannedIntegerLiteral)))
+ unless(hasDescendant(BannedIntegerLiteral)),
+ unless(hasAncestor(BannedAncestor)))
   .bind("nested-duplicates"),
   this);
 
@@ -896,7 +902,8 @@
conditionalOperator(expressionsAreEquivalent(),
// Filter noisy false positives.
unless(conditionalOperatorIsInMacro()),
-   unless(isInTemplateInstantiation()))
+   unless(isInTemplateInstantiation()),
+   unless(hasAncestor(BannedAncestor)))
.bind("cond")),
   this);
 
@@ -909,7 +916,8 @@
 ">=", "&&", "||", "="),
parametersAreEquivalent(),
// Filter noisy false positives.
-   unless(isMacro()), unless(isInTemplateInstantiation()))
+   unless(isMacro()), unless(isInTemplateInstantiation()),
+   unless(hasAncestor(BannedAncestor)))
.bind("call")),
   this);
 
@@ -919,7 +927,8 @@
   hasAnyOverloadedOperatorName("|", "&", "||", "&&", "^"),
   nestedParametersAreEquivalent(), argumentCountIs(2),
   // Filter noisy false positives.
-  unless(isMacro()), unless(isInTemplateInstantiation()))
+  unless(isMacro()), unless(isInTemplateInstantiation()),
+  unless(hasAncestor(BannedAncestor)))
   .b

[PATCH] D133887: [Clang] Support label at end of compound statement

2022-09-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

> Why checking getLangOpts().C99 instead of just C

There is no `getLangOpts().C`. Here are possible C/C++ opt flags:
https://github.com/llvm/llvm-project/blob/7914e53e312074828293356f569d190ac6eae3bd/clang/include/clang/Basic/LangOptions.def#L86-L100
I have no understanding why there is no `getLangOpts().C` flag. Maybe the C89 
standard is a subset of all other C/C++/ObjC standards, so we don't need the 
flag?..

> Whyt no compatibility warning in C23 mode

@aaron.ballman said so in https://reviews.llvm.org/D133887#3793027

  It should definitely be without warning in C23 mode and give an extension 
warning in earlier modes.

I don't know much about extension/incompatible warnings policy (when to apply 
and not apply them), could you please help me to figure this out with Aaron? 😃


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133887/new/

https://reviews.llvm.org/D133887

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D133887: [Clang] Support label at end of compound statement

2022-09-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron updated this revision to Diff 461006.
Izaron added a comment.

Fix diagnostics for C. Thanks to @cor3ntin and @aaron.ballman!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133887/new/

https://reviews.llvm.org/D133887

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/lib/Parse/ParseStmt.cpp
  clang/test/AST/ast-dump-stmt.c
  clang/test/Parser/c2x-label.c
  clang/test/Parser/cxx2b-label.cpp
  clang/test/Parser/switch-recovery.cpp
  clang/www/c_status.html
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1456,7 +1456,7 @@
 
   Labels at the end of compound statements
   https://wg21.link/P2324R2";>P2324R2
-  No
+  Clang 16
 
 
   Delimited escape sequences
Index: clang/www/c_status.html
===
--- clang/www/c_status.html
+++ clang/www/c_status.html
@@ -763,7 +763,7 @@
 
   Free positioning of labels inside compound statements
   https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2508.pdf";>N2508
-  No
+  Clang 16
 
 
   Clarification request for C17 example of undefined behavior
Index: clang/test/Parser/switch-recovery.cpp
===
--- clang/test/Parser/switch-recovery.cpp
+++ clang/test/Parser/switch-recovery.cpp
@@ -160,14 +160,14 @@
 void missing_statement_case(int x) {
   switch (x) {
 case 1:
-case 0: // expected-error {{label at end of compound statement: expected statement}}
+case 0: // expected-error {{label at end of switch compound statement: expected statement}}
   }
 }
 
 void missing_statement_default(int x) {
   switch (x) {
 case 0:
-default: // expected-error {{label at end of compound statement: expected statement}}
+default: // expected-error {{label at end of switch compound statement: expected statement}}
   }
 }
 
@@ -179,7 +179,7 @@
 void pr19022_1a(int x) {
   switch(x) {
   case 1  // expected-error{{expected ':' after 'case'}} \
-  // expected-error{{label at end of compound statement: expected statement}}
+  // expected-error{{label at end of switch compound statement: expected statement}}
   }
 }
 
Index: clang/test/Parser/cxx2b-label.cpp
===
--- /dev/null
+++ clang/test/Parser/cxx2b-label.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx2b -std=c++2b -Wpre-c++2b-compat %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx20 -std=c++20 %s
+
+void foo() {
+label1:
+int x;
+label2:
+x = 1;
+label3: label4: label5:
+} // cxx20-warning {{label at end of compound statement is a C++2b extension}} \
+ cxx2b-warning {{label at end of compound statement is incompatible with C++ standards before C++2b}}
Index: clang/test/Parser/c2x-label.c
===
--- /dev/null
+++ clang/test/Parser/c2x-label.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c17 -Wc2x-compat -verify=c17 %s
+// RUN: %clang_cc1 -fsyntax-only -std=c2x -Wpre-c2x-compat -verify=c2x %s
+
+void foo() {
+int x;
+label1:
+x = 1;
+label2: label3: label4:
+} // c17-warning {{label at end of compound statement is a C2x extension}} \
+ c2x-warning {{label at end of compound statement is incompatible with C standards before C2x}}
Index: clang/test/AST/ast-dump-stmt.c
===
--- clang/test/AST/ast-dump-stmt.c
+++ clang/test/AST/ast-dump-stmt.c
@@ -161,6 +161,10 @@
   // CHECK-NEXT: ImplicitCastExpr
   // CHECK-NEXT: ImplicitCastExpr
   // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}}  'void *' lvalue Var 0x{{[^ ]*}} 'ptr' 'void *'
+
+label3:
+  // CHECK-NEXT: LabelStmt 0x{{[^ ]*}}  'label3'
+  // CHECK-NEXT: NullStmt 0x{{[^ ]*}} 
 }
 
 void TestSwitch(int i) {
Index: clang/lib/Parse/ParseStmt.cpp
===
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -679,9 +679,12 @@
 
 /// ParseLabeledStatement - We have an identifier and a ':' after it.
 ///
+///   label:
+/// identifier ':'
+/// [GNU]   identifier ':' attributes[opt]
+///
 ///   labeled-statement:
-/// identifier ':' statement
-/// [GNU]   identifier ':' attributes[opt] statement
+/// label statement
 ///
 StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
  ParsedStmtContext StmtCtx) {
@@ -725,6 +728,20 @@
 }
   }
 
+  // The label may have no statement following it
+  if (SubStmt.isUnset() && Tok.is(tok::r_brace)) {
+if (getLangOpts().CPlusPlus) {
+  Diag(Tok, getLangOpts().CPlusPlus2b
+? 

[PATCH] D133887: [Clang] Support label at end of compound statement

2022-09-17 Thread Evgeny Shulgin via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG510383626fe1: [Clang] Support label at end of compound 
statement (authored by Izaron).

Changed prior to commit:
  https://reviews.llvm.org/D133887?vs=461006&id=461008#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D133887/new/

https://reviews.llvm.org/D133887

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/lib/Parse/ParseStmt.cpp
  clang/test/AST/ast-dump-stmt.c
  clang/test/Parser/c2x-label.c
  clang/test/Parser/cxx2b-label.cpp
  clang/test/Parser/switch-recovery.cpp
  clang/www/c_status.html
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1456,7 +1456,7 @@
 
   Labels at the end of compound statements
   https://wg21.link/P2324R2";>P2324R2
-  No
+  Clang 16
 
 
   Delimited escape sequences
Index: clang/www/c_status.html
===
--- clang/www/c_status.html
+++ clang/www/c_status.html
@@ -763,7 +763,7 @@
 
   Free positioning of labels inside compound statements
   https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2508.pdf";>N2508
-  No
+  Clang 16
 
 
   Clarification request for C17 example of undefined behavior
Index: clang/test/Parser/switch-recovery.cpp
===
--- clang/test/Parser/switch-recovery.cpp
+++ clang/test/Parser/switch-recovery.cpp
@@ -160,14 +160,14 @@
 void missing_statement_case(int x) {
   switch (x) {
 case 1:
-case 0: // expected-error {{label at end of compound statement: expected statement}}
+case 0: // expected-error {{label at end of switch compound statement: expected statement}}
   }
 }
 
 void missing_statement_default(int x) {
   switch (x) {
 case 0:
-default: // expected-error {{label at end of compound statement: expected statement}}
+default: // expected-error {{label at end of switch compound statement: expected statement}}
   }
 }
 
@@ -179,7 +179,7 @@
 void pr19022_1a(int x) {
   switch(x) {
   case 1  // expected-error{{expected ':' after 'case'}} \
-  // expected-error{{label at end of compound statement: expected statement}}
+  // expected-error{{label at end of switch compound statement: expected statement}}
   }
 }
 
Index: clang/test/Parser/cxx2b-label.cpp
===
--- /dev/null
+++ clang/test/Parser/cxx2b-label.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx2b -std=c++2b -Wpre-c++2b-compat %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx20 -std=c++20 %s
+
+void foo() {
+label1:
+int x;
+label2:
+x = 1;
+label3: label4: label5:
+} // cxx20-warning {{label at end of compound statement is a C++2b extension}} \
+ cxx2b-warning {{label at end of compound statement is incompatible with C++ standards before C++2b}}
Index: clang/test/Parser/c2x-label.c
===
--- /dev/null
+++ clang/test/Parser/c2x-label.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c17 -Wc2x-compat -verify=c17 %s
+// RUN: %clang_cc1 -fsyntax-only -std=c2x -Wpre-c2x-compat -verify=c2x %s
+
+void foo() {
+int x;
+label1:
+x = 1;
+label2: label3: label4:
+} // c17-warning {{label at end of compound statement is a C2x extension}} \
+ c2x-warning {{label at end of compound statement is incompatible with C standards before C2x}}
Index: clang/test/AST/ast-dump-stmt.c
===
--- clang/test/AST/ast-dump-stmt.c
+++ clang/test/AST/ast-dump-stmt.c
@@ -161,6 +161,10 @@
   // CHECK-NEXT: ImplicitCastExpr
   // CHECK-NEXT: ImplicitCastExpr
   // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}}  'void *' lvalue Var 0x{{[^ ]*}} 'ptr' 'void *'
+
+label3:
+  // CHECK-NEXT: LabelStmt 0x{{[^ ]*}}  'label3'
+  // CHECK-NEXT: NullStmt 0x{{[^ ]*}} 
 }
 
 void TestSwitch(int i) {
Index: clang/lib/Parse/ParseStmt.cpp
===
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -679,9 +679,12 @@
 
 /// ParseLabeledStatement - We have an identifier and a ':' after it.
 ///
+///   label:
+/// identifier ':'
+/// [GNU]   identifier ':' attributes[opt]
+///
 ///   labeled-statement:
-/// identifier ':' statement
-/// [GNU]   identifier ':' attributes[opt] statement
+/// label statement
 ///
 StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
  ParsedStmtContext StmtCtx) {
@@ -725,6 +728,20 @@
 }
   }
 
+  // The label m

[PATCH] D134136: [Clang] Support constexpr for builtin fmax, fmin, ilogb, logb, scalbn

2022-09-18 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron created this revision.
Izaron added reviewers: cor3ntin, aaron.ballman.
Herald added a subscriber: hiraditya.
Herald added a project: All.
Izaron requested review of this revision.
Herald added projects: clang, LLVM.
Herald added subscribers: llvm-commits, cfe-commits.

Support constexpr versions of __builtin_fmax, __builtin_fmin,
__builtin_ilogb, __builtin_logb, __builtin_scalbn and their
variations.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D134136

Files:
  clang/docs/LanguageExtensions.rst
  clang/lib/AST/ExprConstant.cpp
  clang/test/Sema/constant-builtins-math.cpp
  llvm/include/llvm/ADT/APFloat.h
  llvm/lib/Support/APFloat.cpp

Index: llvm/lib/Support/APFloat.cpp
===
--- llvm/lib/Support/APFloat.cpp
+++ llvm/lib/Support/APFloat.cpp
@@ -4198,6 +4198,19 @@
   return Normalized.exponent - SignificandBits;
 }
 
+IEEEFloat logb(const IEEEFloat &Arg) {
+  IEEEFloat Result(Arg.getSemantics());
+  if (Arg.isNaN())
+Result.makeNaN();
+  else if (Arg.isZero())
+Result.makeInf(/* Negative = */ true);
+  else if (Arg.isInfinity())
+Result.makeInf(/* Negative = */ false);
+  else
+Result = IEEEFloat(static_cast(ilogb(Arg)));
+  return Result;
+}
+
 IEEEFloat scalbn(IEEEFloat X, int Exp, IEEEFloat::roundingMode RoundingMode) {
   auto MaxExp = X.getSemantics().maxExponent;
   auto MinExp = X.getSemantics().minExponent;
Index: llvm/include/llvm/ADT/APFloat.h
===
--- llvm/include/llvm/ADT/APFloat.h
+++ llvm/include/llvm/ADT/APFloat.h
@@ -592,6 +592,7 @@
 
 hash_code hash_value(const IEEEFloat &Arg);
 int ilogb(const IEEEFloat &Arg);
+IEEEFloat logb(const IEEEFloat &Arg);
 IEEEFloat scalbn(IEEEFloat X, int Exp, IEEEFloat::roundingMode);
 IEEEFloat frexp(const IEEEFloat &Val, int &Exp, IEEEFloat::roundingMode RM);
 
@@ -1248,6 +1249,9 @@
 
   friend hash_code hash_value(const APFloat &Arg);
   friend int ilogb(const APFloat &Arg) { return ilogb(Arg.getIEEE()); }
+  friend APFloat logb(const APFloat &Arg) {
+return APFloat(logb(Arg.getIEEE()), Arg.getSemantics());
+  }
   friend APFloat scalbn(APFloat X, int Exp, roundingMode RM);
   friend APFloat frexp(const APFloat &X, int &Exp, roundingMode RM);
   friend IEEEFloat;
Index: clang/test/Sema/constant-builtins-math.cpp
===
--- /dev/null
+++ clang/test/Sema/constant-builtins-math.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+static_assert(__builtin_fmax(12.34, 56.78) == 56.78);
+static_assert(__builtin_fmaxf(12.34f, 56.78f) == 56.78f);
+static_assert(__builtin_fmaxl(12.34, 56.78) == 56.78);
+static_assert(__builtin_fmaxf16(12.0, 56.0) == 56.0);
+static_assert(__builtin_fmaxf128(12.34, 56.78) == 56.78);
+
+static_assert(__builtin_fmin(12.34, 56.78) == 12.34);
+static_assert(__builtin_fminf(12.34f, 56.78f) == 12.34f);
+static_assert(__builtin_fminl(12.34, 56.78) == 12.34);
+static_assert(__builtin_fminf16(12.0, 56.0) == 12.0);
+static_assert(__builtin_fminf128(12.34, 56.78) == 12.34);
+
+// TODO: investigate why this is `INT_MIN + 1` instead of `INT_MIN`
+static_assert(__builtin_ilogb(0.0) == -2147483647);
+static_assert(__builtin_ilogb(__builtin_inf()) == 2147483647);
+static_assert(__builtin_ilogb(__builtin_nan("")) == -2147483648);
+static_assert(__builtin_ilogb(1.0) == 0);
+static_assert(__builtin_ilogb(32.0) == 5);
+static_assert(__builtin_ilogb(1024.0) == 10);
+static_assert(__builtin_ilogb(-1024.0) == 10);
+static_assert(__builtin_ilogb(0.1) == -4);
+static_assert(__builtin_ilogb(0.1) == -44);
+
+static_assert(__builtin_logb(0.0) == -__builtin_inf());
+static_assert(__builtin_logb(__builtin_inf()) == __builtin_inf());
+static_assert(__builtin_isnan(__builtin_logb(__builtin_nan("";
+static_assert(__builtin_logb(1.0) == 0.0);
+static_assert(__builtin_logb(32.0) == 5.0);
+static_assert(__builtin_logb(1024.0) == 10.0);
+static_assert(__builtin_logb(-1024.0) == 10.0);
+static_assert(__builtin_logb(0.1) == -4.0);
+static_assert(__builtin_logb(0.1) == -44.0);
+
+static_assert(__builtin_scalbn(12.5, 0) == 12.5);
+static_assert(__builtin_scalbn(12.5, 1) == 25);
+static_assert(__builtin_scalbn(12.5, 3) == 100.0);
+static_assert(__builtin_scalbn(0.0, 100) == 0);
+static_assert(__builtin_scalbn(__builtin_inf(), 100) == __builtin_inf());
+static_assert(__builtin_isnan(__builtin_scalbn(__builtin_nan(""), 100)));
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -12410,6 +12410,19 @@
   return false;
 return Success(DidOverflow, E);
   }
+
+  case Builtin::BI__builtin_ilogb:
+  case Builtin::BI__builtin_ilogbf:
+  case Builtin::BI__builtin_ilogbl:
+  case Builtin::BI__builtin_ilogbf128: {
+APFloat F(0.0);
+if (!EvaluateF

[PATCH] D134136: [Clang] Support constexpr for builtin fmax, fmin, ilogb, logb, scalbn

2022-09-18 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added a comment.

libc++ doesn't support constexpr-related patches from C++20 in ``: see 
issue https://github.com/llvm/llvm-project/issues/55370

I reviewed the code in `` and found out that since we use a dozen of 
math functions, we need to support more constexpr builtin math function.

I implemented constexpr versions for five functions. This will be enough to 
implement a 2017 paper: 
https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0415r1.html (in a new 
pull request)

(Also there is a 2019 paper with more constexpr functions for ``: 
https://www.open-std.org/JTC1/SC22/WG21/docs/papers/2019/p1383r0.pdf)

Also builtin implementations will be useful for new C++23 constexpr functions: 
for example https://en.cppreference.com/w/cpp/numeric/math/scalbn


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D134136/new/

https://reviews.llvm.org/D134136

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D134136: [Clang] Support constexpr for builtin fmax, fmin, ilogb, logb, scalbn

2022-09-18 Thread Evgeny Shulgin via Phabricator via cfe-commits
Izaron added inline comments.



Comment at: clang/test/Sema/constant-builtins-math.cpp:16-17
+
+// TODO: investigate why this is `INT_MIN + 1` instead of `INT_MIN`
+static_assert(__builtin_ilogb(0.0) == -2147483647);
+static_assert(__builtin_ilogb(__builtin_inf()) == 2147483647);

runtime version of `__builtin_ilogb/std::ilogb` returns `INT_MIN` 
(`-2147483647`) on this argument, while constexpr version returns `INT_MIN+1` 🤔 

This constant is here:
https://llvm.org/doxygen/APFloat_8cpp_source.html#l04187
https://llvm.org/doxygen/APFloat_8h_source.html#l00229
(I guess we shouldn't change this)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D134136/new/

https://reviews.llvm.org/D134136

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   >