[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-12 Thread Clement Courbet via Phabricator via cfe-commits
courbet added a comment.

I agree. I'll have a look at it.


Repository:
  rL LLVM

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

https://reviews.llvm.org/D55270



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


[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-11 Thread Arthur O'Dwyer via Phabricator via cfe-commits
Quuxplusone added a comment.

@courbet: On the cpplang Slack, Peter Feichtinger mentioned that defaulted 
template arguments should perhaps be treated differently. Is there any way to 
suppress the `, std::allocator` part of this diagnostic? 
https://godbolt.org/z/TM0UHc

Before your patches:

  :11:5: error: static_assert failed due to requirement 
'std::is_integral_v'
  static_assert(std::is_integral_v);
  ^ ~

After your patches:

  :11:5: error: static_assert failed due to requirement 
'std::is_integral_v > >'
  static_assert(std::is_integral_v);
  ^ ~ 

I don't think the new behavior is //worse//; but I don't think it's optimal, 
either.

I think Clang already has a feature to suppress printing these parameters; you 
would just have to figure out where it is and try to hook it into your thing. 
(And if you do, I'm going to ask for a test case where `T::t` is 
`std::pmr::vector`!)


Repository:
  rL LLVM

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

https://reviews.llvm.org/D55270



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


[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-10 Thread Clement Courbet via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL348741: [Sema] Further improvements to to static_assert 
diagnostics. (authored by courbet, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

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

https://reviews.llvm.org/D55270

Files:
  cfe/trunk/include/clang/Sema/Sema.h
  cfe/trunk/lib/Sema/SemaDeclCXX.cpp
  cfe/trunk/lib/Sema/SemaTemplate.cpp
  cfe/trunk/test/PCH/cxx-static_assert.cpp
  cfe/trunk/test/Sema/static-assert.c
  cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp
  cfe/trunk/test/SemaCXX/static-assert.cpp

Index: cfe/trunk/lib/Sema/SemaTemplate.cpp
===
--- cfe/trunk/lib/Sema/SemaTemplate.cpp
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp
@@ -3052,30 +3052,42 @@
   return Cond;
 }
 
-// Print a diagnostic for the failing static_assert expression. Defaults to
-// pretty-printing the expression.
-static void prettyPrintFailedBooleanCondition(llvm::raw_string_ostream &OS,
-  const Expr *FailedCond,
-  const PrintingPolicy &Policy) {
-  const auto *DR = dyn_cast(FailedCond);
-  if (DR && DR->getQualifier()) {
-// If this is a qualified name, expand the template arguments in nested
-// qualifiers.
-DR->getQualifier()->print(OS, Policy, true);
-// Then print the decl itself.
-const ValueDecl *VD = DR->getDecl();
-OS << VD->getName();
-if (const auto *IV = dyn_cast(VD)) {
-  // This is a template variable, print the expanded template arguments.
-  printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy);
+namespace {
+
+// A PrinterHelper that prints more helpful diagnostics for some sub-expressions
+// within failing boolean expression, such as substituting template parameters
+// for actual types.
+class FailedBooleanConditionPrinterHelper : public PrinterHelper {
+public:
+  explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &Policy)
+  : Policy(Policy) {}
+
+  bool handledStmt(Stmt *E, raw_ostream &OS) override {
+const auto *DR = dyn_cast(E);
+if (DR && DR->getQualifier()) {
+  // If this is a qualified name, expand the template arguments in nested
+  // qualifiers.
+  DR->getQualifier()->print(OS, Policy, true);
+  // Then print the decl itself.
+  const ValueDecl *VD = DR->getDecl();
+  OS << VD->getName();
+  if (const auto *IV = dyn_cast(VD)) {
+// This is a template variable, print the expanded template arguments.
+printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy);
+  }
+  return true;
 }
-return;
+return false;
   }
-  FailedCond->printPretty(OS, nullptr, Policy);
-}
+
+private:
+  const PrintingPolicy &Policy;
+};
+
+} // end anonymous namespace
 
 std::pair
-Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
+Sema::findFailedBooleanCondition(Expr *Cond) {
   Cond = lookThroughRangesV3Condition(PP, Cond);
 
   // Separate out all of the terms in a conjunction.
@@ -3087,11 +3099,6 @@
   for (Expr *Term : Terms) {
 Expr *TermAsWritten = Term->IgnoreParenImpCasts();
 
-// Literals are uninteresting.
-if (isa(TermAsWritten) ||
-isa(TermAsWritten))
-  continue;
-
 // The initialization of the parameter from the argument is
 // a constant-evaluated context.
 EnterExpressionEvaluationContext ConstantEvaluated(
@@ -3104,18 +3111,18 @@
   break;
 }
   }
-
-  if (!FailedCond) {
-if (!AllowTopLevelCond)
-  return { nullptr, "" };
-
+  if (!FailedCond)
 FailedCond = Cond->IgnoreParenImpCasts();
-  }
+
+  // Literals are uninteresting.
+  if (isa(FailedCond) || isa(FailedCond))
+return {nullptr, ""};
 
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-prettyPrintFailedBooleanCondition(Out, FailedCond, getPrintingPolicy());
+FailedBooleanConditionPrinterHelper Helper(getPrintingPolicy());
+FailedCond->printPretty(Out, &Helper, getPrintingPolicy());
   }
   return { FailedCond, Description };
 }
@@ -3199,9 +3206,7 @@
 Expr *FailedCond;
 std::string FailedDescription;
 std::tie(FailedCond, FailedDescription) =
-  findFailedBooleanCondition(
-TemplateArgs[0].getSourceExpression(),
-/*AllowTopLevelCond=*/true);
+  findFailedBooleanCondition(TemplateArgs[0].getSourceExpression());
 
 // Remove the old SFINAE diagnostic.
 PartialDiagnosticAt OldDiag =
@@ -9649,7 +9654,7 @@
 Expr *FailedCond;
 std::string FailedDescription;
 std::tie(FailedCond, FailedDescription) =
-  findFailedBooleanCondition(Cond, /*AllowTopLevelCond=*/true);
+  findFailedBooleanCondition(Cond);
 
 Diag(FailedCond->getExprLo

[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-10 Thread Clement Courbet via Phabricator via cfe-commits
courbet added a comment.

Thanks.


Repository:
  rC Clang

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

https://reviews.llvm.org/D55270



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


[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-09 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman accepted this revision.
aaron.ballman added a comment.
This revision is now accepted and ready to land.

LGTM!




Comment at: test/PCH/cxx-static_assert.cpp:17
 
-// expected-error@12 {{static_assert failed "N is not 2!"}}
+// expected-error@12 {{static_assert failed due to requirement '1 == 2' "N is 
not 2!"}}
 T<1> t1; // expected-note {{in instantiation of template class 'T<1>' 
requested here}}

Quuxplusone wrote:
> aaron.ballman wrote:
> > Quuxplusone wrote:
> > > courbet wrote:
> > > > aaron.ballman wrote:
> > > > > I'm not certain how I feel about now printing the failure condition 
> > > > > when there's an explicit message provided. From what I understand, a 
> > > > > fair amount of code in the wild does `static_assert(some_condition, 
> > > > > "some_condition")` because of older language modes where the message 
> > > > > was not optional. I worry we're going to start seeing a lot of 
> > > > > diagnostics like: `static_assert failed due to requirement '1 == 2' 
> > > > > "N == 2"`, which seems a bit low-quality. See 
> > > > > `DFAPacketizer::DFAPacketizer()` in LLVM as an example of something 
> > > > > similar.
> > > > > 
> > > > > Given that the user entered a message, do we still want to show the 
> > > > > requirement? Do we feel the same way if the requirement is fairly 
> > > > > large?
> > > > The issue is that `"N == 2"` is a useless error message. Actually, 
> > > > since the  error message has to be a string literal, there is no way 
> > > > for the user to print a debuggable output. So I really think we should 
> > > > print the failed condition.
> > > FWIW, I also don't agree with Aaron's concern.
> > > 
> > > I do think there is a lot of code in the wild whose string literal was 
> > > "phoned in." After all, this is why C++17 allows us to omit the string 
> > > literal: to avoid boilerplate like this.
> > > 
> > > static_assert(some-condition, "some-condition");
> > > static_assert(some-condition, "some-condition was not satisfied");
> > > static_assert(some-condition, "some-condition must be satisfied");
> > > static_assert(some-condition, "");
> > > 
> > > But should Clang go _out of its way_ to suppress such "redundant" string 
> > > literals? First of all, such suppression would be C++14-and-earlier: if a 
> > > C++17-native program contains a string literal, we should maybe assume 
> > > it's on purpose. Second, it's not clear how a machine could detect 
> > > "redundant" literals with high fidelity.
> > > 
> > > static_assert(std::is_integral, "std::is_integral");
> > > // clearly redundant
> > > static_assert(std::is_integral, "T must be integral");
> > > // redundant, but unlikely to be machine-detectable as such
> > > 
> > > static_assert((DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= (8 * 
> > > sizeof(DFAInput)),
> > > "(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) > (8 * 
> > > sizeof(DFAInput))");
> > > // redundant, but unlikely to be machine-detectable as such
> > > // thanks to the substitution of > for <=
> > > 
> > > static_assert((DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= (8 * 
> > > sizeof(DFAInput)),
> > > "(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) too big for DFAInput");
> > > // redundant, but unlikely to be machine-detectable as such
> > > 
> > > In any event, I agree with @courbet that Clang should print the expansion 
> > > of the failed condition in any case.
> > > 
> > > Also: One might argue that if the `static_assert` fits completely on one 
> > > source line, then we could omit the string-literal from our error message 
> > > because the string literal will be shown anyway as part of the offending 
> > > source line — but I believe IDE-users would complain about that, so, we 
> > > shouldn't do that. And even then, we'd still want to print the failed 
> > > condition!
> > > 
> > > Checking my understanding: The `static_assert` above (taken from 
> > > `DFAPacketizer::DFAPacketizer()` in LLVM) would be unchanged by 
> > > @courbet's patches, because none of its subexpressions are 
> > > template-dependent. Right?
> > > But should Clang go _out of its way_ to suppress such "redundant" string 
> > > literals? 
> > 
> > I wasn't suggesting it should; I was suggesting that Clang should be 
> > conservative and suppress printing the conditional when a message is 
> > present, not when they look to be redundant enough.
> > 
> > > if a C++17-native program contains a string literal, we should maybe 
> > > assume it's on purpose. 
> > 
> > This is the exact scenario I was envisioning.
> > 
> > It's a relatively weak preference, but I kind of prefer not displaying the 
> > conditional information in the presence of a message (at least in C++17 and 
> > above), especially as the conditional can be huge. I'm thinking of 
> > scenarios where the user does something like:
> > ```
> > static_assert(condition1 && condition2 && (condition3 || condi

[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-08 Thread Arthur O'Dwyer via Phabricator via cfe-commits
Quuxplusone added a subscriber: saar.raz.
Quuxplusone added inline comments.



Comment at: test/PCH/cxx-static_assert.cpp:17
 
-// expected-error@12 {{static_assert failed "N is not 2!"}}
+// expected-error@12 {{static_assert failed due to requirement '1 == 2' "N is 
not 2!"}}
 T<1> t1; // expected-note {{in instantiation of template class 'T<1>' 
requested here}}

aaron.ballman wrote:
> Quuxplusone wrote:
> > courbet wrote:
> > > aaron.ballman wrote:
> > > > I'm not certain how I feel about now printing the failure condition 
> > > > when there's an explicit message provided. From what I understand, a 
> > > > fair amount of code in the wild does `static_assert(some_condition, 
> > > > "some_condition")` because of older language modes where the message 
> > > > was not optional. I worry we're going to start seeing a lot of 
> > > > diagnostics like: `static_assert failed due to requirement '1 == 2' "N 
> > > > == 2"`, which seems a bit low-quality. See 
> > > > `DFAPacketizer::DFAPacketizer()` in LLVM as an example of something 
> > > > similar.
> > > > 
> > > > Given that the user entered a message, do we still want to show the 
> > > > requirement? Do we feel the same way if the requirement is fairly large?
> > > The issue is that `"N == 2"` is a useless error message. Actually, since 
> > > the  error message has to be a string literal, there is no way for the 
> > > user to print a debuggable output. So I really think we should print the 
> > > failed condition.
> > FWIW, I also don't agree with Aaron's concern.
> > 
> > I do think there is a lot of code in the wild whose string literal was 
> > "phoned in." After all, this is why C++17 allows us to omit the string 
> > literal: to avoid boilerplate like this.
> > 
> > static_assert(some-condition, "some-condition");
> > static_assert(some-condition, "some-condition was not satisfied");
> > static_assert(some-condition, "some-condition must be satisfied");
> > static_assert(some-condition, "");
> > 
> > But should Clang go _out of its way_ to suppress such "redundant" string 
> > literals? First of all, such suppression would be C++14-and-earlier: if a 
> > C++17-native program contains a string literal, we should maybe assume it's 
> > on purpose. Second, it's not clear how a machine could detect "redundant" 
> > literals with high fidelity.
> > 
> > static_assert(std::is_integral, "std::is_integral");
> > // clearly redundant
> > static_assert(std::is_integral, "T must be integral");
> > // redundant, but unlikely to be machine-detectable as such
> > 
> > static_assert((DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= (8 * 
> > sizeof(DFAInput)),
> > "(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) > (8 * sizeof(DFAInput))");
> > // redundant, but unlikely to be machine-detectable as such
> > // thanks to the substitution of > for <=
> > 
> > static_assert((DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= (8 * 
> > sizeof(DFAInput)),
> > "(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) too big for DFAInput");
> > // redundant, but unlikely to be machine-detectable as such
> > 
> > In any event, I agree with @courbet that Clang should print the expansion 
> > of the failed condition in any case.
> > 
> > Also: One might argue that if the `static_assert` fits completely on one 
> > source line, then we could omit the string-literal from our error message 
> > because the string literal will be shown anyway as part of the offending 
> > source line — but I believe IDE-users would complain about that, so, we 
> > shouldn't do that. And even then, we'd still want to print the failed 
> > condition!
> > 
> > Checking my understanding: The `static_assert` above (taken from 
> > `DFAPacketizer::DFAPacketizer()` in LLVM) would be unchanged by @courbet's 
> > patches, because none of its subexpressions are template-dependent. Right?
> > But should Clang go _out of its way_ to suppress such "redundant" string 
> > literals? 
> 
> I wasn't suggesting it should; I was suggesting that Clang should be 
> conservative and suppress printing the conditional when a message is present, 
> not when they look to be redundant enough.
> 
> > if a C++17-native program contains a string literal, we should maybe assume 
> > it's on purpose. 
> 
> This is the exact scenario I was envisioning.
> 
> It's a relatively weak preference, but I kind of prefer not displaying the 
> conditional information in the presence of a message (at least in C++17 and 
> above), especially as the conditional can be huge. I'm thinking of scenarios 
> where the user does something like:
> ```
> static_assert(condition1 && condition2 && (condition3 || condition4), "Simple 
> explanation");
> ```
> except that `condition` is replaced by `std::some_type_trait` in 
> various interesting ways.
> 
> I'm thinking of scenarios where the user does something like:
> 
> static_assert(condition1 && condition2 && (condit

[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-07 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added inline comments.



Comment at: test/PCH/cxx-static_assert.cpp:17
 
-// expected-error@12 {{static_assert failed "N is not 2!"}}
+// expected-error@12 {{static_assert failed due to requirement '1 == 2' "N is 
not 2!"}}
 T<1> t1; // expected-note {{in instantiation of template class 'T<1>' 
requested here}}

Quuxplusone wrote:
> courbet wrote:
> > aaron.ballman wrote:
> > > I'm not certain how I feel about now printing the failure condition when 
> > > there's an explicit message provided. From what I understand, a fair 
> > > amount of code in the wild does `static_assert(some_condition, 
> > > "some_condition")` because of older language modes where the message was 
> > > not optional. I worry we're going to start seeing a lot of diagnostics 
> > > like: `static_assert failed due to requirement '1 == 2' "N == 2"`, which 
> > > seems a bit low-quality. See `DFAPacketizer::DFAPacketizer()` in LLVM as 
> > > an example of something similar.
> > > 
> > > Given that the user entered a message, do we still want to show the 
> > > requirement? Do we feel the same way if the requirement is fairly large?
> > The issue is that `"N == 2"` is a useless error message. Actually, since 
> > the  error message has to be a string literal, there is no way for the user 
> > to print a debuggable output. So I really think we should print the failed 
> > condition.
> FWIW, I also don't agree with Aaron's concern.
> 
> I do think there is a lot of code in the wild whose string literal was 
> "phoned in." After all, this is why C++17 allows us to omit the string 
> literal: to avoid boilerplate like this.
> 
> static_assert(some-condition, "some-condition");
> static_assert(some-condition, "some-condition was not satisfied");
> static_assert(some-condition, "some-condition must be satisfied");
> static_assert(some-condition, "");
> 
> But should Clang go _out of its way_ to suppress such "redundant" string 
> literals? First of all, such suppression would be C++14-and-earlier: if a 
> C++17-native program contains a string literal, we should maybe assume it's 
> on purpose. Second, it's not clear how a machine could detect "redundant" 
> literals with high fidelity.
> 
> static_assert(std::is_integral, "std::is_integral");
> // clearly redundant
> static_assert(std::is_integral, "T must be integral");
> // redundant, but unlikely to be machine-detectable as such
> 
> static_assert((DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= (8 * 
> sizeof(DFAInput)),
> "(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) > (8 * sizeof(DFAInput))");
> // redundant, but unlikely to be machine-detectable as such
> // thanks to the substitution of > for <=
> 
> static_assert((DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= (8 * 
> sizeof(DFAInput)),
> "(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) too big for DFAInput");
> // redundant, but unlikely to be machine-detectable as such
> 
> In any event, I agree with @courbet that Clang should print the expansion of 
> the failed condition in any case.
> 
> Also: One might argue that if the `static_assert` fits completely on one 
> source line, then we could omit the string-literal from our error message 
> because the string literal will be shown anyway as part of the offending 
> source line — but I believe IDE-users would complain about that, so, we 
> shouldn't do that. And even then, we'd still want to print the failed 
> condition!
> 
> Checking my understanding: The `static_assert` above (taken from 
> `DFAPacketizer::DFAPacketizer()` in LLVM) would be unchanged by @courbet's 
> patches, because none of its subexpressions are template-dependent. Right?
> But should Clang go _out of its way_ to suppress such "redundant" string 
> literals? 

I wasn't suggesting it should; I was suggesting that Clang should be 
conservative and suppress printing the conditional when a message is present, 
not when they look to be redundant enough.

> if a C++17-native program contains a string literal, we should maybe assume 
> it's on purpose. 

This is the exact scenario I was envisioning.

It's a relatively weak preference, but I kind of prefer not displaying the 
conditional information in the presence of a message (at least in C++17 and 
above), especially as the conditional can be huge. I'm thinking of scenarios 
where the user does something like:
```
static_assert(condition1 && condition2 && (condition3 || condition4), "Simple 
explanation");
```
except that `condition` is replaced by `std::some_type_trait` in various 
interesting ways.



Repository:
  rC Clang

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

https://reviews.llvm.org/D55270



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


[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-07 Thread Arthur O'Dwyer via Phabricator via cfe-commits
Quuxplusone added inline comments.



Comment at: test/PCH/cxx-static_assert.cpp:17
 
-// expected-error@12 {{static_assert failed "N is not 2!"}}
+// expected-error@12 {{static_assert failed due to requirement '1 == 2' "N is 
not 2!"}}
 T<1> t1; // expected-note {{in instantiation of template class 'T<1>' 
requested here}}

courbet wrote:
> aaron.ballman wrote:
> > I'm not certain how I feel about now printing the failure condition when 
> > there's an explicit message provided. From what I understand, a fair amount 
> > of code in the wild does `static_assert(some_condition, "some_condition")` 
> > because of older language modes where the message was not optional. I worry 
> > we're going to start seeing a lot of diagnostics like: `static_assert 
> > failed due to requirement '1 == 2' "N == 2"`, which seems a bit 
> > low-quality. See `DFAPacketizer::DFAPacketizer()` in LLVM as an example of 
> > something similar.
> > 
> > Given that the user entered a message, do we still want to show the 
> > requirement? Do we feel the same way if the requirement is fairly large?
> The issue is that `"N == 2"` is a useless error message. Actually, since the  
> error message has to be a string literal, there is no way for the user to 
> print a debuggable output. So I really think we should print the failed 
> condition.
FWIW, I also don't agree with Aaron's concern.

I do think there is a lot of code in the wild whose string literal was "phoned 
in." After all, this is why C++17 allows us to omit the string literal: to 
avoid boilerplate like this.

static_assert(some-condition, "some-condition");
static_assert(some-condition, "some-condition was not satisfied");
static_assert(some-condition, "some-condition must be satisfied");
static_assert(some-condition, "");

But should Clang go _out of its way_ to suppress such "redundant" string 
literals? First of all, such suppression would be C++14-and-earlier: if a 
C++17-native program contains a string literal, we should maybe assume it's on 
purpose. Second, it's not clear how a machine could detect "redundant" literals 
with high fidelity.

static_assert(std::is_integral, "std::is_integral");
// clearly redundant
static_assert(std::is_integral, "T must be integral");
// redundant, but unlikely to be machine-detectable as such

static_assert((DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= (8 * 
sizeof(DFAInput)),
"(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) > (8 * sizeof(DFAInput))");
// redundant, but unlikely to be machine-detectable as such
// thanks to the substitution of > for <=

static_assert((DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= (8 * 
sizeof(DFAInput)),
"(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) too big for DFAInput");
// redundant, but unlikely to be machine-detectable as such

In any event, I agree with @courbet that Clang should print the expansion of 
the failed condition in any case.

Also: One might argue that if the `static_assert` fits completely on one source 
line, then we could omit the string-literal from our error message because the 
string literal will be shown anyway as part of the offending source line — but 
I believe IDE-users would complain about that, so, we shouldn't do that. And 
even then, we'd still want to print the failed condition!

Checking my understanding: The `static_assert` above (taken from 
`DFAPacketizer::DFAPacketizer()` in LLVM) would be unchanged by @courbet's 
patches, because none of its subexpressions are template-dependent. Right?


Repository:
  rC Clang

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

https://reviews.llvm.org/D55270



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


[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-07 Thread Clement Courbet via Phabricator via cfe-commits
courbet marked an inline comment as done.
courbet added inline comments.



Comment at: test/PCH/cxx-static_assert.cpp:17
 
-// expected-error@12 {{static_assert failed "N is not 2!"}}
+// expected-error@12 {{static_assert failed due to requirement '1 == 2' "N is 
not 2!"}}
 T<1> t1; // expected-note {{in instantiation of template class 'T<1>' 
requested here}}

aaron.ballman wrote:
> I'm not certain how I feel about now printing the failure condition when 
> there's an explicit message provided. From what I understand, a fair amount 
> of code in the wild does `static_assert(some_condition, "some_condition")` 
> because of older language modes where the message was not optional. I worry 
> we're going to start seeing a lot of diagnostics like: `static_assert failed 
> due to requirement '1 == 2' "N == 2"`, which seems a bit low-quality. See 
> `DFAPacketizer::DFAPacketizer()` in LLVM as an example of something similar.
> 
> Given that the user entered a message, do we still want to show the 
> requirement? Do we feel the same way if the requirement is fairly large?
The issue is that `"N == 2"` is a useless error message. Actually, since the  
error message has to be a string literal, there is no way for the user to print 
a debuggable output. So I really think we should print the failed condition.


Repository:
  rC Clang

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

https://reviews.llvm.org/D55270



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


[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-06 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added inline comments.



Comment at: test/PCH/cxx-static_assert.cpp:17
 
-// expected-error@12 {{static_assert failed "N is not 2!"}}
+// expected-error@12 {{static_assert failed due to requirement '1 == 2' "N is 
not 2!"}}
 T<1> t1; // expected-note {{in instantiation of template class 'T<1>' 
requested here}}

I'm not certain how I feel about now printing the failure condition when 
there's an explicit message provided. From what I understand, a fair amount of 
code in the wild does `static_assert(some_condition, "some_condition")` because 
of older language modes where the message was not optional. I worry we're going 
to start seeing a lot of diagnostics like: `static_assert failed due to 
requirement '1 == 2' "N == 2"`, which seems a bit low-quality. See 
`DFAPacketizer::DFAPacketizer()` in LLVM as an example of something similar.

Given that the user entered a message, do we still want to show the 
requirement? Do we feel the same way if the requirement is fairly large?


Repository:
  rC Clang

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

https://reviews.llvm.org/D55270



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


[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-05 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 176773.
courbet added a comment.

- Update PHC and C11 tests.


Repository:
  rC Clang

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

https://reviews.llvm.org/D55270

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaTemplate.cpp
  test/PCH/cxx-static_assert.cpp
  test/Sema/static-assert.c
  test/SemaCXX/static-assert-cxx17.cpp
  test/SemaCXX/static-assert.cpp

Index: test/SemaCXX/static-assert.cpp
===
--- test/SemaCXX/static-assert.cpp
+++ test/SemaCXX/static-assert.cpp
@@ -15,14 +15,14 @@
 };
 
 template struct T {
-static_assert(N == 2, "N is not 2!"); // expected-error {{static_assert failed "N is not 2!"}}
+static_assert(N == 2, "N is not 2!"); // expected-error {{static_assert failed due to requirement '1 == 2' "N is not 2!"}}
 };
 
 T<1> t1; // expected-note {{in instantiation of template class 'T<1>' requested here}}
 T<2> t2;
 
 template struct S {
-static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static_assert failed "Type not big enough!"}}
+static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static_assert failed due to requirement 'sizeof(char) > sizeof(char)' "Type not big enough!"}}
 };
 
 S s1; // expected-note {{in instantiation of template class 'S' requested here}}
@@ -111,6 +111,14 @@
 // expected-error@-1{{static_assert failed due to requirement 'std::is_same::value' "message"}}
 static_assert(std::is_const::value, "message");
 // expected-error@-1{{static_assert failed due to requirement 'std::is_const::value' "message"}}
+static_assert(!std::is_const::value, "message");
+// expected-error@-1{{static_assert failed due to requirement '!std::is_const::value' "message"}}
+static_assert(!(std::is_const::value), "message");
+// expected-error@-1{{static_assert failed due to requirement '!(std::is_const::value)' "message"}}
+static_assert(std::is_const::value == false, "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_const::value == false' "message"}}
+static_assert(!(std::is_const::value == true), "message");
+// expected-error@-1{{static_assert failed due to requirement '!(std::is_const::value == true)' "message"}}
 
 struct BI_tag {};
 struct RAI_tag : BI_tag {};
Index: test/SemaCXX/static-assert-cxx17.cpp
===
--- test/SemaCXX/static-assert-cxx17.cpp
+++ test/SemaCXX/static-assert-cxx17.cpp
@@ -45,3 +45,12 @@
 };
 template void foo4();
 // expected-note@-1{{in instantiation of function template specialization 'foo4' requested here}}
+
+
+template 
+void foo5() {
+  static_assert(!!(global_inline_var));
+  // expected-error@-1{{static_assert failed due to requirement '!!(global_inline_var)'}}
+}
+template void foo5();
+// expected-note@-1{{in instantiation of function template specialization 'foo5' requested here}}
Index: test/Sema/static-assert.c
===
--- test/Sema/static-assert.c
+++ test/Sema/static-assert.c
@@ -38,5 +38,5 @@
 
 typedef UNION(unsigned, struct A) U1;
 UNION(char[2], short) u2 = { .one = { 'a', 'b' } };
-typedef UNION(char, short) U3; // expected-error {{static_assert failed "type size mismatch"}}
+typedef UNION(char, short) U3; // expected-error {{static_assert failed due to requirement 'sizeof(char) == sizeof(short)' "type size mismatch"}}
 typedef UNION(float, 0.5f) U4; // expected-error {{expected a type}}
Index: test/PCH/cxx-static_assert.cpp
===
--- test/PCH/cxx-static_assert.cpp
+++ test/PCH/cxx-static_assert.cpp
@@ -3,7 +3,7 @@
 
 // Test with pch.
 // RUN: %clang_cc1 -std=c++11 -emit-pch -o %t %s
-// RUN: %clang_cc1 -include-pch %t -verify -std=c++11 %s 
+// RUN: %clang_cc1 -include-pch %t -verify -std=c++11 %s
 
 #ifndef HEADER
 #define HEADER
@@ -14,7 +14,7 @@
 
 #else
 
-// expected-error@12 {{static_assert failed "N is not 2!"}}
+// expected-error@12 {{static_assert failed due to requirement '1 == 2' "N is not 2!"}}
 T<1> t1; // expected-note {{in instantiation of template class 'T<1>' requested here}}
 T<2> t2;
 
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,30 +3052,42 @@
   return Cond;
 }
 
-// Print a diagnostic for the failing static_assert expression. Defaults to
-// pretty-printing the expression.
-static void prettyPrintFailedBooleanCondition(llvm::raw_string_ostream &OS,
-  const Expr *FailedCond,
-  const PrintingPolicy &Policy) {
-  const auto *DR = dyn_cast(FailedCond);
-  if (DR && DR->getQualifier()) {
-// If this is a qualified name, expand the template arguments in nested
-//

[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-05 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 176771.
courbet marked 2 inline comments as done.
courbet added a comment.

- Address comments
- Add more tests
- Remove AllowTopLevel and handle cases like `sizeof(T)` (-> `sizeof(int)`)


Repository:
  rC Clang

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

https://reviews.llvm.org/D55270

Files:
  include/clang/Sema/Sema.h
  lib/Sema/SemaDeclCXX.cpp
  lib/Sema/SemaTemplate.cpp
  test/SemaCXX/static-assert-cxx17.cpp
  test/SemaCXX/static-assert.cpp

Index: test/SemaCXX/static-assert.cpp
===
--- test/SemaCXX/static-assert.cpp
+++ test/SemaCXX/static-assert.cpp
@@ -15,14 +15,14 @@
 };
 
 template struct T {
-static_assert(N == 2, "N is not 2!"); // expected-error {{static_assert failed "N is not 2!"}}
+static_assert(N == 2, "N is not 2!"); // expected-error {{static_assert failed due to requirement '1 == 2' "N is not 2!"}}
 };
 
 T<1> t1; // expected-note {{in instantiation of template class 'T<1>' requested here}}
 T<2> t2;
 
 template struct S {
-static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static_assert failed "Type not big enough!"}}
+static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static_assert failed due to requirement 'sizeof(char) > sizeof(char)' "Type not big enough!"}}
 };
 
 S s1; // expected-note {{in instantiation of template class 'S' requested here}}
@@ -111,6 +111,14 @@
 // expected-error@-1{{static_assert failed due to requirement 'std::is_same::value' "message"}}
 static_assert(std::is_const::value, "message");
 // expected-error@-1{{static_assert failed due to requirement 'std::is_const::value' "message"}}
+static_assert(!std::is_const::value, "message");
+// expected-error@-1{{static_assert failed due to requirement '!std::is_const::value' "message"}}
+static_assert(!(std::is_const::value), "message");
+// expected-error@-1{{static_assert failed due to requirement '!(std::is_const::value)' "message"}}
+static_assert(std::is_const::value == false, "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_const::value == false' "message"}}
+static_assert(!(std::is_const::value == true), "message");
+// expected-error@-1{{static_assert failed due to requirement '!(std::is_const::value == true)' "message"}}
 
 struct BI_tag {};
 struct RAI_tag : BI_tag {};
Index: test/SemaCXX/static-assert-cxx17.cpp
===
--- test/SemaCXX/static-assert-cxx17.cpp
+++ test/SemaCXX/static-assert-cxx17.cpp
@@ -45,3 +45,12 @@
 };
 template void foo4();
 // expected-note@-1{{in instantiation of function template specialization 'foo4' requested here}}
+
+
+template 
+void foo5() {
+  static_assert(!!(global_inline_var));
+  // expected-error@-1{{static_assert failed due to requirement '!!(global_inline_var)'}}
+}
+template void foo5();
+// expected-note@-1{{in instantiation of function template specialization 'foo5' requested here}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,30 +3052,42 @@
   return Cond;
 }
 
-// Print a diagnostic for the failing static_assert expression. Defaults to
-// pretty-printing the expression.
-static void prettyPrintFailedBooleanCondition(llvm::raw_string_ostream &OS,
-  const Expr *FailedCond,
-  const PrintingPolicy &Policy) {
-  const auto *DR = dyn_cast(FailedCond);
-  if (DR && DR->getQualifier()) {
-// If this is a qualified name, expand the template arguments in nested
-// qualifiers.
-DR->getQualifier()->print(OS, Policy, true);
-// Then print the decl itself.
-const ValueDecl *VD = DR->getDecl();
-OS << VD->getName();
-if (const auto *IV = dyn_cast(VD)) {
-  // This is a template variable, print the expanded template arguments.
-  printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy);
+namespace {
+
+// A PrinterHelper that prints more helpful diagnostics for some sub-expressions
+// within failing boolean expression, such as substituting template parameters
+// for actual types.
+class FailedBooleanConditionPrinterHelper : public PrinterHelper {
+public:
+  explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &Policy)
+  : Policy(Policy) {}
+
+  bool handledStmt(Stmt *E, raw_ostream &OS) override {
+const auto *DR = dyn_cast(E);
+if (DR && DR->getQualifier()) {
+  // If this is a qualified name, expand the template arguments in nested
+  // qualifiers.
+  DR->getQualifier()->print(OS, Policy, true);
+  // Then print the decl itself.
+  const ValueDecl *VD = DR->getDecl();
+  OS << VD->getName();
+  if (const auto *IV = dyn_cast(VD)) {
+// This is a templat

[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-05 Thread Clement Courbet via Phabricator via cfe-commits
courbet marked 7 inline comments as done.
courbet added inline comments.



Comment at: lib/Sema/SemaTemplate.cpp:3065
+
+  ~FailedBooleanConditionPrinterHelper() override {}
+

Quuxplusone wrote:
> aaron.ballman wrote:
> > Is this definition necessary?
> Nit: I don't know if it is LLVM style to provide explicitly written-out 
> overrides for all virtual destructors. In my own code, if a destructor would 
> be redundant, I wouldn't write it.
I don't think the style guide says anything; removed.



Comment at: test/SemaCXX/static-assert.cpp:117
+static_assert(!(std::is_const::value), "message");
+// expected-error@-1{{static_assert failed due to requirement 
'!(std::is_const::value)' "message"}}
 

Quuxplusone wrote:
> Please also add a test case for the `is_const_v` inline-variable-template 
> version.
> ```
> template
> inline constexpr bool is_const_v = is_const::value;
> static_assert(is_const_v, "message");  // if this test case 
> was missing from the previous patch
> static_assert(!is_const_v, "message");  // exercise the 
> same codepath for this new feature
> ```
> 
> Also, does using the PrinterHelper mean that you get a bunch of other cases 
> for free? Like, does this work now too?
> ```
> static_assert(is_const::value == false, "message");
> ```
> Please also add a test case for the is_const_v inline-variable-template 
> version.

done (in c++17 tests)

> Also, does using the PrinterHelper mean that you get a bunch of other cases 
> for free? Like, does this work now too?

Exactly. While I'm at it I've added tests for your use case and removed the no 
longer needed AllowTopLevel parameter.




Repository:
  rC Clang

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

https://reviews.llvm.org/D55270



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


[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-04 Thread Arthur O'Dwyer via Phabricator via cfe-commits
Quuxplusone added inline comments.



Comment at: lib/Sema/SemaTemplate.cpp:3062
+public:
+  FailedBooleanConditionPrinterHelper(const PrintingPolicy &Policy)
+  : Policy(Policy) {}

`explicit`



Comment at: lib/Sema/SemaTemplate.cpp:3065
+
+  ~FailedBooleanConditionPrinterHelper() override {}
+

aaron.ballman wrote:
> Is this definition necessary?
Nit: I don't know if it is LLVM style to provide explicitly written-out 
overrides for all virtual destructors. In my own code, if a destructor would be 
redundant, I wouldn't write it.



Comment at: lib/Sema/SemaTemplate.cpp:3089
+
+} // namespace
 

`} // end anonymous namespace`



Comment at: test/SemaCXX/static-assert.cpp:117
+static_assert(!(std::is_const::value), "message");
+// expected-error@-1{{static_assert failed due to requirement 
'!(std::is_const::value)' "message"}}
 

Please also add a test case for the `is_const_v` inline-variable-template 
version.
```
template
inline constexpr bool is_const_v = is_const::value;
static_assert(is_const_v, "message");  // if this test case 
was missing from the previous patch
static_assert(!is_const_v, "message");  // exercise the 
same codepath for this new feature
```

Also, does using the PrinterHelper mean that you get a bunch of other cases for 
free? Like, does this work now too?
```
static_assert(is_const::value == false, "message");
```


Repository:
  rC Clang

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

https://reviews.llvm.org/D55270



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


[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-04 Thread Aaron Ballman via Phabricator via cfe-commits
aaron.ballman added inline comments.



Comment at: lib/Sema/SemaTemplate.cpp:3065
+
+  ~FailedBooleanConditionPrinterHelper() override {}
+

Is this definition necessary?


Repository:
  rC Clang

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

https://reviews.llvm.org/D55270



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


[PATCH] D55270: [Sema] Further improvements to to static_assert diagnostics.

2018-12-04 Thread Clement Courbet via Phabricator via cfe-commits
courbet created this revision.
courbet added reviewers: aaron.ballman, Quuxplusone.

We're now handling cases like `static_assert(!expr)` and
static_assert(!(expr))`.


Repository:
  rC Clang

https://reviews.llvm.org/D55270

Files:
  lib/Sema/SemaTemplate.cpp
  test/SemaCXX/static-assert.cpp


Index: test/SemaCXX/static-assert.cpp
===
--- test/SemaCXX/static-assert.cpp
+++ test/SemaCXX/static-assert.cpp
@@ -111,6 +111,10 @@
 // expected-error@-1{{static_assert failed due to requirement 
'std::is_same::value' "message"}}
 static_assert(std::is_const::value, "message");
 // expected-error@-1{{static_assert failed due to requirement 
'std::is_const::value' "message"}}
+static_assert(!std::is_const::value, "message");
+// expected-error@-1{{static_assert failed due to requirement 
'!std::is_const::value' "message"}}
+static_assert(!(std::is_const::value), "message");
+// expected-error@-1{{static_assert failed due to requirement 
'!(std::is_const::value)' "message"}}
 
 struct BI_tag {};
 struct RAI_tag : BI_tag {};
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,27 +3052,41 @@
   return Cond;
 }
 
-// Print a diagnostic for the failing static_assert expression. Defaults to
-// pretty-printing the expression.
-static void prettyPrintFailedBooleanCondition(llvm::raw_string_ostream &OS,
-  const Expr *FailedCond,
-  const PrintingPolicy &Policy) {
-  const auto *DR = dyn_cast(FailedCond);
-  if (DR && DR->getQualifier()) {
-// If this is a qualified name, expand the template arguments in nested
-// qualifiers.
-DR->getQualifier()->print(OS, Policy, true);
-// Then print the decl itself.
-const ValueDecl *VD = DR->getDecl();
-OS << VD->getName();
-if (const auto *IV = dyn_cast(VD)) {
-  // This is a template variable, print the expanded template arguments.
-  printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy);
+namespace {
+
+// A PrinterHelper that prints more helpful diagnostics for some 
sub-expressions
+// within failing boolean expression, such as substituting template parameters
+// for actual types.
+class FailedBooleanConditionPrinterHelper : public PrinterHelper {
+public:
+  FailedBooleanConditionPrinterHelper(const PrintingPolicy &Policy)
+  : Policy(Policy) {}
+
+  ~FailedBooleanConditionPrinterHelper() override {}
+
+  bool handledStmt(Stmt *E, raw_ostream &OS) override {
+const auto *DR = dyn_cast(E);
+if (DR && DR->getQualifier()) {
+  // If this is a qualified name, expand the template arguments in nested
+  // qualifiers.
+  DR->getQualifier()->print(OS, Policy, true);
+  // Then print the decl itself.
+  const ValueDecl *VD = DR->getDecl();
+  OS << VD->getName();
+  if (const auto *IV = dyn_cast(VD)) {
+// This is a template variable, print the expanded template arguments.
+printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy);
+  }
+  return true;
 }
-return;
+return false;
   }
-  FailedCond->printPretty(OS, nullptr, Policy);
-}
+
+private:
+  const PrintingPolicy &Policy;
+};
+
+} // namespace
 
 std::pair
 Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
@@ -3115,7 +3129,8 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-prettyPrintFailedBooleanCondition(Out, FailedCond, getPrintingPolicy());
+FailedBooleanConditionPrinterHelper Helper(getPrintingPolicy());
+FailedCond->printPretty(Out, &Helper, getPrintingPolicy());
   }
   return { FailedCond, Description };
 }


Index: test/SemaCXX/static-assert.cpp
===
--- test/SemaCXX/static-assert.cpp
+++ test/SemaCXX/static-assert.cpp
@@ -111,6 +111,10 @@
 // expected-error@-1{{static_assert failed due to requirement 'std::is_same::value' "message"}}
 static_assert(std::is_const::value, "message");
 // expected-error@-1{{static_assert failed due to requirement 'std::is_const::value' "message"}}
+static_assert(!std::is_const::value, "message");
+// expected-error@-1{{static_assert failed due to requirement '!std::is_const::value' "message"}}
+static_assert(!(std::is_const::value), "message");
+// expected-error@-1{{static_assert failed due to requirement '!(std::is_const::value)' "message"}}
 
 struct BI_tag {};
 struct RAI_tag : BI_tag {};
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,27 +3052,41 @@
   return Cond;
 }
 
-// Print a diagnostic for the failing static_assert expression. Defaults to
-// pretty-printing the expression.
-static void prettyPrintFailedBooleanCondition(llvm