[PATCH] D38455: [clang-tidy] new cppcoreguidelines-narrowing-conversions check.

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

- More explicit documentation.
- Do not trigger in template and macro contexts.
- More tests.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D38455

Files:
  clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tidy/bugprone/CMakeLists.txt
  clang-tidy/cppcoreguidelines/CMakeLists.txt
  clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
  clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp
  clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp

Index: test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp
===
--- /dev/null
+++ test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp
@@ -0,0 +1,103 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-narrowing-conversions %t
+
+float ceil(float);
+namespace std {
+double ceil(double);
+long double floor(long double);
+} // namespace std
+
+namespace floats {
+
+struct ConvertsToFloat {
+  operator float() const { return 0.5; }
+};
+
+float operator "" _Pa(unsigned long long);
+
+void not_ok(double d) {
+  int i = 0;
+  i = d;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+  i = 0.5f;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+  i = static_cast(d);
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+  i = ConvertsToFloat();
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+  i = 15_Pa;
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+}
+
+void not_ok_binary_ops(double d) {
+  int i = 0;
+  i += 0.5;
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+  i += 0.5f;
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+  i += d;
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+  // We warn on the following even though it's not dangerous because there is no
+  // reason to use a double literal here.
+  // TODO(courbet): Provide an automatic fix.
+  i += 2.0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+  i += 2.0f;
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+
+  i *= 0.5f;
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+  i /= 0.5f;
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+  i += (double)0.5f;
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+}
+
+void ok(double d) {
+  int i = 0;
+  i = 1;
+  i = static_cast(0.5);
+  i = static_cast(d);
+  i = std::ceil(0.5);
+  i = ::std::floor(0.5);
+  {
+using std::ceil;
+i = ceil(0.5f);
+  }
+  i = ceil(0.5f);
+}
+
+void ok_binary_ops(double d) {
+  int i = 0;
+  i += 1;
+  i += static_cast(0.5);
+  i += static_cast(d);
+  i += (int)d;
+  i += std::ceil(0.5);
+  i += ::std::floor(0.5);
+  {
+using std::ceil;
+i += ceil(0.5f);
+  }
+  i += ceil(0.5f);
+}
+
+// We're bailing out in templates and macros.
+template 
+void f(T1 one, T2 two) {
+  one += two;
+}
+
+void template_context() {
+  f(1, 2);
+  f(1, .5);
+}
+
+#define DERP(i, j) (i += j)
+
+void macro_context() {
+  int i = 0;
+  DERP(i, 2);
+  DERP(i, .5);
+}
+
+}  // namespace floats
Index: docs/clang-tidy/checks/list.rst
===
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -78,6 +78,7 @@
cppcoreguidelines-avoid-goto
cppcoreguidelines-c-copy-assignment-signature (redirects to misc-unconventional-assign-operator) 
cppcoreguidelines-interfaces-global-init
+   cppcoreguidelines-narrowing-conversions
cppcoreguidelines-no-malloc
cppcoreguidelines-owning-memory
cppcoreguidelines-pro-bounds-array-to-pointer-decay
Index: docs/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.rst
===
--- 

[PATCH] D38455: [clang-tidy] new cppcoreguidelines-narrowing-conversions check.

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

Thanks.




Comment at: clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp:35
+  hasSourceExpression(IsFloatExpr),
+  unless(hasParent(castExpr(
+ .bind("cast"),

aaron.ballman wrote:
> I believe this code will not diagnose under this check -- is that intended as 
> a way to silence the check?
> ```
> i += (double)0.5;
> ```
Did you mean `(int)0.5` ?

Yes, the user essentially told us they knew what they were doing. I've added an 
explicit test for this.



Comment at: test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp:81
+
+}  // namespace floats

aaron.ballman wrote:
> What should happen in cases like the following:
> ```
> template 
> void f(T1 one, T2 two) {
>   one += two;
> }
> 
> void g() {
>   f(1, 2);
>   f(1, .5);
> }
> 
> #define DERP(i, j) (i += j)
> 
> void h() {
>   int i = 0;
>   DERP(1, 2);
>   DERP(i, .5);
> }
> ```
I added more tests.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D38455



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


[PATCH] D38455: [clang-tidy] new cppcoreguidelines-narrowing-conversions check.

2018-05-18 Thread Clement Courbet via Phabricator via cfe-commits
courbet added inline comments.



Comment at: clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp:35
+  hasSourceExpression(IsFloatExpr),
+  unless(hasParent(castExpr(
+ .bind("cast"),

aaron.ballman wrote:
> courbet wrote:
> > aaron.ballman wrote:
> > > I believe this code will not diagnose under this check -- is that 
> > > intended as a way to silence the check?
> > > ```
> > > i += (double)0.5;
> > > ```
> > Did you mean `(int)0.5` ?
> > 
> > Yes, the user essentially told us they knew what they were doing. I've 
> > added an explicit test for this.
> I truly meant `(double)0.5` -- where the cast has no impact on the narrowing 
> conversion, but the check still doesn't diagnose because there's an explicit 
> cast present. Should the check be checking for explicit casts to the narrowed 
> type?
OK, then that's fine (I added a test for that for): there is an explicit cast 
to double, but then the compiler generates an extra cast to int on top, which 
triggers.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D38455



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


[PATCH] D38455: [clang-tidy] new cppcoreguidelines-narrowing-conversions check.

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

Great, thanks for the review !


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D38455



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


[PATCH] D38455: [clang-tidy] new cppcoreguidelines-narrowing-conversions check.

2018-05-23 Thread Clement Courbet via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL333066: [clang-tidy] new 
cppcoreguidelines-narrowing-conversions check. (authored by courbet, committed 
by ).

Repository:
  rL LLVM

https://reviews.llvm.org/D38455

Files:
  clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt
  clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CMakeLists.txt
  
clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
  
clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp
  
clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.h
  clang-tools-extra/trunk/docs/ReleaseNotes.rst
  
clang-tools-extra/trunk/docs/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.rst
  clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/trunk/test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp

Index: clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt
===
--- clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt
+++ clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt
@@ -48,6 +48,7 @@
   clangBasic
   clangLex
   clangTidy
+  clangTidyCppCoreGuidelinesModule
   clangTidyUtils
   clangTooling
   )
Index: clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp
===
--- clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -10,6 +10,7 @@
 #include "../ClangTidy.h"
 #include "../ClangTidyModule.h"
 #include "../ClangTidyModuleRegistry.h"
+#include "../cppcoreguidelines/NarrowingConversionsCheck.h"
 #include "ArgumentCommentCheck.h"
 #include "AssertSideEffectCheck.h"
 #include "BoolPointerImplicitConversionCheck.h"
@@ -92,6 +93,8 @@
 "bugprone-move-forwarding-reference");
 CheckFactories.registerCheck(
 "bugprone-multiple-statement-macro");
+CheckFactories.registerCheck(
+"bugprone-narrowing-conversions");
 CheckFactories.registerCheck(
 "bugprone-parent-virtual-call");
 CheckFactories.registerCheck(
Index: clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp
@@ -0,0 +1,70 @@
+//===--- NarrowingConversionsCheck.cpp - clang-tidy===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+
+#include "NarrowingConversionsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+// FIXME: Check double -> float truncation. Pay attention to casts:
+void NarrowingConversionsCheck::registerMatchers(MatchFinder *Finder) {
+  // ceil() and floor() are guaranteed to return integers, even though the type
+  // is not integral.
+  const auto IsCeilFloorCall = callExpr(callee(functionDecl(
+  hasAnyName("::ceil", "::std::ceil", "::floor", "::std::floor";
+
+  const auto IsFloatExpr =
+  expr(hasType(realFloatingPointType()), unless(IsCeilFloorCall));
+
+  // casts:
+  //   i = 0.5;
+  //   void f(int); f(0.5);
+  Finder->addMatcher(implicitCastExpr(hasImplicitDestinationType(isInteger()),
+  hasSourceExpression(IsFloatExpr),
+  unless(hasParent(castExpr())),
+  unless(isInTemplateInstantiation()))
+ .bind("cast"),
+ this);
+
+  // Binary operators:
+  //   i += 0.5;
+  Finder->addMatcher(
+  binaryOperator(isAssignmentOperator(),
+ // The `=` case generates an implicit cast which is covered
+ // by the previous matcher.
+ unless(hasOperatorName("=")),
+ hasLHS(hasType(isInteger())), hasRHS(IsFloatExpr),
+ unless(isInTemplateInstantiation()))
+  .bind("op"),
+  this);
+}
+
+void NarrowingConversionsCheck::check(const MatchFinder::MatchResult &Result) {
+  if (const auto *Op = Result.Nodes.getNodeAs("op")) {
+if (Op->getLocStart().isMacroID())
+  return;
+diag(Op->getOperatorLoc(), "narrowing conversion from %0 to %1")
+<< Op->getRHS()->getType() << Op->getLHS()->getType();
+return;
+  }
+  co

[PATCH] D38455: [clang-tidy] new cppcoreguidelines-narrowing-conversions check.

2018-03-19 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 138910.
courbet added a comment.
Herald added a subscriber: cfe-commits.

Do not trigger on `some_int += std::floor(some_float)`;


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D38455

Files:
  clang-tidy/cppcoreguidelines/CMakeLists.txt
  clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
  clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp
  clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp

Index: test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp
===
--- /dev/null
+++ test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp
@@ -0,0 +1,38 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-narrowing-conversions %t
+
+float ceil(float);
+namespace std {
+double ceil(double);
+long double floor(long double);
+} // namespace std
+
+void not_ok(double d) {
+  int i = 0;
+  i += 0.5;
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+  i += 0.5f;
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+  i += d;
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+  // We warn on the following even though it's not dangerous because there is no
+  // reason to use a double literal here.
+  // TODO(courbet): Provide an automatic fix.
+  i += 2.0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'double' to 'int' [cppcoreguidelines-narrowing-conversions]
+  i += 2.0f;
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: narrowing conversion from 'float' to 'int' [cppcoreguidelines-narrowing-conversions]
+}
+
+void ok(double d) {
+  int i = 0;
+  i += 1;
+  i += static_cast(3.0);
+  i += static_cast(d);
+  i += std::ceil(3.0);
+  i += ::std::floor(3.0);
+  {
+using std::ceil;
+i += ceil(3.0f);
+  }
+  i += ceil(3.0f);
+}
Index: docs/clang-tidy/checks/list.rst
===
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -74,6 +74,7 @@
cppcoreguidelines-avoid-goto
cppcoreguidelines-c-copy-assignment-signature (redirects to misc-unconventional-assign-operator) 
cppcoreguidelines-interfaces-global-init
+   cppcoreguidelines-narrowing-conversions
cppcoreguidelines-no-malloc
cppcoreguidelines-owning-memory
cppcoreguidelines-pro-bounds-array-to-pointer-decay
Index: docs/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.rst
===
--- /dev/null
+++ docs/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.rst
@@ -0,0 +1,13 @@
+.. title:: clang-tidy - cppcoreguidelines-narrowing-conversions
+
+cppcoreguidelines-narrowing-conversions
+===
+
+Checks for silent narrowing conversions, e.g: ``int i = 0; i += 0.1;``. While
+the issue is obvious in this former example, it might not be so in the
+following: ``void MyClass::f(double d) { int_member_ += d; }``.
+
+This rule is part of the "Expressions and statements" profile of the C++ Core
+Guidelines, corresponding to rule ES.46. See
+
+https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Res-narrowing.
Index: docs/ReleaseNotes.rst
===
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -178,6 +178,11 @@
 - The 'misc-unused-raii' check was renamed to `bugprone-unused-raii
   `_
 
+- New `cppcoreguidelines-narrowing-conversions
+  `_ check
+
+  Checks for narrowing conversions, e.g. ``int i = 0; i += 0.1;``.
+
 Improvements to include-fixer
 -
 
Index: clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.h
===
--- /dev/null
+++ clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.h
@@ -0,0 +1,37 @@
+//===--- NarrowingConversionsCheck.h - clang-tidy*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_NARROWING_CONVERSIONS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_NARROWING_CONVERSIONS_H
+
+#include ".

[PATCH] D56657: [clang-tidy] bugprone-string-constructor: Catch string from nullptr.

2019-01-14 Thread Clement Courbet via Phabricator via cfe-commits
courbet created this revision.
Herald added subscribers: cfe-commits, xazax.hun.

Context: https://twitter.com/willkirkby/status/1084219580799741953


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D56657

Files:
  clang-tidy/bugprone/StringConstructorCheck.cpp
  test/clang-tidy/bugprone-string-constructor.cpp


Index: test/clang-tidy/bugprone-string-constructor.cpp
===
--- test/clang-tidy/bugprone-string-constructor.cpp
+++ test/clang-tidy/bugprone-string-constructor.cpp
@@ -9,6 +9,7 @@
 struct basic_string {
   basic_string();
   basic_string(const C*, unsigned int size);
+  basic_string(const C*, const A& allocator = A());
   basic_string(unsigned int size, C c);
 };
 typedef basic_string string;
@@ -45,6 +46,13 @@
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger then string 
literal size
   std::string q5(kText3,  0x100);
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+  std::string q6(nullptr);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructing string from nullptr 
is undefined behaviour
+}
+
+std::string StringFromZero() {
+  return 0;
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: constructing string from nullptr 
is undefined behaviour
 }
 
 void Valid() {
@@ -53,4 +61,5 @@
   std::wstring wstr(4, L'x');
   std::string s1("test", 4);
   std::string s2("test", 3);
+  std::string s3("test");
 }
Index: clang-tidy/bugprone/StringConstructorCheck.cpp
===
--- clang-tidy/bugprone/StringConstructorCheck.cpp
+++ clang-tidy/bugprone/StringConstructorCheck.cpp
@@ -100,6 +100,17 @@
integerLiteral().bind("int"))
   .bind("constructor"),
   this);
+
+  // Check the literal string constructor with char pointer.
+  // [i.e. string (const char* s);]
+  Finder->addMatcher(
+  cxxConstructExpr(
+  hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
+  //hasArgument(0, hasType(CharPtrType)),
+  hasArgument(0, expr().bind("from-ptr")),
+  hasArgument(1, unless(hasType(isInteger()
+  .bind("constructor"),
+  this);
 }
 
 void StringConstructorCheck::check(const MatchFinder::MatchResult &Result) {
@@ -128,6 +139,14 @@
 if (Lit->getValue().ugt(Str->getLength())) {
   diag(Loc, "length is bigger then string literal size");
 }
+  } else if (const Expr* Ptr = Result.Nodes.getNodeAs("from-ptr")) {
+Expr::EvalResult ConstPtr;
+if (Ptr->EvaluateAsRValue(ConstPtr, Ctx) && (
+(ConstPtr.Val.isInt() && ConstPtr.Val.getInt().isNullValue()) ||
+(ConstPtr.Val.isLValue() && ConstPtr.Val.isNullPointer())
+  )) {
+  diag(Loc, "constructing string from nullptr is undefined behaviour");
+}
   }
 }
 


Index: test/clang-tidy/bugprone-string-constructor.cpp
===
--- test/clang-tidy/bugprone-string-constructor.cpp
+++ test/clang-tidy/bugprone-string-constructor.cpp
@@ -9,6 +9,7 @@
 struct basic_string {
   basic_string();
   basic_string(const C*, unsigned int size);
+  basic_string(const C*, const A& allocator = A());
   basic_string(unsigned int size, C c);
 };
 typedef basic_string string;
@@ -45,6 +46,13 @@
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger then string literal size
   std::string q5(kText3,  0x100);
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+  std::string q6(nullptr);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructing string from nullptr is undefined behaviour
+}
+
+std::string StringFromZero() {
+  return 0;
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: constructing string from nullptr is undefined behaviour
 }
 
 void Valid() {
@@ -53,4 +61,5 @@
   std::wstring wstr(4, L'x');
   std::string s1("test", 4);
   std::string s2("test", 3);
+  std::string s3("test");
 }
Index: clang-tidy/bugprone/StringConstructorCheck.cpp
===
--- clang-tidy/bugprone/StringConstructorCheck.cpp
+++ clang-tidy/bugprone/StringConstructorCheck.cpp
@@ -100,6 +100,17 @@
integerLiteral().bind("int"))
   .bind("constructor"),
   this);
+
+  // Check the literal string constructor with char pointer.
+  // [i.e. string (const char* s);]
+  Finder->addMatcher(
+  cxxConstructExpr(
+  hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
+  //hasArgument(0, hasType(CharPtrType)),
+  hasArgument(0, expr().bind("from-ptr")),
+  hasArgument(1, unless(hasType(isInteger()
+  .bind("constructor"),
+  this);
 }
 
 void StringConstructorCheck::check(const MatchFinder::MatchResult &Result) {
@@ -128,6 +139,14 @@
 if (Lit->getValue().ugt(Str->getLength())) {
   diag(Loc, "length is bigger then st

[PATCH] D56657: [clang-tidy] bugprone-string-constructor: Catch string from nullptr.

2019-01-14 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 181519.
courbet added a comment.

Remove commented code.


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D56657

Files:
  clang-tidy/bugprone/StringConstructorCheck.cpp
  test/clang-tidy/bugprone-string-constructor.cpp


Index: test/clang-tidy/bugprone-string-constructor.cpp
===
--- test/clang-tidy/bugprone-string-constructor.cpp
+++ test/clang-tidy/bugprone-string-constructor.cpp
@@ -9,6 +9,7 @@
 struct basic_string {
   basic_string();
   basic_string(const C*, unsigned int size);
+  basic_string(const C*, const A& allocator = A());
   basic_string(unsigned int size, C c);
 };
 typedef basic_string string;
@@ -45,6 +46,13 @@
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger then string 
literal size
   std::string q5(kText3,  0x100);
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+  std::string q6(nullptr);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructing string from nullptr 
is undefined behaviour
+}
+
+std::string StringFromZero() {
+  return 0;
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: constructing string from nullptr 
is undefined behaviour
 }
 
 void Valid() {
@@ -53,4 +61,5 @@
   std::wstring wstr(4, L'x');
   std::string s1("test", 4);
   std::string s2("test", 3);
+  std::string s3("test");
 }
Index: clang-tidy/bugprone/StringConstructorCheck.cpp
===
--- clang-tidy/bugprone/StringConstructorCheck.cpp
+++ clang-tidy/bugprone/StringConstructorCheck.cpp
@@ -100,6 +100,16 @@
integerLiteral().bind("int"))
   .bind("constructor"),
   this);
+
+  // Check the literal string constructor with char pointer.
+  // [i.e. string (const char* s);]
+  Finder->addMatcher(
+  cxxConstructExpr(
+  hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
+  hasArgument(0, expr().bind("from-ptr")),
+  hasArgument(1, unless(hasType(isInteger()
+  .bind("constructor"),
+  this);
 }
 
 void StringConstructorCheck::check(const MatchFinder::MatchResult &Result) {
@@ -128,6 +138,14 @@
 if (Lit->getValue().ugt(Str->getLength())) {
   diag(Loc, "length is bigger then string literal size");
 }
+  } else if (const Expr* Ptr = Result.Nodes.getNodeAs("from-ptr")) {
+Expr::EvalResult ConstPtr;
+if (Ptr->EvaluateAsRValue(ConstPtr, Ctx) && (
+(ConstPtr.Val.isInt() && ConstPtr.Val.getInt().isNullValue()) ||
+(ConstPtr.Val.isLValue() && ConstPtr.Val.isNullPointer())
+  )) {
+  diag(Loc, "constructing string from nullptr is undefined behaviour");
+}
   }
 }
 


Index: test/clang-tidy/bugprone-string-constructor.cpp
===
--- test/clang-tidy/bugprone-string-constructor.cpp
+++ test/clang-tidy/bugprone-string-constructor.cpp
@@ -9,6 +9,7 @@
 struct basic_string {
   basic_string();
   basic_string(const C*, unsigned int size);
+  basic_string(const C*, const A& allocator = A());
   basic_string(unsigned int size, C c);
 };
 typedef basic_string string;
@@ -45,6 +46,13 @@
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger then string literal size
   std::string q5(kText3,  0x100);
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+  std::string q6(nullptr);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructing string from nullptr is undefined behaviour
+}
+
+std::string StringFromZero() {
+  return 0;
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: constructing string from nullptr is undefined behaviour
 }
 
 void Valid() {
@@ -53,4 +61,5 @@
   std::wstring wstr(4, L'x');
   std::string s1("test", 4);
   std::string s2("test", 3);
+  std::string s3("test");
 }
Index: clang-tidy/bugprone/StringConstructorCheck.cpp
===
--- clang-tidy/bugprone/StringConstructorCheck.cpp
+++ clang-tidy/bugprone/StringConstructorCheck.cpp
@@ -100,6 +100,16 @@
integerLiteral().bind("int"))
   .bind("constructor"),
   this);
+
+  // Check the literal string constructor with char pointer.
+  // [i.e. string (const char* s);]
+  Finder->addMatcher(
+  cxxConstructExpr(
+  hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
+  hasArgument(0, expr().bind("from-ptr")),
+  hasArgument(1, unless(hasType(isInteger()
+  .bind("constructor"),
+  this);
 }
 
 void StringConstructorCheck::check(const MatchFinder::MatchResult &Result) {
@@ -128,6 +138,14 @@
 if (Lit->getValue().ugt(Str->getLength())) {
   diag(Loc, "length is bigger then string literal size");
 }
+  } else if (const Expr* Ptr = Result.Nodes.getNodeAs("from-p

[PATCH] D56657: [clang-tidy] bugprone-string-constructor: Catch string from nullptr.

2019-01-16 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 181985.
courbet marked 2 inline comments as done.
courbet added a comment.

clang-format + add test


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D56657

Files:
  clang-tidy/bugprone/StringConstructorCheck.cpp
  test/clang-tidy/bugprone-string-constructor.cpp


Index: test/clang-tidy/bugprone-string-constructor.cpp
===
--- test/clang-tidy/bugprone-string-constructor.cpp
+++ test/clang-tidy/bugprone-string-constructor.cpp
@@ -9,6 +9,7 @@
 struct basic_string {
   basic_string();
   basic_string(const C*, unsigned int size);
+  basic_string(const C *, const A &allocator = A());
   basic_string(unsigned int size, C c);
 };
 typedef basic_string string;
@@ -45,6 +46,15 @@
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger then string 
literal size
   std::string q5(kText3,  0x100);
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+  std::string q6(nullptr);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructing string from nullptr 
is undefined behaviour
+  std::string q7 = 0;
+  // CHECK-MESSAGES: [[@LINE-1]]:20: warning: constructing string from nullptr 
is undefined behaviour
+}
+
+std::string StringFromZero() {
+  return 0;
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: constructing string from nullptr 
is undefined behaviour
 }
 
 void Valid() {
@@ -53,4 +63,5 @@
   std::wstring wstr(4, L'x');
   std::string s1("test", 4);
   std::string s2("test", 3);
+  std::string s3("test");
 }
Index: clang-tidy/bugprone/StringConstructorCheck.cpp
===
--- clang-tidy/bugprone/StringConstructorCheck.cpp
+++ clang-tidy/bugprone/StringConstructorCheck.cpp
@@ -100,6 +100,15 @@
integerLiteral().bind("int"))
   .bind("constructor"),
   this);
+
+  // Check the literal string constructor with char pointer.
+  // [i.e. string (const char* s);]
+  Finder->addMatcher(
+  cxxConstructExpr(hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
+   hasArgument(0, expr().bind("from-ptr")),
+   hasArgument(1, unless(hasType(isInteger()
+  .bind("constructor"),
+  this);
 }
 
 void StringConstructorCheck::check(const MatchFinder::MatchResult &Result) {
@@ -128,6 +137,13 @@
 if (Lit->getValue().ugt(Str->getLength())) {
   diag(Loc, "length is bigger then string literal size");
 }
+  } else if (const auto *Ptr = Result.Nodes.getNodeAs("from-ptr")) {
+Expr::EvalResult ConstPtr;
+if (Ptr->EvaluateAsRValue(ConstPtr, Ctx) &&
+((ConstPtr.Val.isInt() && ConstPtr.Val.getInt().isNullValue()) ||
+ (ConstPtr.Val.isLValue() && ConstPtr.Val.isNullPointer( {
+  diag(Loc, "constructing string from nullptr is undefined behaviour");
+}
   }
 }
 


Index: test/clang-tidy/bugprone-string-constructor.cpp
===
--- test/clang-tidy/bugprone-string-constructor.cpp
+++ test/clang-tidy/bugprone-string-constructor.cpp
@@ -9,6 +9,7 @@
 struct basic_string {
   basic_string();
   basic_string(const C*, unsigned int size);
+  basic_string(const C *, const A &allocator = A());
   basic_string(unsigned int size, C c);
 };
 typedef basic_string string;
@@ -45,6 +46,15 @@
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger then string literal size
   std::string q5(kText3,  0x100);
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+  std::string q6(nullptr);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructing string from nullptr is undefined behaviour
+  std::string q7 = 0;
+  // CHECK-MESSAGES: [[@LINE-1]]:20: warning: constructing string from nullptr is undefined behaviour
+}
+
+std::string StringFromZero() {
+  return 0;
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: constructing string from nullptr is undefined behaviour
 }
 
 void Valid() {
@@ -53,4 +63,5 @@
   std::wstring wstr(4, L'x');
   std::string s1("test", 4);
   std::string s2("test", 3);
+  std::string s3("test");
 }
Index: clang-tidy/bugprone/StringConstructorCheck.cpp
===
--- clang-tidy/bugprone/StringConstructorCheck.cpp
+++ clang-tidy/bugprone/StringConstructorCheck.cpp
@@ -100,6 +100,15 @@
integerLiteral().bind("int"))
   .bind("constructor"),
   this);
+
+  // Check the literal string constructor with char pointer.
+  // [i.e. string (const char* s);]
+  Finder->addMatcher(
+  cxxConstructExpr(hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
+   hasArgument(0, expr().bind("from-ptr")),
+   hasArgument(1, unless(hasType(isInteger()
+  .bind("c

[PATCH] D56657: [clang-tidy] bugprone-string-constructor: Catch string from nullptr.

2019-01-16 Thread Clement Courbet via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rCTE351308: [clang-tidy] bugprone-string-constructor: Catch 
string from nullptr. (authored by courbet, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D56657?vs=181985&id=181986#toc

Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D56657

Files:
  clang-tidy/bugprone/StringConstructorCheck.cpp
  test/clang-tidy/bugprone-string-constructor.cpp


Index: test/clang-tidy/bugprone-string-constructor.cpp
===
--- test/clang-tidy/bugprone-string-constructor.cpp
+++ test/clang-tidy/bugprone-string-constructor.cpp
@@ -9,6 +9,7 @@
 struct basic_string {
   basic_string();
   basic_string(const C*, unsigned int size);
+  basic_string(const C *, const A &allocator = A());
   basic_string(unsigned int size, C c);
 };
 typedef basic_string string;
@@ -45,6 +46,15 @@
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger then string 
literal size
   std::string q5(kText3,  0x100);
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+  std::string q6(nullptr);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructing string from nullptr 
is undefined behaviour
+  std::string q7 = 0;
+  // CHECK-MESSAGES: [[@LINE-1]]:20: warning: constructing string from nullptr 
is undefined behaviour
+}
+
+std::string StringFromZero() {
+  return 0;
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: constructing string from nullptr 
is undefined behaviour
 }
 
 void Valid() {
@@ -53,4 +63,5 @@
   std::wstring wstr(4, L'x');
   std::string s1("test", 4);
   std::string s2("test", 3);
+  std::string s3("test");
 }
Index: clang-tidy/bugprone/StringConstructorCheck.cpp
===
--- clang-tidy/bugprone/StringConstructorCheck.cpp
+++ clang-tidy/bugprone/StringConstructorCheck.cpp
@@ -100,6 +100,15 @@
integerLiteral().bind("int"))
   .bind("constructor"),
   this);
+
+  // Check the literal string constructor with char pointer.
+  // [i.e. string (const char* s);]
+  Finder->addMatcher(
+  cxxConstructExpr(hasDeclaration(cxxMethodDecl(hasName("basic_string"))),
+   hasArgument(0, expr().bind("from-ptr")),
+   hasArgument(1, unless(hasType(isInteger()
+  .bind("constructor"),
+  this);
 }
 
 void StringConstructorCheck::check(const MatchFinder::MatchResult &Result) {
@@ -128,6 +137,13 @@
 if (Lit->getValue().ugt(Str->getLength())) {
   diag(Loc, "length is bigger then string literal size");
 }
+  } else if (const auto *Ptr = Result.Nodes.getNodeAs("from-ptr")) {
+Expr::EvalResult ConstPtr;
+if (Ptr->EvaluateAsRValue(ConstPtr, Ctx) &&
+((ConstPtr.Val.isInt() && ConstPtr.Val.getInt().isNullValue()) ||
+ (ConstPtr.Val.isLValue() && ConstPtr.Val.isNullPointer( {
+  diag(Loc, "constructing string from nullptr is undefined behaviour");
+}
   }
 }
 


Index: test/clang-tidy/bugprone-string-constructor.cpp
===
--- test/clang-tidy/bugprone-string-constructor.cpp
+++ test/clang-tidy/bugprone-string-constructor.cpp
@@ -9,6 +9,7 @@
 struct basic_string {
   basic_string();
   basic_string(const C*, unsigned int size);
+  basic_string(const C *, const A &allocator = A());
   basic_string(unsigned int size, C c);
 };
 typedef basic_string string;
@@ -45,6 +46,15 @@
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: length is bigger then string literal size
   std::string q5(kText3,  0x100);
   // CHECK-MESSAGES: [[@LINE-1]]:15: warning: suspicious large length parameter
+  std::string q6(nullptr);
+  // CHECK-MESSAGES: [[@LINE-1]]:15: warning: constructing string from nullptr is undefined behaviour
+  std::string q7 = 0;
+  // CHECK-MESSAGES: [[@LINE-1]]:20: warning: constructing string from nullptr is undefined behaviour
+}
+
+std::string StringFromZero() {
+  return 0;
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: constructing string from nullptr is undefined behaviour
 }
 
 void Valid() {
@@ -53,4 +63,5 @@
   std::wstring wstr(4, L'x');
   std::string s1("test", 4);
   std::string s2("test", 3);
+  std::string s3("test");
 }
Index: clang-tidy/bugprone/StringConstructorCheck.cpp
===
--- clang-tidy/bugprone/StringConstructorCheck.cpp
+++ clang-tidy/bugprone/StringConstructorCheck.cpp
@@ -100,6 +100,15 @@
integerLiteral().bind("int"))
   .bind("constructor"),
   this);
+
+  // Check the literal string constructor with char pointer.
+  // [i.e. string (const char* s);]
+  Finder->addMatcher(
+  cxxConstructExpr(hasDeclaration(cxxMethodDecl(hasName("basic_string")))

[PATCH] D56657: [clang-tidy] bugprone-string-constructor: Catch string from nullptr.

2019-01-16 Thread Clement Courbet via Phabricator via cfe-commits
courbet added a comment.

Thanks.


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D56657



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


[PATCH] D53488: [clang-tidy] Catching narrowing from double to float.

2018-11-05 Thread Clement Courbet via Phabricator via cfe-commits
courbet added inline comments.



Comment at: clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp:155
+  if (!LhsIntegerRange.Contains(IntegerConstant))
+diag(SourceLoc, "narrowing conversion from %0 to %1") << RhsType << 
LhsType;
+  return true;

I think it would be clearer to have something like "narrowing conversion from 
%0 literal to %1"



Comment at: test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp:163
+  int i;
+  while (i) {
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: narrowing conversion from 
'int' to 'bool' [cppcoreguidelines-narrowing-conversions]

I think some people would not like to be warned on this (especially for the 
form `if (!returns_int())`, because the `!` does the cast). What about adding 
options to the check to disable some forms ?



Comment at: test/clang-tidy/cppcoreguidelines-narrowing-conversions.cpp:164
+  while (i) {
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: narrowing conversion from 
'int' to 'bool' [cppcoreguidelines-narrowing-conversions]
+  }

What about providing a fix for this one :
`while (i != 0) {`


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D53488



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


[PATCH] D54830: [ASTMatchers] Add hasSideEffect() matcher.

2018-11-22 Thread Clement Courbet via Phabricator via cfe-commits
courbet created this revision.
courbet added a reviewer: aaron.ballman.
Herald added a subscriber: cfe-commits.

Exposes Expr::HasSideEffects.


Repository:
  rC Clang

https://reviews.llvm.org/D54830

Files:
  docs/LibASTMatchersReference.html
  include/clang/ASTMatchers/ASTMatchers.h
  lib/ASTMatchers/Dynamic/Registry.cpp
  unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp


Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2259,5 +2259,21 @@
 notMatches("int main2() {}", functionDecl(isMain(;
 }
 
+TEST(Matcher, hasSideEffects) {
+  EXPECT_TRUE(matches("void call();"
+  "void f() { call(); }",
+  expr(hasSideEffects(;
+  EXPECT_TRUE(matches("void f(int& a) { a = 0; }", expr(hasSideEffects(;
+  EXPECT_TRUE(
+  matches("void f(volatile int a) { (void)a; }", expr(hasSideEffects(;
+
+  EXPECT_TRUE(notMatches("void call();"
+ "void f() { }",
+ expr(hasSideEffects(;
+  EXPECT_TRUE(
+  notMatches("void f(int& a) { (void)a; }", expr(hasSideEffects(;
+  EXPECT_TRUE(notMatches("void f(int a) { (void)a; }", 
expr(hasSideEffects(;
+}
+
 } // namespace ast_matchers
 } // namespace clang
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -294,6 +294,7 @@
   REGISTER_MATCHER(hasReturnValue);
   REGISTER_MATCHER(hasRHS);
   REGISTER_MATCHER(hasSelector);
+  REGISTER_MATCHER(hasSideEffects);
   REGISTER_MATCHER(hasSingleDecl);
   REGISTER_MATCHER(hasSize);
   REGISTER_MATCHER(hasSizeExpr);
Index: include/clang/ASTMatchers/ASTMatchers.h
===
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -4118,6 +4118,24 @@
  InnerMatcher.matches(*DeclarationStatement, Finder, Builder);
 }
 
+/// \brief Matches expressions with potential side effects.
+///
+/// Given
+/// \code
+///   void f(int& a, int b, volatile int c) {
+/// call();
+/// a = 0;
+/// a;
+/// b;
+/// c;
+///   }
+/// \endcode
+/// expr(hasSideEffects())
+///   matches 'call()', 'a = 0', 'c', but not '0', 'a', 'b'.
+AST_MATCHER(Expr, hasSideEffects) {
+  return Node.HasSideEffects(Finder->getASTContext());
+}
+
 /// Matches the index expression of an array subscript expression.
 ///
 /// Given
Index: docs/LibASTMatchersReference.html
===
--- docs/LibASTMatchersReference.html
+++ docs/LibASTMatchersReference.html
@@ -2806,6 +2806,22 @@
 
 
 
+MatcherExpr>hasSideEffects
+Matches expressions 
with potential side effects.
+
+Given
+  void f(int& a, int b, volatile int c) {
+call();
+a = 0;
+a;
+b;
+c;
+  }
+expr(hasSideEffects())
+  matches 'call()', 'a = 0', 'c', but not '0', 'a', 'b'.
+
+
+
 MatcherExpr>isInstantiationDependent
 Matches 
expressions that are instantiation-dependent even if it is
 neither type- nor value-dependent.


Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2259,5 +2259,21 @@
 notMatches("int main2() {}", functionDecl(isMain(;
 }
 
+TEST(Matcher, hasSideEffects) {
+  EXPECT_TRUE(matches("void call();"
+  "void f() { call(); }",
+  expr(hasSideEffects(;
+  EXPECT_TRUE(matches("void f(int& a) { a = 0; }", expr(hasSideEffects(;
+  EXPECT_TRUE(
+  matches("void f(volatile int a) { (void)a; }", expr(hasSideEffects(;
+
+  EXPECT_TRUE(notMatches("void call();"
+ "void f() { }",
+ expr(hasSideEffects(;
+  EXPECT_TRUE(
+  notMatches("void f(int& a) { (void)a; }", expr(hasSideEffects(;
+  EXPECT_TRUE(notMatches("void f(int a) { (void)a; }", expr(hasSideEffects(;
+}
+
 } // namespace ast_matchers
 } // namespace clang
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -294,6 +294,7 @@
   REGISTER_MATCHER(hasReturnValue);
   REGISTER_MATCHER(hasRHS);
   REGISTER_MATCHER(hasSelector);
+  REGISTER_MATCHER(hasSideEffects);
   REGISTER_MATCHER(hasSingleDecl);
   REGISTER_MATCHER(hasSize);
   REGISTER_MATCHER(hasSizeExpr);
Index: include/clang/ASTMatchers/ASTMatchers.h

[PATCH] D54830: [ASTMatchers] Add hasSideEffect() matcher.

2018-11-22 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 175031.
courbet added a comment.

rebase


Repository:
  rC Clang

https://reviews.llvm.org/D54830

Files:
  docs/LibASTMatchersReference.html
  include/clang/ASTMatchers/ASTMatchers.h
  lib/ASTMatchers/Dynamic/Registry.cpp
  unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp


Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2259,5 +2259,21 @@
 notMatches("int main2() {}", functionDecl(isMain(;
 }
 
+TEST(Matcher, hasSideEffects) {
+  EXPECT_TRUE(matches("void call();"
+  "void f() { call(); }",
+  expr(hasSideEffects(;
+  EXPECT_TRUE(matches("void f(int& a) { a = 0; }", expr(hasSideEffects(;
+  EXPECT_TRUE(
+  matches("void f(volatile int a) { (void)a; }", expr(hasSideEffects(;
+
+  EXPECT_TRUE(notMatches("void call();"
+ "void f() { }",
+ expr(hasSideEffects(;
+  EXPECT_TRUE(
+  notMatches("void f(int& a) { (void)a; }", expr(hasSideEffects(;
+  EXPECT_TRUE(notMatches("void f(int a) { (void)a; }", 
expr(hasSideEffects(;
+}
+
 } // namespace ast_matchers
 } // namespace clang
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -294,6 +294,7 @@
   REGISTER_MATCHER(hasReturnValue);
   REGISTER_MATCHER(hasRHS);
   REGISTER_MATCHER(hasSelector);
+  REGISTER_MATCHER(hasSideEffects);
   REGISTER_MATCHER(hasSingleDecl);
   REGISTER_MATCHER(hasSize);
   REGISTER_MATCHER(hasSizeExpr);
Index: include/clang/ASTMatchers/ASTMatchers.h
===
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -4118,6 +4118,24 @@
  InnerMatcher.matches(*DeclarationStatement, Finder, Builder);
 }
 
+/// \brief Matches expressions with potential side effects.
+///
+/// Given
+/// \code
+///   void f(int& a, int b, volatile int c) {
+/// call();
+/// a = 0;
+/// a;
+/// b;
+/// c;
+///   }
+/// \endcode
+/// expr(hasSideEffects())
+///   matches 'call()', 'a = 0', 'c', but not '0', 'a', 'b'.
+AST_MATCHER(Expr, hasSideEffects) {
+  return Node.HasSideEffects(Finder->getASTContext());
+}
+
 /// Matches the index expression of an array subscript expression.
 ///
 /// Given
Index: docs/LibASTMatchersReference.html
===
--- docs/LibASTMatchersReference.html
+++ docs/LibASTMatchersReference.html
@@ -2817,6 +2817,22 @@
 
 
 
+MatcherExpr>hasSideEffects
+Matches expressions 
with potential side effects.
+
+Given
+  void f(int& a, int b, volatile int c) {
+call();
+a = 0;
+a;
+b;
+c;
+  }
+expr(hasSideEffects())
+  matches 'call()', 'a = 0', 'c', but not '0', 'a', 'b'.
+
+
+
 MatcherExpr>isInstantiationDependent
 Matches 
expressions that are instantiation-dependent even if it is
 neither type- nor value-dependent.


Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2259,5 +2259,21 @@
 notMatches("int main2() {}", functionDecl(isMain(;
 }
 
+TEST(Matcher, hasSideEffects) {
+  EXPECT_TRUE(matches("void call();"
+  "void f() { call(); }",
+  expr(hasSideEffects(;
+  EXPECT_TRUE(matches("void f(int& a) { a = 0; }", expr(hasSideEffects(;
+  EXPECT_TRUE(
+  matches("void f(volatile int a) { (void)a; }", expr(hasSideEffects(;
+
+  EXPECT_TRUE(notMatches("void call();"
+ "void f() { }",
+ expr(hasSideEffects(;
+  EXPECT_TRUE(
+  notMatches("void f(int& a) { (void)a; }", expr(hasSideEffects(;
+  EXPECT_TRUE(notMatches("void f(int a) { (void)a; }", expr(hasSideEffects(;
+}
+
 } // namespace ast_matchers
 } // namespace clang
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -294,6 +294,7 @@
   REGISTER_MATCHER(hasReturnValue);
   REGISTER_MATCHER(hasRHS);
   REGISTER_MATCHER(hasSelector);
+  REGISTER_MATCHER(hasSideEffects);
   REGISTER_MATCHER(hasSingleDecl);
   REGISTER_MATCHER(hasSize);
   REGISTER_MATCHER(hasSizeExpr);
Index: include/clang/ASTMatchers/ASTMatchers.h
===
--- include/clang/ASTMatchers/ASTMatchers.h
+++ incl

[PATCH] D54830: [ASTMatchers] Add hasSideEffect() matcher.

2018-11-22 Thread Clement Courbet via Phabricator via cfe-commits
courbet marked an inline comment as done.
courbet added a comment.

Thanks.


Repository:
  rC Clang

https://reviews.llvm.org/D54830



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


[PATCH] D54830: [ASTMatchers] Add hasSideEffect() matcher.

2018-11-22 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 175044.
courbet added a comment.

address comment


Repository:
  rC Clang

https://reviews.llvm.org/D54830

Files:
  docs/LibASTMatchersReference.html
  include/clang/ASTMatchers/ASTMatchers.h
  lib/ASTMatchers/Dynamic/Registry.cpp
  unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp


Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2259,5 +2259,21 @@
 notMatches("int main2() {}", functionDecl(isMain(;
 }
 
+TEST(Matcher, hasSideEffects) {
+  EXPECT_TRUE(matches("void call();"
+  "void f() { call(); }",
+  expr(hasSideEffects(;
+  EXPECT_TRUE(matches("void f(int& a) { a = 0; }", expr(hasSideEffects(;
+  EXPECT_TRUE(
+  matches("void f(volatile int a) { (void)a; }", expr(hasSideEffects(;
+
+  EXPECT_TRUE(notMatches("void call();"
+ "void f() { }",
+ expr(hasSideEffects(;
+  EXPECT_TRUE(
+  notMatches("void f(int& a) { (void)a; }", expr(hasSideEffects(;
+  EXPECT_TRUE(notMatches("void f(int a) { (void)a; }", 
expr(hasSideEffects(;
+}
+
 } // namespace ast_matchers
 } // namespace clang
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -294,6 +294,7 @@
   REGISTER_MATCHER(hasReturnValue);
   REGISTER_MATCHER(hasRHS);
   REGISTER_MATCHER(hasSelector);
+  REGISTER_MATCHER(hasSideEffects);
   REGISTER_MATCHER(hasSingleDecl);
   REGISTER_MATCHER(hasSize);
   REGISTER_MATCHER(hasSizeExpr);
Index: include/clang/ASTMatchers/ASTMatchers.h
===
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -4118,6 +4118,26 @@
  InnerMatcher.matches(*DeclarationStatement, Finder, Builder);
 }
 
+/// \brief Matches expressions with potential side effects other than producing
+/// a value, such as a calling a function, throwing an exception, or reading a
+/// volatile variable.
+///
+/// Given
+/// \code
+///   void f(int& a, int b, volatile int c) {
+/// call();
+/// a = 0;
+/// a;
+/// b;
+/// c;
+///   }
+/// \endcode
+/// expr(hasSideEffects())
+///   matches 'call()', 'a = 0', 'c', but not '0', 'a', 'b'.
+AST_MATCHER(Expr, hasSideEffects) {
+  return Node.HasSideEffects(Finder->getASTContext());
+}
+
 /// Matches the index expression of an array subscript expression.
 ///
 /// Given
Index: docs/LibASTMatchersReference.html
===
--- docs/LibASTMatchersReference.html
+++ docs/LibASTMatchersReference.html
@@ -2817,6 +2817,24 @@
 
 
 
+MatcherExpr>hasSideEffects
+Matches expressions 
with potential side effects other than producing
+a value, such as a calling a function, throwing an exception, or reading a
+volatile variable.
+
+Given
+  void f(int& a, int b, volatile int c) {
+call();
+a = 0;
+a;
+b;
+c;
+  }
+expr(hasSideEffects())
+  matches 'call()', 'a = 0', 'c', but not '0', 'a', 'b'.
+
+
+
 MatcherExpr>isInstantiationDependent
 Matches 
expressions that are instantiation-dependent even if it is
 neither type- nor value-dependent.


Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2259,5 +2259,21 @@
 notMatches("int main2() {}", functionDecl(isMain(;
 }
 
+TEST(Matcher, hasSideEffects) {
+  EXPECT_TRUE(matches("void call();"
+  "void f() { call(); }",
+  expr(hasSideEffects(;
+  EXPECT_TRUE(matches("void f(int& a) { a = 0; }", expr(hasSideEffects(;
+  EXPECT_TRUE(
+  matches("void f(volatile int a) { (void)a; }", expr(hasSideEffects(;
+
+  EXPECT_TRUE(notMatches("void call();"
+ "void f() { }",
+ expr(hasSideEffects(;
+  EXPECT_TRUE(
+  notMatches("void f(int& a) { (void)a; }", expr(hasSideEffects(;
+  EXPECT_TRUE(notMatches("void f(int a) { (void)a; }", expr(hasSideEffects(;
+}
+
 } // namespace ast_matchers
 } // namespace clang
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -294,6 +294,7 @@
   REGISTER_MATCHER(hasReturnValue);
   REGISTER_MATCHER(hasRHS);
   REGISTER_MATCHER(hasSelector);
+  REGISTER_MATCHER(hasSideEffects);
   REGISTER_MATCHE

[PATCH] D54830: [ASTMatchers] Add hasSideEffect() matcher.

2018-11-22 Thread Clement Courbet via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC347462: [ASTMatchers] Add hasSideEffect() matcher. (authored 
by courbet, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D54830?vs=175044&id=175045#toc

Repository:
  rC Clang

https://reviews.llvm.org/D54830

Files:
  docs/LibASTMatchersReference.html
  include/clang/ASTMatchers/ASTMatchers.h
  lib/ASTMatchers/Dynamic/Registry.cpp
  unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp


Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -294,6 +294,7 @@
   REGISTER_MATCHER(hasReturnValue);
   REGISTER_MATCHER(hasRHS);
   REGISTER_MATCHER(hasSelector);
+  REGISTER_MATCHER(hasSideEffects);
   REGISTER_MATCHER(hasSingleDecl);
   REGISTER_MATCHER(hasSize);
   REGISTER_MATCHER(hasSizeExpr);
Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2259,5 +2259,21 @@
 notMatches("int main2() {}", functionDecl(isMain(;
 }
 
+TEST(Matcher, hasSideEffects) {
+  EXPECT_TRUE(matches("void call();"
+  "void f() { call(); }",
+  expr(hasSideEffects(;
+  EXPECT_TRUE(matches("void f(int& a) { a = 0; }", expr(hasSideEffects(;
+  EXPECT_TRUE(
+  matches("void f(volatile int a) { (void)a; }", expr(hasSideEffects(;
+
+  EXPECT_TRUE(notMatches("void call();"
+ "void f() { }",
+ expr(hasSideEffects(;
+  EXPECT_TRUE(
+  notMatches("void f(int& a) { (void)a; }", expr(hasSideEffects(;
+  EXPECT_TRUE(notMatches("void f(int a) { (void)a; }", 
expr(hasSideEffects(;
+}
+
 } // namespace ast_matchers
 } // namespace clang
Index: docs/LibASTMatchersReference.html
===
--- docs/LibASTMatchersReference.html
+++ docs/LibASTMatchersReference.html
@@ -2817,6 +2817,24 @@
 
 
 
+MatcherExpr>hasSideEffects
+Matches expressions 
with potential side effects other than producing
+a value, such as a calling a function, throwing an exception, or reading a
+volatile variable.
+
+Given
+  void f(int& a, int b, volatile int c) {
+call();
+a = 0;
+a;
+b;
+c;
+  }
+expr(hasSideEffects())
+  matches 'call()', 'a = 0', 'c', but not '0', 'a', 'b'.
+
+
+
 MatcherExpr>isInstantiationDependent
 Matches 
expressions that are instantiation-dependent even if it is
 neither type- nor value-dependent.
Index: include/clang/ASTMatchers/ASTMatchers.h
===
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -4118,6 +4118,26 @@
  InnerMatcher.matches(*DeclarationStatement, Finder, Builder);
 }
 
+/// \brief Matches expressions with potential side effects other than producing
+/// a value, such as a calling a function, throwing an exception, or reading a
+/// volatile variable.
+///
+/// Given
+/// \code
+///   void f(int& a, int b, volatile int c) {
+/// call();
+/// a = 0;
+/// a;
+/// b;
+/// c;
+///   }
+/// \endcode
+/// expr(hasSideEffects())
+///   matches 'call()', 'a = 0', 'c', but not '0', 'a', 'b'.
+AST_MATCHER(Expr, hasSideEffects) {
+  return Node.HasSideEffects(Finder->getASTContext());
+}
+
 /// Matches the index expression of an array subscript expression.
 ///
 /// Given


Index: lib/ASTMatchers/Dynamic/Registry.cpp
===
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -294,6 +294,7 @@
   REGISTER_MATCHER(hasReturnValue);
   REGISTER_MATCHER(hasRHS);
   REGISTER_MATCHER(hasSelector);
+  REGISTER_MATCHER(hasSideEffects);
   REGISTER_MATCHER(hasSingleDecl);
   REGISTER_MATCHER(hasSize);
   REGISTER_MATCHER(hasSizeExpr);
Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===
--- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2259,5 +2259,21 @@
 notMatches("int main2() {}", functionDecl(isMain(;
 }
 
+TEST(Matcher, hasSideEffects) {
+  EXPECT_TRUE(matches("void call();"
+  "void f() { call(); }",
+  expr(hasSideEffects(;
+  EXPECT_TRUE(matches("void f(int& a) { a = 0; }", expr(hasSideEffects(;
+  EXPECT_TRUE(
+  matches("void f(volatile int a) { (void)a; }", expr(hasSideEffects(;
+
+  EXPECT_TRUE(notMatches("void call();"
+ "void f() { }",
+

[PATCH] D54903: [WIP][Sema] Improve static_assert diagnostics.

2018-11-26 Thread Clement Courbet via Phabricator via cfe-commits
courbet created this revision.
Herald added a subscriber: cfe-commits.

`static_assert(std::is_same::value, "message")` now prints the
value of U and V.


Repository:
  rC Clang

https://reviews.llvm.org/D54903

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
@@ -68,3 +68,27 @@
 };
 
 static_assert(first_trait::value && second_trait::value, "message"); // 
expected-error{{static_assert failed due to requirement 
'second_trait::value' "message"}}
+
+namespace std {
+
+template 
+struct is_same {
+  static const bool value = false;
+};
+
+template 
+struct is_same {
+  static const bool value = true;
+};
+
+} // namespace std
+
+struct ExampleTypes {
+  using T = int;
+  using U = float;
+};
+
+template 
+class StaticAssertIsSame {
+  static_assert(std::is_same::value, 
"message"); // expected-error{{static_assert failed due to requirement 'int and 
float are the same type' "message"}}
+};
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,6 +3052,48 @@
   return Cond;
 }
 
+// Pretty prints std::is_same as 'U and V are the same types'.
+static void
+prettyPrintFailedIsSameCondition(llvm::raw_string_ostream &OS,
+ const RecordDecl *Decl,
+ const PrintingPolicy &PrintPolicy) {
+  const auto *const TmplDecl = dyn_cast(Decl);
+  assert(TmplDecl &&
+ "std::is_same should be a ClassTemplateSpecializationDecl");
+  const auto &Args = TmplDecl->getTemplateArgs();
+  assert(Args.size() == 2 && "std::is_same should have 2 template parameters");
+  Args.get(0).getAsType().print(OS, PrintPolicy);
+  OS << " and ";
+  Args.get(1).getAsType().print(OS, PrintPolicy);
+  OS << " are the same type";
+}
+
+// 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 *const FailedCond,
+  const PrintingPolicy &PrintPolicy) {
+  if (const auto *const DR = dyn_cast(FailedCond)) {
+const auto *const Var = dyn_cast(DR->getDecl());
+if (Var && Var->isStaticDataMember() && Var->getName() == "value") {
+  const NestedNameSpecifier *const Qualifier = Var->getQualifier();
+  // This might be an std type trait.
+  const auto *const Record = Qualifier->getAsRecordDecl();
+  const auto *const Parent = Qualifier->getPrefix();
+  if (Parent && Parent->getPrefix() &&
+  Parent->getPrefix()->getKind() == NestedNameSpecifier::Global &&
+  Parent->getAsNamespace() &&
+  Parent->getAsNamespace()->getName() == "std" &&
+  Record->getName() == "is_same") {
+prettyPrintFailedIsSameCondition(OS, Record, PrintPolicy);
+return;
+  }
+}
+  }
+  FailedCond->printPretty(OS, nullptr, PrintPolicy);
+}
+
 std::pair
 Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
   Cond = lookThroughRangesV3Condition(PP, Cond);
@@ -3093,7 +3135,7 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-FailedCond->printPretty(Out, nullptr, getPrintingPolicy());
+prettyPrintFailedBooleanCondition(Out, FailedCond, getPrintingPolicy());
   }
   return { FailedCond, Description };
 }


Index: test/SemaCXX/static-assert.cpp
===
--- test/SemaCXX/static-assert.cpp
+++ test/SemaCXX/static-assert.cpp
@@ -68,3 +68,27 @@
 };
 
 static_assert(first_trait::value && second_trait::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait::value' "message"}}
+
+namespace std {
+
+template 
+struct is_same {
+  static const bool value = false;
+};
+
+template 
+struct is_same {
+  static const bool value = true;
+};
+
+} // namespace std
+
+struct ExampleTypes {
+  using T = int;
+  using U = float;
+};
+
+template 
+class StaticAssertIsSame {
+  static_assert(std::is_same::value, "message"); // expected-error{{static_assert failed due to requirement 'int and float are the same type' "message"}}
+};
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,6 +3052,48 @@
   return Cond;
 }
 
+// Pretty prints std::is_same as 'U and V are the same types'.
+static void
+prettyPrintFailedIsSameCondition(llvm::raw_string_ostream &OS,
+ const RecordDecl *Decl,
+ const PrintingPolicy &PrintPolicy) {
+  const auto *const TmplDecl = dyn_cast(Decl);
+  assert(TmplDecl &&
+ "std::is_same should be 

[PATCH] D54903: [WIP][Sema] Improve static_assert diagnostics.

2018-11-27 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 175465.
courbet added a comment.

Handle all std type traits.


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903

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
@@ -68,3 +68,44 @@
 };
 
 static_assert(first_trait::value && second_trait::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait::value' "message"}}
+
+namespace std {
+
+template 
+struct integral_constant {
+  static const Tp value = v;
+  typedef Tp value_type;
+  typedef integral_constant type;
+};
+
+template 
+const Tp integral_constant::value;
+
+typedef integral_constant true_type;
+typedef integral_constant false_type;
+
+template 
+struct is_const : public false_type {};
+template 
+struct is_const : public true_type {};
+
+// We do not define is_same in terms of integral_constant to check that both implementations are supported.
+template 
+struct is_same {
+  static const bool value = false;
+};
+
+template 
+struct is_same {
+  static const bool value = true;
+};
+
+} // namespace std
+
+struct ExampleTypes {
+  using T = int;
+  using U = float;
+};
+
+static_assert(std::is_same::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_same::value' "message"}}
+static_assert(std::is_const::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_const::value' "message"}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,6 +3052,75 @@
   return Cond;
 }
 
+// Returns true if `Name` is the name of an std type trait.
+static bool isTypeTraitName(const llvm::StringRef RecordName) {
+  return
+#define TYPE_TRAIT_1(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_2(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_N(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#include "clang/Basic/TokenKinds.def"
+#undef TYPE_TRAIT_1
+#undef TYPE_TRAIT_2
+#undef TYPE_TRAIT_N
+  false;
+}
+
+// If `Record` is a type trait, pretty prints the condition with actual types
+// and returns true.
+static bool prettyPrintTypeTrait(const NestedNameSpecifier *const NNS,
+ llvm::raw_string_ostream &OS,
+ const PrintingPolicy &PrintPolicy) {
+  // We are looking for a type.
+  if (NNS == nullptr || NNS->getKind() != NestedNameSpecifier::TypeSpec)
+return false;
+  // In namespace "::std".
+  const NestedNameSpecifier *const Parent = NNS->getPrefix();
+  if (Parent == nullptr ||
+  Parent->getKind() != NestedNameSpecifier::Namespace ||
+  Parent->getAsNamespace()->getName() != "std")
+return false;
+  const NestedNameSpecifier *const GrandParent = Parent->getPrefix();
+  if (!(GrandParent == nullptr ||
+GrandParent->getKind() == NestedNameSpecifier::Global))
+return false;
+  // Now check whether the record name is one of the known type traits.
+  const RecordDecl *const Record = NNS->getAsRecordDecl();
+  if (!isTypeTraitName(Record->getName()))
+return false;
+  // Print the type trait with resolved template parameters.
+  const auto *const TmplDecl =
+  dyn_cast(Record);
+  assert(TmplDecl &&
+ "std type_traits should be ClassTemplateSpecializationDecl");
+  OS << "std::" << Record->getName() << "<";
+  auto Args = TmplDecl->getTemplateArgs().asArray();
+  Args.front().print(PrintPolicy, OS);
+  for (const auto &Arg : Args.drop_front()) {
+OS << ", ";
+Arg.print(PrintPolicy, OS);
+  }
+  OS << ">";
+  return true;
+}
+
+// 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 *const FailedCond,
+  const PrintingPolicy &PrintPolicy) {
+  if (const auto *const DR = dyn_cast(FailedCond)) {
+const auto *const Var = dyn_cast(DR->getDecl());
+// This might be `std::some_type_trait::value`.
+if (Var && Var->isStaticDataMember() && Var->getName() == "value" &&
+prettyPrintTypeTrait(DR->getQualifier(), OS, PrintPolicy)) {
+  OS << "::value";
+  return;
+}
+  }
+  FailedCond->printPretty(OS, nullptr, PrintPolicy);
+}
+
 std::pair
 Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
   Cond = lookThroughRangesV3Condition(PP, Cond);
@@ -3093,7 +3162,7 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-FailedCond->printPretty(Out, nullptr, getPrintingPolicy());
+prettyPrin

[PATCH] D54903: [Sema] Improve static_assert diagnostics.

2018-11-28 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 175638.
courbet marked 5 inline comments as done.
courbet edited the summary of this revision.
courbet added a comment.

Address Aaron's comments.


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903

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
@@ -68,3 +68,44 @@
 };
 
 static_assert(first_trait::value && second_trait::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait::value' "message"}}
+
+namespace std {
+
+template 
+struct integral_constant {
+  static const Tp value = v;
+  typedef Tp value_type;
+  typedef integral_constant type;
+};
+
+template 
+const Tp integral_constant::value;
+
+typedef integral_constant true_type;
+typedef integral_constant false_type;
+
+template 
+struct is_const : public false_type {};
+template 
+struct is_const : public true_type {};
+
+// We do not define is_same in terms of integral_constant to check that both implementations are supported.
+template 
+struct is_same {
+  static const bool value = false;
+};
+
+template 
+struct is_same {
+  static const bool value = true;
+};
+
+} // namespace std
+
+struct ExampleTypes {
+  using T = int;
+  using U = float;
+};
+
+static_assert(std::is_same::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_same::value' "message"}}
+static_assert(std::is_const::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_const::value' "message"}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,6 +3052,67 @@
   return Cond;
 }
 
+// Returns true if `Name` is the name of an std type trait.
+static bool isTypeTraitName(const llvm::StringRef RecordName) {
+  return
+#define TYPE_TRAIT_1(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_2(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_N(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#include "clang/Basic/TokenKinds.def"
+#undef TYPE_TRAIT_1
+#undef TYPE_TRAIT_2
+#undef TYPE_TRAIT_N
+  false;
+}
+
+// If `Record` is a type trait, pretty prints the condition with actual types
+// and returns true.
+static bool prettyPrintTypeTrait(const NestedNameSpecifier *NNS,
+ llvm::raw_string_ostream &OS,
+ const PrintingPolicy &PrintPolicy) {
+  // We are looking for a type.
+  if (NNS == nullptr || NNS->getKind() != NestedNameSpecifier::TypeSpec)
+return false;
+  const RecordDecl * Record = NNS->getAsRecordDecl();
+  // In namespace "::std".
+  if (!Record->isInStdNamespace())
+return false;
+  // Now check whether the record name is one of the known type traits.
+  if (!isTypeTraitName(Record->getName()))
+return false;
+  // Print the type trait with resolved template parameters.
+  const auto * TmplDecl = dyn_cast(Record);
+  assert(TmplDecl &&
+ "std type_traits should be ClassTemplateSpecializationDecl");
+  OS << "std::" << Record->getName() << "<";
+  ArrayRef Args = TmplDecl->getTemplateArgs().asArray();
+  Args.front().print(PrintPolicy, OS);
+  for (const auto &Arg : Args.drop_front()) {
+OS << ", ";
+Arg.print(PrintPolicy, OS);
+  }
+  OS << ">";
+  return true;
+}
+
+// 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 &PrintPolicy) {
+  if (const auto * DR = dyn_cast(FailedCond)) {
+const auto *Var = dyn_cast(DR->getDecl());
+// This might be `std::some_type_trait::value`.
+if (Var && Var->isStaticDataMember() && Var->getName() == "value" &&
+prettyPrintTypeTrait(DR->getQualifier(), OS, PrintPolicy)) {
+  OS << "::value";
+  return;
+}
+  }
+  FailedCond->printPretty(OS, nullptr, PrintPolicy);
+}
+
 std::pair
 Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
   Cond = lookThroughRangesV3Condition(PP, Cond);
@@ -3093,7 +3154,7 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-FailedCond->printPretty(Out, nullptr, getPrintingPolicy());
+prettyPrintFailedBooleanCondition(Out, FailedCond, getPrintingPolicy());
   }
   return { FailedCond, Description };
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D54903: [Sema] Improve static_assert diagnostics.

2018-11-28 Thread Clement Courbet via Phabricator via cfe-commits
courbet marked an inline comment as done.
courbet added a comment.

Thanks for the comments.




Comment at: lib/Sema/SemaTemplate.cpp:3070
+// and returns true.
+static bool prettyPrintTypeTrait(const NestedNameSpecifier *const NNS,
+ llvm::raw_string_ostream &OS,

aaron.ballman wrote:
> No need for the pointer itself to be `const` qualified -- drop the top-level 
> `const` qualifier (here and elsewhere).
constness prevents me from accidentally reassigning the variable. But I won't 
fight over it :)



Comment at: lib/Sema/SemaTemplate.cpp:3115
+// This might be `std::some_type_trait::value`.
+if (Var && Var->isStaticDataMember() && Var->getName() == "value" &&
+prettyPrintTypeTrait(DR->getQualifier(), OS, PrintPolicy)) {

aaron.ballman wrote:
> You can also check `Var->isInStdNamespace()` here to simplify the logic above.
Thanks for the pointer ! I was looking for something like this :)
I still have to check this on the qualifier and not the variable though, but 
that does make the logic a lot simpler.



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

Quuxplusone wrote:
> I would like to see some more realistic test cases. I suggest this test case 
> for example:
> ```
> struct BI_tag {};
> struct RAI_tag : BI_tag {};
> struct MyIterator {
> using tag = BI_tag;
> };
> struct MyContainer {
> using iterator = MyIterator;
> };
> template
> void foo() {
> static_assert(std::is_base_of_v Container::iterator::tag>);
> }
> ```
> This is an example where as a programmer I would not want to see //only// 
> `failed due to requirement std::is_base_of_v` — that doesn't 
> help me solve the issue. OTOH, since every diagnostic includes a cursor to 
> the exact text of the `static_assert` already, I think it's fair to say that 
> the current diagnostic message is redundant, and therefore it's okay to 
> replace it (as you propose to do) with something that is not redundant.
> I think it's fair to say that the current diagnostic message is redundant, 
> and therefore it's okay to replace it (as you propose to do) with something 
> that is not redundant.

Yes, the proposal here might not be the *best* possible diagnostic for all 
cases, but it's already a huge improvement on the existing one, and solves a 
significant proportion of use cases.

Here, the programmer will see:
```
test.cc:13:5: error: static_assert failed due to requirement 
'std::is_base_of::value'
static_assert(std::is_base_of::value);
^ 
~~
```
which I think is a reasonable help for debugging.



Repository:
  rC Clang

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

https://reviews.llvm.org/D54903



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


[PATCH] D54903: [Sema] Improve static_assert diagnostics.

2018-11-28 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 175667.
courbet added a comment.

clang-formant patch


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903

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
@@ -68,3 +68,44 @@
 };
 
 static_assert(first_trait::value && second_trait::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait::value' "message"}}
+
+namespace std {
+
+template 
+struct integral_constant {
+  static const Tp value = v;
+  typedef Tp value_type;
+  typedef integral_constant type;
+};
+
+template 
+const Tp integral_constant::value;
+
+typedef integral_constant true_type;
+typedef integral_constant false_type;
+
+template 
+struct is_const : public false_type {};
+template 
+struct is_const : public true_type {};
+
+// We do not define is_same in terms of integral_constant to check that both implementations are supported.
+template 
+struct is_same {
+  static const bool value = false;
+};
+
+template 
+struct is_same {
+  static const bool value = true;
+};
+
+} // namespace std
+
+struct ExampleTypes {
+  using T = int;
+  using U = float;
+};
+
+static_assert(std::is_same::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_same::value' "message"}}
+static_assert(std::is_const::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_const::value' "message"}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,6 +3052,67 @@
   return Cond;
 }
 
+// Returns true if `Name` is the name of an std type trait.
+static bool isTypeTraitName(const llvm::StringRef RecordName) {
+  return
+#define TYPE_TRAIT_1(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_2(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_N(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#include "clang/Basic/TokenKinds.def"
+#undef TYPE_TRAIT_1
+#undef TYPE_TRAIT_2
+#undef TYPE_TRAIT_N
+  false;
+}
+
+// If `Record` is a type trait, pretty prints the condition with actual types
+// and returns true.
+static bool prettyPrintTypeTrait(const NestedNameSpecifier *NNS,
+ llvm::raw_string_ostream &OS,
+ const PrintingPolicy &PrintPolicy) {
+  // We are looking for a type.
+  if (NNS == nullptr || NNS->getKind() != NestedNameSpecifier::TypeSpec)
+return false;
+  const RecordDecl *Record = NNS->getAsRecordDecl();
+  // In namespace "::std".
+  if (!Record->isInStdNamespace())
+return false;
+  // Now check whether the record name is one of the known type traits.
+  if (!isTypeTraitName(Record->getName()))
+return false;
+  // Print the type trait with resolved template parameters.
+  const auto *TmplDecl = dyn_cast(Record);
+  assert(TmplDecl &&
+ "std type_traits should be ClassTemplateSpecializationDecl");
+  OS << "std::" << Record->getName() << "<";
+  ArrayRef Args = TmplDecl->getTemplateArgs().asArray();
+  Args.front().print(PrintPolicy, OS);
+  for (const auto &Arg : Args.drop_front()) {
+OS << ", ";
+Arg.print(PrintPolicy, OS);
+  }
+  OS << ">";
+  return true;
+}
+
+// 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 &PrintPolicy) {
+  if (const auto *DR = dyn_cast(FailedCond)) {
+const auto *Var = dyn_cast(DR->getDecl());
+// This might be `std::some_type_trait::value`.
+if (Var && Var->isStaticDataMember() && Var->getName() == "value" &&
+prettyPrintTypeTrait(DR->getQualifier(), OS, PrintPolicy)) {
+  OS << "::value";
+  return;
+}
+  }
+  FailedCond->printPretty(OS, nullptr, PrintPolicy);
+}
+
 std::pair
 Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
   Cond = lookThroughRangesV3Condition(PP, Cond);
@@ -3093,7 +3154,7 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-FailedCond->printPretty(Out, nullptr, getPrintingPolicy());
+prettyPrintFailedBooleanCondition(Out, FailedCond, getPrintingPolicy());
   }
   return { FailedCond, Description };
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D54903: [Sema] Improve static_assert diagnostics.

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

harden against null getAsRecordDecl().


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903

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
@@ -68,3 +68,44 @@
 };
 
 static_assert(first_trait::value && second_trait::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait::value' "message"}}
+
+namespace std {
+
+template 
+struct integral_constant {
+  static const Tp value = v;
+  typedef Tp value_type;
+  typedef integral_constant type;
+};
+
+template 
+const Tp integral_constant::value;
+
+typedef integral_constant true_type;
+typedef integral_constant false_type;
+
+template 
+struct is_const : public false_type {};
+template 
+struct is_const : public true_type {};
+
+// We do not define is_same in terms of integral_constant to check that both implementations are supported.
+template 
+struct is_same {
+  static const bool value = false;
+};
+
+template 
+struct is_same {
+  static const bool value = true;
+};
+
+} // namespace std
+
+struct ExampleTypes {
+  using T = int;
+  using U = float;
+};
+
+static_assert(std::is_same::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_same::value' "message"}}
+static_assert(std::is_const::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_const::value' "message"}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,6 +3052,69 @@
   return Cond;
 }
 
+// Returns true if `Name` is the name of an std type trait.
+static bool isTypeTraitName(const llvm::StringRef RecordName) {
+  return
+#define TYPE_TRAIT_1(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_2(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_N(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#include "clang/Basic/TokenKinds.def"
+#undef TYPE_TRAIT_1
+#undef TYPE_TRAIT_2
+#undef TYPE_TRAIT_N
+  false;
+}
+
+// If `Record` is a type trait, pretty prints the condition with actual types
+// and returns true.
+static bool prettyPrintTypeTrait(const NestedNameSpecifier *NNS,
+ llvm::raw_string_ostream &OS,
+ const PrintingPolicy &PrintPolicy) {
+  // We are looking for a type.
+  if (NNS == nullptr || NNS->getKind() != NestedNameSpecifier::TypeSpec)
+return false;
+  const RecordDecl *Record = NNS->getAsRecordDecl();
+  if (Record == nullptr)
+return false;
+  // In namespace "::std".
+  if (!Record->isInStdNamespace())
+return false;
+  // Now check whether the record name is one of the known type traits.
+  if (!isTypeTraitName(Record->getName()))
+return false;
+  // Print the type trait with resolved template parameters.
+  const auto *TmplDecl = dyn_cast(Record);
+  assert(TmplDecl &&
+ "std type_traits should be ClassTemplateSpecializationDecl");
+  OS << "std::" << Record->getName() << "<";
+  ArrayRef Args = TmplDecl->getTemplateArgs().asArray();
+  Args.front().print(PrintPolicy, OS);
+  for (const auto &Arg : Args.drop_front()) {
+OS << ", ";
+Arg.print(PrintPolicy, OS);
+  }
+  OS << ">";
+  return true;
+}
+
+// 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 &PrintPolicy) {
+  if (const auto *DR = dyn_cast(FailedCond)) {
+const auto *Var = dyn_cast(DR->getDecl());
+// This might be `std::some_type_trait::value`.
+if (Var && Var->isStaticDataMember() && Var->getName() == "value" &&
+prettyPrintTypeTrait(DR->getQualifier(), OS, PrintPolicy)) {
+  OS << "::value";
+  return;
+}
+  }
+  FailedCond->printPretty(OS, nullptr, PrintPolicy);
+}
+
 std::pair
 Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
   Cond = lookThroughRangesV3Condition(PP, Cond);
@@ -3093,7 +3156,7 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-FailedCond->printPretty(Out, nullptr, getPrintingPolicy());
+prettyPrintFailedBooleanCondition(Out, FailedCond, getPrintingPolicy());
   }
   return { FailedCond, Description };
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D54903: [Sema] Improve static_assert diagnostics.

2018-11-28 Thread Clement Courbet via Phabricator via cfe-commits
courbet added inline comments.



Comment at: lib/Sema/SemaTemplate.cpp:3076
+return false;
+  const RecordDecl * Record = NNS->getAsRecordDecl();
+  // In namespace "::std".

aaron.ballman wrote:
> Formatting is incorrect here; you should run the patch through clang-format.
> 
> Can `getAsRecordDecl()` return null even when looking for a type out of a 
> NNS? If so, you should assert/test for that.
Good point, I've added a test.


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903



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


[PATCH] D54903: [Sema] Improve static_assert diagnostics.

2018-11-28 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 175669.
courbet added a comment.

fix variable name in comment


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903

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
@@ -68,3 +68,44 @@
 };
 
 static_assert(first_trait::value && second_trait::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait::value' "message"}}
+
+namespace std {
+
+template 
+struct integral_constant {
+  static const Tp value = v;
+  typedef Tp value_type;
+  typedef integral_constant type;
+};
+
+template 
+const Tp integral_constant::value;
+
+typedef integral_constant true_type;
+typedef integral_constant false_type;
+
+template 
+struct is_const : public false_type {};
+template 
+struct is_const : public true_type {};
+
+// We do not define is_same in terms of integral_constant to check that both implementations are supported.
+template 
+struct is_same {
+  static const bool value = false;
+};
+
+template 
+struct is_same {
+  static const bool value = true;
+};
+
+} // namespace std
+
+struct ExampleTypes {
+  using T = int;
+  using U = float;
+};
+
+static_assert(std::is_same::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_same::value' "message"}}
+static_assert(std::is_const::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_const::value' "message"}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,6 +3052,69 @@
   return Cond;
 }
 
+// Returns true if `RecordName` is the name of an std type trait.
+static bool isTypeTraitName(const llvm::StringRef RecordName) {
+  return
+#define TYPE_TRAIT_1(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_2(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_N(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#include "clang/Basic/TokenKinds.def"
+#undef TYPE_TRAIT_1
+#undef TYPE_TRAIT_2
+#undef TYPE_TRAIT_N
+  false;
+}
+
+// If `Record` is a type trait, pretty prints the condition with actual types
+// and returns true.
+static bool prettyPrintTypeTrait(const NestedNameSpecifier *NNS,
+ llvm::raw_string_ostream &OS,
+ const PrintingPolicy &PrintPolicy) {
+  // We are looking for a type.
+  if (NNS == nullptr || NNS->getKind() != NestedNameSpecifier::TypeSpec)
+return false;
+  const RecordDecl *Record = NNS->getAsRecordDecl();
+  if (Record == nullptr)
+return false;
+  // In namespace "::std".
+  if (!Record->isInStdNamespace())
+return false;
+  // Now check whether the record name is one of the known type traits.
+  if (!isTypeTraitName(Record->getName()))
+return false;
+  // Print the type trait with resolved template parameters.
+  const auto *TmplDecl = dyn_cast(Record);
+  assert(TmplDecl &&
+ "std type_traits should be ClassTemplateSpecializationDecl");
+  OS << "std::" << Record->getName() << "<";
+  ArrayRef Args = TmplDecl->getTemplateArgs().asArray();
+  Args.front().print(PrintPolicy, OS);
+  for (const auto &Arg : Args.drop_front()) {
+OS << ", ";
+Arg.print(PrintPolicy, OS);
+  }
+  OS << ">";
+  return true;
+}
+
+// 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 &PrintPolicy) {
+  if (const auto *DR = dyn_cast(FailedCond)) {
+const auto *Var = dyn_cast(DR->getDecl());
+// This might be `std::some_type_trait::value`.
+if (Var && Var->isStaticDataMember() && Var->getName() == "value" &&
+prettyPrintTypeTrait(DR->getQualifier(), OS, PrintPolicy)) {
+  OS << "::value";
+  return;
+}
+  }
+  FailedCond->printPretty(OS, nullptr, PrintPolicy);
+}
+
 std::pair
 Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
   Cond = lookThroughRangesV3Condition(PP, Cond);
@@ -3093,7 +3156,7 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-FailedCond->printPretty(Out, nullptr, getPrintingPolicy());
+prettyPrintFailedBooleanCondition(Out, FailedCond, getPrintingPolicy());
   }
   return { FailedCond, Description };
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D54903: [Sema] Improve static_assert diagnostics.

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



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

Quuxplusone wrote:
> aaron.ballman wrote:
> > courbet wrote:
> > > Quuxplusone wrote:
> > > > I would like to see some more realistic test cases. I suggest this test 
> > > > case for example:
> > > > ```
> > > > struct BI_tag {};
> > > > struct RAI_tag : BI_tag {};
> > > > struct MyIterator {
> > > > using tag = BI_tag;
> > > > };
> > > > struct MyContainer {
> > > > using iterator = MyIterator;
> > > > };
> > > > template
> > > > void foo() {
> > > > static_assert(std::is_base_of_v > > > Container::iterator::tag>);
> > > > }
> > > > ```
> > > > This is an example where as a programmer I would not want to see 
> > > > //only// `failed due to requirement std::is_base_of_v` 
> > > > — that doesn't help me solve the issue. OTOH, since every diagnostic 
> > > > includes a cursor to the exact text of the `static_assert` already, I 
> > > > think it's fair to say that the current diagnostic message is 
> > > > redundant, and therefore it's okay to replace it (as you propose to do) 
> > > > with something that is not redundant.
> > > > I think it's fair to say that the current diagnostic message is 
> > > > redundant, and therefore it's okay to replace it (as you propose to do) 
> > > > with something that is not redundant.
> > > 
> > > Yes, the proposal here might not be the *best* possible diagnostic for 
> > > all cases, but it's already a huge improvement on the existing one, and 
> > > solves a significant proportion of use cases.
> > > 
> > > Here, the programmer will see:
> > > ```
> > > test.cc:13:5: error: static_assert failed due to requirement 
> > > 'std::is_base_of::value'
> > > static_assert(std::is_base_of > > Container::iterator::tag>::value);
> > > ^ 
> > > ~~
> > > ```
> > > which I think is a reasonable help for debugging.
> > > 
> > @Quuxplusone, do you have recommendations for what you'd prefer to see 
> > instead?
> > 
> > FWIW, I think this is a good incremental improvement. If there's more 
> > information we could display easily as part of this patch, we should 
> > consider it, but I'm also fine with saying this is progress.
> > @Quuxplusone, do you have recommendations for what you'd prefer to see 
> > instead?
> 
> On the diagnostic itself, no, this looks good and I was just thinking out 
> loud.
> 
> On the test cases, yes, I suggest that there should be at least one test case 
> where a `static_assert` appears inside a template and uses something 
> template-dependent.
SG, I'll add such an example (with std::is_same if you don't mind to avoid 
having to duplicate the whole `` in the test :) )


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903



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


[PATCH] D54903: [Sema] Improve static_assert diagnostics.

2018-11-28 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 175673.
courbet added a comment.

Add unit test with dependent types.


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903

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
@@ -68,3 +68,58 @@
 };
 
 static_assert(first_trait::value && second_trait::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait::value' "message"}}
+
+namespace std {
+
+template 
+struct integral_constant {
+  static const Tp value = v;
+  typedef Tp value_type;
+  typedef integral_constant type;
+};
+
+template 
+const Tp integral_constant::value;
+
+typedef integral_constant true_type;
+typedef integral_constant false_type;
+
+template 
+struct is_const : public false_type {};
+template 
+struct is_const : public true_type {};
+
+// We do not define is_same in terms of integral_constant to check that both implementations are supported.
+template 
+struct is_same {
+  static const bool value = false;
+};
+
+template 
+struct is_same {
+  static const bool value = true;
+};
+
+} // namespace std
+
+struct ExampleTypes {
+  using T = int;
+  using U = float;
+};
+
+static_assert(std::is_same::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_same::value' "message"}}
+static_assert(std::is_const::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_const::value' "message"}}
+
+struct BI_tag {};
+struct RAI_tag : BI_tag {};
+struct MyIterator {
+  using tag = BI_tag;
+};
+struct MyContainer {
+  using iterator = MyIterator;
+};
+template 
+void foo() {
+  static_assert(std::is_same::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_same::value' "message"}}
+}
+template void foo(); // expected-note {{in instantiation of function template specialization 'foo' requested here}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,6 +3052,69 @@
   return Cond;
 }
 
+// Returns true if `RecordName` is the name of an std type trait.
+static bool isTypeTraitName(const llvm::StringRef RecordName) {
+  return
+#define TYPE_TRAIT_1(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_2(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_N(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#include "clang/Basic/TokenKinds.def"
+#undef TYPE_TRAIT_1
+#undef TYPE_TRAIT_2
+#undef TYPE_TRAIT_N
+  false;
+}
+
+// If `Record` is a type trait, pretty prints the condition with actual types
+// and returns true.
+static bool prettyPrintTypeTrait(const NestedNameSpecifier *NNS,
+ llvm::raw_string_ostream &OS,
+ const PrintingPolicy &PrintPolicy) {
+  // We are looking for a type.
+  if (NNS == nullptr || NNS->getKind() != NestedNameSpecifier::TypeSpec)
+return false;
+  const RecordDecl *Record = NNS->getAsRecordDecl();
+  if (Record == nullptr)
+return false;
+  // In namespace "::std".
+  if (!Record->isInStdNamespace())
+return false;
+  // Now check whether the record name is one of the known type traits.
+  if (!isTypeTraitName(Record->getName()))
+return false;
+  // Print the type trait with resolved template parameters.
+  const auto *TmplDecl = dyn_cast(Record);
+  assert(TmplDecl &&
+ "std type_traits should be ClassTemplateSpecializationDecl");
+  OS << "std::" << Record->getName() << "<";
+  ArrayRef Args = TmplDecl->getTemplateArgs().asArray();
+  Args.front().print(PrintPolicy, OS);
+  for (const auto &Arg : Args.drop_front()) {
+OS << ", ";
+Arg.print(PrintPolicy, OS);
+  }
+  OS << ">";
+  return true;
+}
+
+// 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 &PrintPolicy) {
+  if (const auto *DR = dyn_cast(FailedCond)) {
+const auto *Var = dyn_cast(DR->getDecl());
+// This might be `std::some_type_trait::value`.
+if (Var && Var->isStaticDataMember() && Var->getName() == "value" &&
+prettyPrintTypeTrait(DR->getQualifier(), OS, PrintPolicy)) {
+  OS << "::value";
+  return;
+}
+  }
+  FailedCond->printPretty(OS, nullptr, PrintPolicy);
+}
+
 std::pair
 Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
   Cond = lookThroughRangesV3Condition(PP, Cond);
@@ -3093,7 +3156,7 @@
   std::string Description;
   {
 llvm::raw_string_os

[PATCH] D54903: [Sema] Improve static_assert diagnostics.

2018-11-28 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 175679.
courbet added a comment.

Replace custom printing code with clang helper.


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903

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
@@ -68,3 +68,58 @@
 };
 
 static_assert(first_trait::value && second_trait::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait::value' "message"}}
+
+namespace std {
+
+template 
+struct integral_constant {
+  static const Tp value = v;
+  typedef Tp value_type;
+  typedef integral_constant type;
+};
+
+template 
+const Tp integral_constant::value;
+
+typedef integral_constant true_type;
+typedef integral_constant false_type;
+
+template 
+struct is_const : public false_type {};
+template 
+struct is_const : public true_type {};
+
+// We do not define is_same in terms of integral_constant to check that both implementations are supported.
+template 
+struct is_same {
+  static const bool value = false;
+};
+
+template 
+struct is_same {
+  static const bool value = true;
+};
+
+} // namespace std
+
+struct ExampleTypes {
+  using T = int;
+  using U = float;
+};
+
+static_assert(std::is_same::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_same::value' "message"}}
+static_assert(std::is_const::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_const::value' "message"}}
+
+struct BI_tag {};
+struct RAI_tag : BI_tag {};
+struct MyIterator {
+  using tag = BI_tag;
+};
+struct MyContainer {
+  using iterator = MyIterator;
+};
+template 
+void foo() {
+  static_assert(std::is_same::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_same::value' "message"}}
+}
+template void foo(); // expected-note {{in instantiation of function template specialization 'foo' requested here}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,6 +3052,63 @@
   return Cond;
 }
 
+// Returns true if `RecordName` is the name of an std type trait.
+static bool isTypeTraitName(const llvm::StringRef RecordName) {
+  return
+#define TYPE_TRAIT_1(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_2(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#define TYPE_TRAIT_N(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#include "clang/Basic/TokenKinds.def"
+#undef TYPE_TRAIT_1
+#undef TYPE_TRAIT_2
+#undef TYPE_TRAIT_N
+  false;
+}
+
+// If `Record` is a type trait, pretty prints the condition with actual types
+// and returns true.
+static bool prettyPrintTypeTrait(const NestedNameSpecifier *NNS,
+ llvm::raw_string_ostream &OS,
+ const PrintingPolicy &PrintPolicy) {
+  // We are looking for a type.
+  if (NNS == nullptr || NNS->getKind() != NestedNameSpecifier::TypeSpec)
+return false;
+  const RecordDecl *Record = NNS->getAsRecordDecl();
+  if (Record == nullptr)
+return false;
+  // In namespace "::std".
+  if (!Record->isInStdNamespace())
+return false;
+  // Now check whether the record name is one of the known type traits.
+  if (!isTypeTraitName(Record->getName()))
+return false;
+  // Print the type trait with resolved template parameters.
+  const auto *TmplDecl = dyn_cast(Record);
+  assert(TmplDecl &&
+ "std type_traits should be ClassTemplateSpecializationDecl");
+  OS << "std::" << Record->getName();
+  printTemplateArgumentList(OS, TmplDecl->getTemplateArgs().asArray(), PrintPolicy);
+  return true;
+}
+
+// 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 &PrintPolicy) {
+  if (const auto *DR = dyn_cast(FailedCond)) {
+const auto *Var = dyn_cast(DR->getDecl());
+// This might be `std::some_type_trait::value`.
+if (Var && Var->isStaticDataMember() && Var->getName() == "value" &&
+prettyPrintTypeTrait(DR->getQualifier(), OS, PrintPolicy)) {
+  OS << "::value";
+  return;
+}
+  }
+  FailedCond->printPretty(OS, nullptr, PrintPolicy);
+}
+
 std::pair
 Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
   Cond = lookThroughRangesV3Condition(PP, Cond);
@@ -3093,7 +3150,7 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-FailedCond->printPretty(Out, nullptr, getPrintingPolicy());
+prettyPrintFailedBooleanCondi

[PATCH] D54903: [Sema] Improve static_assert diagnostics.

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

expand types in all qualifiers, not only type traits.


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903

Files:
  include/clang/AST/NestedNameSpecifier.h
  lib/AST/NestedNameSpecifier.cpp
  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
@@ -68,3 +68,74 @@
 };
 
 static_assert(first_trait::value && second_trait::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait::value' "message"}}
+
+namespace std {
+
+template 
+struct integral_constant {
+  static const Tp value = v;
+  typedef Tp value_type;
+  typedef integral_constant type;
+};
+
+template 
+const Tp integral_constant::value;
+
+typedef integral_constant true_type;
+typedef integral_constant false_type;
+
+template 
+struct is_const : public false_type {};
+template 
+struct is_const : public true_type {};
+
+// We do not define is_same in terms of integral_constant to check that both implementations are supported.
+template 
+struct is_same {
+  static const bool value = false;
+};
+
+template 
+struct is_same {
+  static const bool value = true;
+};
+
+} // namespace std
+
+struct ExampleTypes {
+  using T = int;
+  using U = float;
+};
+
+static_assert(std::is_same::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_same::value' "message"}}
+static_assert(std::is_const::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_const::value' "message"}}
+
+struct BI_tag {};
+struct RAI_tag : BI_tag {};
+struct MyIterator {
+  using tag = BI_tag;
+};
+struct MyContainer {
+  using iterator = MyIterator;
+};
+template 
+void foo() {
+  static_assert(std::is_same::value, "message"); // expected-error{{static_assert failed due to requirement 'std::is_same::value' "message"}}
+}
+template void foo(); // expected-note {{in instantiation of function template specialization 'foo' requested here}}
+
+namespace ns {
+template 
+struct NestedTemplates1 {
+  struct NestedTemplates2 {
+template 
+struct NestedTemplates3 : public std::is_same {};
+  };
+};
+} // namespace ns
+
+template 
+void foo2() {
+  static_assert(::ns::NestedTemplates1::NestedTemplates2::template NestedTemplates3::value, "message"); // expected-error{{static_assert failed due to requirement '::ns::NestedTemplates1::NestedTemplates2::NestedTemplates3::value' "message"}}
+}
+template void foo2(); // expected-note {{in instantiation of function template specialization 'foo2' requested here}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,6 +3052,23 @@
   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 &PrintPolicy) {
+  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, PrintPolicy, true);
+OS << DR->getDecl()->getName();
+return;
+  }
+  FailedCond->printPretty(OS, nullptr, PrintPolicy);
+}
+
 std::pair
 Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
   Cond = lookThroughRangesV3Condition(PP, Cond);
@@ -3093,7 +3110,7 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-FailedCond->printPretty(Out, nullptr, getPrintingPolicy());
+prettyPrintFailedBooleanCondition(Out, FailedCond, getPrintingPolicy());
   }
   return { FailedCond, Description };
 }
Index: lib/AST/NestedNameSpecifier.cpp
===
--- lib/AST/NestedNameSpecifier.cpp
+++ lib/AST/NestedNameSpecifier.cpp
@@ -16,6 +16,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/TemplateName.h"
 #include "clang/AST/Type.h"
@@ -270,9 +271,8 @@
 
 /// Print this nested name specifier to the given output
 /// stream.
-void
-NestedNameSpecifier::print(raw_ostream &OS,
-   const PrintingPolicy &Policy) const {
+void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
+bool ResolveTemplateArguments) const {
   if (getPrefix())
 getPrefix()->print(OS, Policy

[PATCH] D54903: [Sema] Improve static_assert diagnostics.

2018-11-28 Thread Clement Courbet via Phabricator via cfe-commits
courbet marked 2 inline comments as done.
courbet added inline comments.



Comment at: lib/Sema/SemaTemplate.cpp:3061
+#define TYPE_TRAIT_N(Spelling, Name, Key) RecordName == (#Spelling + 2) ||
+#include "clang/Basic/TokenKinds.def"
+#undef TYPE_TRAIT_1

Quuxplusone wrote:
> Why do you bother to check a whitelist of "known" type trait names? It seems 
> to me that if you replaced this function body with `return true;`, the 
> diagnostic would automatically be able to handle cases such as
> 
> static_assert(std::is_trivially_move_constructible::value);  // not a 
> builtin
> static_assert(folly::IsRelocatable::value);  // not in namespace std
> 
> What would go wrong if you replaced this entire function body with `return 
> true;`?
That's a very good question. I guess because I was mainly interested in this. 
But now that I think of it, there is no reason to limit to  "known" type 
traits, or even to type traits at all. Any qualified DeclRefExpr shoul see its 
qualifiers be spelled out with explicit types, e.g.

`ns::S1::S2::var`

should be diagnosed as something like:

`ns::S1::S2::var`

I've done that and added unit tests. Tell me what you think.



Repository:
  rC Clang

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

https://reviews.llvm.org/D54903



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


[PATCH] D54903: [Sema] Improve static_assert diagnostics.

2018-11-29 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 175855.
courbet marked 5 inline comments as done.
courbet added a comment.

- add more tests
- handle c++17 constructs
- add c++17 tests in static-assert-cxx17.cpp


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903

Files:
  include/clang/AST/NestedNameSpecifier.h
  lib/AST/NestedNameSpecifier.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
@@ -68,3 +68,100 @@
 };
 
 static_assert(first_trait::value && second_trait::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait::value' "message"}}
+
+namespace std {
+
+template 
+struct integral_constant {
+  static const Tp value = v;
+  typedef Tp value_type;
+  typedef integral_constant type;
+};
+
+template 
+const Tp integral_constant::value;
+
+typedef integral_constant true_type;
+typedef integral_constant false_type;
+
+template 
+struct is_const : public false_type {};
+template 
+struct is_const : public true_type {};
+
+// We do not define is_same in terms of integral_constant to check that both implementations are supported.
+template 
+struct is_same {
+  static const bool value = false;
+};
+
+template 
+struct is_same {
+  static const bool value = true;
+};
+
+} // namespace std
+
+struct ExampleTypes {
+  using T = int;
+  using U = float;
+};
+
+static_assert(std::is_same::value, "message");
+// 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"}}
+
+struct BI_tag {};
+struct RAI_tag : BI_tag {};
+struct MyIterator {
+  using tag = BI_tag;
+};
+struct MyContainer {
+  using iterator = MyIterator;
+};
+template 
+void foo() {
+  static_assert(std::is_same::value, "message");
+  // expected-error@-1{{static_assert failed due to requirement 'std::is_same::value' "message"}}
+}
+template void foo();
+// expected-note@-1{{in instantiation of function template specialization 'foo' requested here}}
+
+namespace ns {
+template 
+struct NestedTemplates1 {
+  struct NestedTemplates2 {
+template 
+struct NestedTemplates3 : public std::is_same {};
+  };
+};
+} // namespace ns
+
+template 
+void foo2() {
+  static_assert(::ns::NestedTemplates1::NestedTemplates2::template NestedTemplates3::value, "message");
+  // expected-error@-1{{static_assert failed due to requirement '::ns::NestedTemplates1::NestedTemplates2::NestedTemplates3::value' "message"}}
+}
+template void foo2();
+// expected-note@-1{{in instantiation of function template specialization 'foo2' requested here}}
+
+template 
+void foo3(T t) {
+  static_assert(std::is_const::value, "message");
+  // expected-error-re@-1{{static_assert failed due to requirement 'std::is_const<(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})>::value' "message"}}
+  static_assert(std::is_const::value, "message");
+  // expected-error-re@-1{{static_assert failed due to requirement 'std::is_const<(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})>::value' "message"}}
+}
+void callFoo3() {
+  foo3([]() {});
+  // expected-note@-1{{in instantiation of function template specialization 'foo3<(lambda at }}
+}
+
+template 
+void foo4(T t) {
+  static_assert(std::is_const::value, "message");
+  // expected-error@-1{{type 'int' cannot be used prior to '::' because it has no members}}
+}
+void callFoo4() { foo4(42); }
+// expected-note@-1{{in instantiation of function template specialization 'foo4' requested here}}
Index: test/SemaCXX/static-assert-cxx17.cpp
===
--- /dev/null
+++ test/SemaCXX/static-assert-cxx17.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1z -triple=x86_64-linux-gnu
+
+template 
+struct S1 {
+  static constexpr const bool value = false;
+};
+
+template 
+inline constexpr bool global_inline_var = S1::value;
+
+template 
+struct S2 {
+  template 
+  static inline constexpr bool var = global_inline_var;
+};
+
+template 
+void foo() {
+  static_assert(S1::value);
+  // expected-error@-1{{static_assert failed due to requirement 'S1::value'}}
+}
+template void foo();
+// expected-note@-1{{in instantiation of function template specialization 'foo' requested here}}
+
+template 
+void foo2() {
+  static_assert(global_inline_var);
+  // expected-error@-1{{static_assert failed due to requirement 'global_inline_var'}}
+}
+template void foo2();
+// expected-note@-1{{in instantiation of function template specialization 'foo2' requested here}}
+
+template 
+void foo3() {
+  static_assert(T::template var);
+  // expected-error@-1{{static_assert failed due t

[PATCH] D54903: [Sema] Improve static_assert diagnostics.

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

Thanks




Comment at: lib/Sema/SemaTemplate.cpp:3064
+// If this is a qualified name, expand the template arguments in nested
+// qualifiers.
+DR->getQualifier()->print(OS, PrintPolicy, true);

Quuxplusone wrote:
> I don't understand this code enough to say whether this "qualified name" 
> business is needed. Is this what currently prevents you from expanding e.g. 
> `is_base_of_v`, as opposed to `is_base_of::value`? What would go 
> wrong if you removed //this// condition?
Expr does not have getQualifier(), DeclRefExpr is the one that does.

is_base_of_v is also a DeclRefExpr, so that works as expected.



Comment at: test/SemaCXX/static-assert.cpp:123
+void foo() {
+  static_assert(std::is_same::value, "message"); // expected-error{{static_assert 
failed due to requirement 'std::is_same::value' "message"}}
+}

Quuxplusone wrote:
> Incidentally, you can put `// expected-error@-1{{...}}` on the following 
> line, to avoid such long lines.
Thanks for the tip.



Comment at: test/SemaCXX/static-assert.cpp:141
+}
+template void foo2(); // expected-note {{in instantiation of 
function template specialization 'foo2' requested here}}

Quuxplusone wrote:
> Nice!
> I would also like to see at least one test where one or more of the types are 
> hard-to-name; e.g.
> ```
> template
> void foo(T t) {
> static_assert(std::is_integral::value);
> static_assert(std::is_integral::value);
> }
> void test() { foo([](){}); }
> ```
> Another interesting case would be where one of the types is non-existent — 
> which I //expect// would not hit your codepath at all, right?
> ```
> template
> void foo(T t) {
> static_assert(std::is_integral::value);
> static_assert(std::is_integral::value);
> }
> void test() { foo(42); }
> ```
> And should there be any test for a `static_assert` with no "message" element? 
> or are you confident that that'll just work, and you want to keep this test 
> file building in C++11 mode?
> I would also like to see at least one test where one or more of the types are 
> hard-to-name; e.g.

SG, done.

> Another interesting case would be where one of the types is non-existent — 
> which I expect would not hit your codepath at all, right?

Right. Done.

> And should there be any test for a static_assert with no "message" element? 
> or are you confident that that'll just work, and you want to keep this test 
> file building in C++11 mode?

This test file has negative tests for c++17 message-less static asserts, so 
I've added the c++17 tests in a separate file.


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903



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


[PATCH] D54903: [Sema] Improve static_assert diagnostics.

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



Comment at: lib/AST/NestedNameSpecifier.cpp:308-310
+if (ResolveTemplateArguments && getAsRecordDecl()) {
+  if (const auto *Record =
+  dyn_cast(getAsRecordDecl())) {

aaron.ballman wrote:
> I'd remove the `getAsRecordDecl()` from the first `if` and instead use 
> `dyn_cast_or_null` in the second `if`. Probably something like:
> ```
> const auto *Record = 
> dyn_cast_or_null(getAsRecordDecl());
> if (ResolveTemplateArguments && Record) {
> }
> ```
SG, thanks for the pointer to `dyn_cast_or_null`.



Comment at: lib/Sema/SemaTemplate.cpp:3071
+  printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy);
+}
+return;

aaron.ballman wrote:
> Quuxplusone wrote:
> > Checking my understanding: Am I correct that this code currently does not 
> > pretty-print
> > 
> > static_assert(std::is_same(), "");
> > 
> > (creating an object of the trait type and then using its constexpr 
> > `operator bool` to convert it to bool)? This is a rare idiom and doesn't 
> > need to be supported AFAIC.
> I'm fine worrying about that situation for a follow-up patch if it isn't 
> currently supported.
This is not supported indeed. There are a bunch of other expr types that we 
could support.
This is the most frequent one (11.2% of our codebase), the next one I plan to 
address (in a follow-up patch) is 
`static_assert(!std;:type_trait::value)` with 6.6%.
The one you're mentioning here accounts for 2.8%.


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903



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


[PATCH] D54903: [Sema] Improve static_assert diagnostics.

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

- Fix spurious formating changes
- Add tests
- Improve readability.


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903

Files:
  include/clang/AST/NestedNameSpecifier.h
  lib/AST/NestedNameSpecifier.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
@@ -68,3 +68,100 @@
 };
 
 static_assert(first_trait::value && second_trait::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait::value' "message"}}
+
+namespace std {
+
+template 
+struct integral_constant {
+  static const Tp value = v;
+  typedef Tp value_type;
+  typedef integral_constant type;
+};
+
+template 
+const Tp integral_constant::value;
+
+typedef integral_constant true_type;
+typedef integral_constant false_type;
+
+template 
+struct is_const : public false_type {};
+template 
+struct is_const : public true_type {};
+
+// We do not define is_same in terms of integral_constant to check that both implementations are supported.
+template 
+struct is_same {
+  static const bool value = false;
+};
+
+template 
+struct is_same {
+  static const bool value = true;
+};
+
+} // namespace std
+
+struct ExampleTypes {
+  using T = int;
+  using U = float;
+};
+
+static_assert(std::is_same::value, "message");
+// 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"}}
+
+struct BI_tag {};
+struct RAI_tag : BI_tag {};
+struct MyIterator {
+  using tag = BI_tag;
+};
+struct MyContainer {
+  using iterator = MyIterator;
+};
+template 
+void foo() {
+  static_assert(std::is_same::value, "message");
+  // expected-error@-1{{static_assert failed due to requirement 'std::is_same::value' "message"}}
+}
+template void foo();
+// expected-note@-1{{in instantiation of function template specialization 'foo' requested here}}
+
+namespace ns {
+template 
+struct NestedTemplates1 {
+  struct NestedTemplates2 {
+template 
+struct NestedTemplates3 : public std::is_same {};
+  };
+};
+} // namespace ns
+
+template 
+void foo2() {
+  static_assert(::ns::NestedTemplates1::NestedTemplates2::template NestedTemplates3::value, "message");
+  // expected-error@-1{{static_assert failed due to requirement '::ns::NestedTemplates1::NestedTemplates2::NestedTemplates3::value' "message"}}
+}
+template void foo2();
+// expected-note@-1{{in instantiation of function template specialization 'foo2' requested here}}
+
+template 
+void foo3(T t) {
+  static_assert(std::is_const::value, "message");
+  // expected-error-re@-1{{static_assert failed due to requirement 'std::is_const<(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})>::value' "message"}}
+  static_assert(std::is_const::value, "message");
+  // expected-error-re@-1{{static_assert failed due to requirement 'std::is_const<(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})>::value' "message"}}
+}
+void callFoo3() {
+  foo3([]() {});
+  // expected-note@-1{{in instantiation of function template specialization 'foo3<(lambda at }}
+}
+
+template 
+void foo4(T t) {
+  static_assert(std::is_const::value, "message");
+  // expected-error@-1{{type 'int' cannot be used prior to '::' because it has no members}}
+}
+void callFoo4() { foo4(42); }
+// expected-note@-1{{in instantiation of function template specialization 'foo4' requested here}}
Index: test/SemaCXX/static-assert-cxx17.cpp
===
--- /dev/null
+++ test/SemaCXX/static-assert-cxx17.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1z -triple=x86_64-linux-gnu
+
+template 
+struct S1 {
+  static constexpr const bool value = false;
+};
+
+template 
+inline constexpr bool global_inline_var = S1::value;
+
+template 
+struct S2 {
+  template 
+  static inline constexpr bool var = global_inline_var;
+};
+
+template 
+void foo() {
+  static_assert(S1::value);
+  // expected-error@-1{{static_assert failed due to requirement 'S1::value'}}
+}
+template void foo();
+// expected-note@-1{{in instantiation of function template specialization 'foo' requested here}}
+
+template 
+void foo2() {
+  static_assert(global_inline_var);
+  // expected-error@-1{{static_assert failed due to requirement 'global_inline_var'}}
+}
+template void foo2();
+// expected-note@-1{{in instantiation of function template specialization 'foo2' requested here}}
+
+template 
+void foo3() {
+  static_assert(T::template var);
+  // expected-error@-1{{static_assert failed due to requirement 'S2::var'}}
+}
+template void foo3, int, float>(

[PATCH] D54903: [Sema] Improve static_assert diagnostics.

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



Comment at: lib/Sema/SemaTemplate.cpp:3055
 
+// Print a diagnostic for the failing static_assert expression. Defaults to
+// pretty-printing the expression.

aaron.ballman wrote:
> Comment is a bit out of date as this is no longer specific to `static_assert`.
> 
> It looks like this may also change the behavior of enable_if diagnostic 
> reporting. Do you need to update any of those tests from this change? If not, 
> can you devise some tests for that case as well to show that this isn't just 
> a static_assert behavior? (Do a search for `findFailedBooleanCondition` to 
> find where the behavior has changed.)
Nope, unfortunately the code that calls this is actually untested...
I could not find a test that actually enters the:
```
if (TypeAliasTemplateDecl *AliasTemplate =
  dyn_cast(Template))
```
in `Sema::CheckTemplateIdType`.

I stopped at the following insanity:

```
// RUN: %clang_cc1 -std=c++11 -verify %s

template 
struct is_same {
  enum { value = 0 };
};

template  struct is_same {
  enum { value = 1 };
};

struct Dispatch {
  template  using SameAs = is_same;
};

template 
struct S {
  template  using same = typename DispatchT::template SameAs;

  template 
  static void foo() __attribute__((enable_if(same::value, "")));

};

void runFoo() {
  // S::foo();
  S::foo();

}
```

This one exercises the code up to `if (CanonType.isNull()) {`, but I'm not sure 
how to get a null type here.



Repository:
  rC Clang

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

https://reviews.llvm.org/D54903



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


[PATCH] D54903: [Sema] Improve static_assert diagnostics.

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



Comment at: lib/Sema/SemaTemplate.cpp:3055
 
+// Print a diagnostic for the failing static_assert expression. Defaults to
+// pretty-printing the expression.

aaron.ballman wrote:
> courbet wrote:
> > aaron.ballman wrote:
> > > Comment is a bit out of date as this is no longer specific to 
> > > `static_assert`.
> > > 
> > > It looks like this may also change the behavior of enable_if diagnostic 
> > > reporting. Do you need to update any of those tests from this change? If 
> > > not, can you devise some tests for that case as well to show that this 
> > > isn't just a static_assert behavior? (Do a search for 
> > > `findFailedBooleanCondition` to find where the behavior has changed.)
> > Nope, unfortunately the code that calls this is actually untested...
> > I could not find a test that actually enters the:
> > ```
> > if (TypeAliasTemplateDecl *AliasTemplate =
> >   dyn_cast(Template))
> > ```
> > in `Sema::CheckTemplateIdType`.
> > 
> > I stopped at the following insanity:
> > 
> > ```
> > // RUN: %clang_cc1 -std=c++11 -verify %s
> > 
> > template 
> > struct is_same {
> >   enum { value = 0 };
> > };
> > 
> > template  struct is_same {
> >   enum { value = 1 };
> > };
> > 
> > struct Dispatch {
> >   template  using SameAs = is_same;
> > };
> > 
> > template 
> > struct S {
> >   template  using same = typename DispatchT::template SameAs;
> > 
> >   template 
> >   static void foo() __attribute__((enable_if(same::value, "")));
> > 
> > };
> > 
> > void runFoo() {
> >   // S::foo();
> >   S::foo();
> > 
> > }
> > ```
> > 
> > This one exercises the code up to `if (CanonType.isNull()) {`, but I'm not 
> > sure how to get a null type here.
> > 
> How about this:
> ```
> namespace boost {
>   template struct enable_if {};
>   template struct enable_if { typedef T type; };
> }
> 
> template struct NonTemplateFunction {
>   typename boost::enable_if::type f();
> };
> 
> template 
> struct Bobble {
>   using type = T;
> };
> 
> struct Frobble {
>   using type = char;
> };
> NonTemplateFunction::type> NTFC;
> ```
> That should trigger the path in `Sema::CheckTypenameType()`, I believe.
This triggers:
```
else if (ClassTemplateDecl *ClassTemplate
   = dyn_cast(Template))
```

Modifying it to:
```
namespace boost {
  template struct enable_if {};
  template struct enable_if { typedef T type; };
}

template struct NonTemplateFunction {
  template  using toto = typename boost::enable_if::type;
  toto f();
};

template 
struct Bobble {
  using type = T;
};

struct Frobble {
  using type = char;
};
NonTemplateFunction::type> NTFC;
```

triggers the same path as my previous example, but not the `IsNull()` test.


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903



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


[PATCH] D54903: [Sema] Improve static_assert diagnostics.

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

Thank you both for the review !


Repository:
  rC Clang

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

https://reviews.llvm.org/D54903



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


[PATCH] D54903: [Sema] Improve static_assert diagnostics.

2018-12-04 Thread Clement Courbet via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL348239: [WIP][Sema] Improve static_assert diagnostics for 
type traits. (authored by courbet, committed by ).
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

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

https://reviews.llvm.org/D54903

Files:
  cfe/trunk/include/clang/AST/NestedNameSpecifier.h
  cfe/trunk/lib/AST/NestedNameSpecifier.cpp
  cfe/trunk/lib/Sema/SemaTemplate.cpp
  cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp
  cfe/trunk/test/SemaCXX/static-assert.cpp

Index: cfe/trunk/include/clang/AST/NestedNameSpecifier.h
===
--- cfe/trunk/include/clang/AST/NestedNameSpecifier.h
+++ cfe/trunk/include/clang/AST/NestedNameSpecifier.h
@@ -212,9 +212,12 @@
   /// parameter pack (for C++11 variadic templates).
   bool containsUnexpandedParameterPack() const;
 
-  /// Print this nested name specifier to the given output
-  /// stream.
-  void print(raw_ostream &OS, const PrintingPolicy &Policy) const;
+  /// Print this nested name specifier to the given output stream. If
+  /// `ResolveTemplateArguments` is true, we'll print actual types, e.g.
+  /// `ns::SomeTemplate` instead of
+  /// `ns::SomeTemplate`.
+  void print(raw_ostream &OS, const PrintingPolicy &Policy,
+ bool ResolveTemplateArguments = false) const;
 
   void Profile(llvm::FoldingSetNodeID &ID) const {
 ID.AddPointer(Prefix.getOpaqueValue());
Index: cfe/trunk/test/SemaCXX/static-assert.cpp
===
--- cfe/trunk/test/SemaCXX/static-assert.cpp
+++ cfe/trunk/test/SemaCXX/static-assert.cpp
@@ -68,3 +68,100 @@
 };
 
 static_assert(first_trait::value && second_trait::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait::value' "message"}}
+
+namespace std {
+
+template 
+struct integral_constant {
+  static const Tp value = v;
+  typedef Tp value_type;
+  typedef integral_constant type;
+};
+
+template 
+const Tp integral_constant::value;
+
+typedef integral_constant true_type;
+typedef integral_constant false_type;
+
+template 
+struct is_const : public false_type {};
+template 
+struct is_const : public true_type {};
+
+// We do not define is_same in terms of integral_constant to check that both implementations are supported.
+template 
+struct is_same {
+  static const bool value = false;
+};
+
+template 
+struct is_same {
+  static const bool value = true;
+};
+
+} // namespace std
+
+struct ExampleTypes {
+  using T = int;
+  using U = float;
+};
+
+static_assert(std::is_same::value, "message");
+// 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"}}
+
+struct BI_tag {};
+struct RAI_tag : BI_tag {};
+struct MyIterator {
+  using tag = BI_tag;
+};
+struct MyContainer {
+  using iterator = MyIterator;
+};
+template 
+void foo() {
+  static_assert(std::is_same::value, "message");
+  // expected-error@-1{{static_assert failed due to requirement 'std::is_same::value' "message"}}
+}
+template void foo();
+// expected-note@-1{{in instantiation of function template specialization 'foo' requested here}}
+
+namespace ns {
+template 
+struct NestedTemplates1 {
+  struct NestedTemplates2 {
+template 
+struct NestedTemplates3 : public std::is_same {};
+  };
+};
+} // namespace ns
+
+template 
+void foo2() {
+  static_assert(::ns::NestedTemplates1::NestedTemplates2::template NestedTemplates3::value, "message");
+  // expected-error@-1{{static_assert failed due to requirement '::ns::NestedTemplates1::NestedTemplates2::NestedTemplates3::value' "message"}}
+}
+template void foo2();
+// expected-note@-1{{in instantiation of function template specialization 'foo2' requested here}}
+
+template 
+void foo3(T t) {
+  static_assert(std::is_const::value, "message");
+  // expected-error-re@-1{{static_assert failed due to requirement 'std::is_const<(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})>::value' "message"}}
+  static_assert(std::is_const::value, "message");
+  // expected-error-re@-1{{static_assert failed due to requirement 'std::is_const<(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})>::value' "message"}}
+}
+void callFoo3() {
+  foo3([]() {});
+  // expected-note@-1{{in instantiation of function template specialization 'foo3<(lambda at }}
+}
+
+template 
+void foo4(T t) {
+  static_assert(std::is_const::value, "message");
+  // expected-error@-1{{type 'int' cannot be used prior to '::' because it has no members}}
+}
+void callFoo4() { foo4(42); }
+// expected-note@-1{{in instantiation of function template specialization 'foo4' requested here}}
Index: cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp

[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

[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-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-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-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-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] D55552: [Sema] Better static assert diagnostics for expressions involving temporaries.

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

Handles expressions such as:

- `std::is_const()`
- `std::is_const()()`;
- `std::is_same(decltype(U()), V>::value`;


Repository:
  rC Clang

https://reviews.llvm.org/D2

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
@@ -76,6 +76,8 @@
   static const Tp value = v;
   typedef Tp value_type;
   typedef integral_constant type;
+  constexpr operator value_type() const noexcept { return value; }
+  constexpr value_type operator()() const noexcept { return value; }
 };
 
 template 
@@ -103,6 +105,7 @@
 } // namespace std
 
 struct ExampleTypes {
+  explicit ExampleTypes(int);
   using T = int;
   using U = float;
 };
@@ -119,6 +122,18 @@
 // 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"}}
+static_assert(std::is_const(), "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_const()' "message"}}
+static_assert(!(std::is_const()()), "message");
+// expected-error@-1{{static_assert failed due to requirement '!(std::is_const()())' "message"}}
+static_assert(std::is_same()), int>::value, "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::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
@@ -3059,8 +3059,9 @@
 // for actual types.
 class FailedBooleanConditionPrinterHelper : public PrinterHelper {
 public:
-  explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &P)
-  : Policy(P) {}
+  FailedBooleanConditionPrinterHelper(const ASTContext &Context,
+  const PrintingPolicy &P)
+  : Context(Context), Policy(P) {}
 
   bool handledStmt(Stmt *E, raw_ostream &OS) override {
 const auto *DR = dyn_cast(E);
@@ -3077,10 +3078,38 @@
   }
   return true;
 }
+if (auto *Node = dyn_cast(E)) {
+  Node->getType().getCanonicalType().print(OS, Policy);
+  if (Node->isStdInitListInitialization())
+/* Nothing to do; braces are part of creating the std::initializer_list.
+ */
+;
+  else if (Node->isListInitialization())
+OS << "{";
+  else
+OS << "(";
+  for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(),
+ArgEnd = Node->arg_end();
+   Arg != ArgEnd; ++Arg) {
+if ((*Arg)->isDefaultArgument())
+  break;
+if (Arg != Node->arg_begin())
+  OS << ", ";
+(*Arg)->printPretty(OS, this, Policy);
+  }
+  if (Node->isStdInitListInitialization())
+/* See above. */;
+  else if (Node->isListInitialization())
+OS << "}";
+  else
+OS << ")";
+  return true;
+}
 return false;
   }
 
 private:
+  const ASTContext &Context;
   const PrintingPolicy Policy;
 };
 
@@ -3122,7 +3151,7 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-FailedBooleanConditionPrinterHelper Helper(getPrintingPolicy());
+FailedBooleanConditionPrinterHelper Helper(Context, getPrintingPolicy());
 FailedCond->printPretty(Out, &Helper, getPrintingPolicy());
   }
   return { FailedCond, Description };
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D55552: [Sema] Better static assert diagnostics for expressions involving temporaries.

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

cosmetics


Repository:
  rC Clang

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

https://reviews.llvm.org/D2

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
@@ -76,6 +76,8 @@
   static const Tp value = v;
   typedef Tp value_type;
   typedef integral_constant type;
+  constexpr operator value_type() const noexcept { return value; }
+  constexpr value_type operator()() const noexcept { return value; }
 };
 
 template 
@@ -103,6 +105,7 @@
 } // namespace std
 
 struct ExampleTypes {
+  explicit ExampleTypes(int);
   using T = int;
   using U = float;
 };
@@ -119,6 +122,18 @@
 // 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"}}
+static_assert(std::is_const(), "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_const()' "message"}}
+static_assert(!(std::is_const()()), "message");
+// expected-error@-1{{static_assert failed due to requirement '!(std::is_const()())' "message"}}
+static_assert(std::is_same()), int>::value, "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::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
@@ -3059,8 +3059,9 @@
 // for actual types.
 class FailedBooleanConditionPrinterHelper : public PrinterHelper {
 public:
-  explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &P)
-  : Policy(P) {}
+  FailedBooleanConditionPrinterHelper(const ASTContext &Context,
+  const PrintingPolicy &P)
+  : Context(Context), Policy(P) {}
 
   bool handledStmt(Stmt *E, raw_ostream &OS) override {
 const auto *DR = dyn_cast(E);
@@ -3077,10 +3078,37 @@
   }
   return true;
 }
+if (auto *Node = dyn_cast(E)) {
+  Node->getType().getCanonicalType().print(OS, Policy);
+  if (Node->isStdInitListInitialization())
+// Nothing to do; braces are part of creating the std::initializer_list.
+;
+  else if (Node->isListInitialization())
+OS << "{";
+  else
+OS << "(";
+  for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(),
+ArgEnd = Node->arg_end();
+   Arg != ArgEnd; ++Arg) {
+if ((*Arg)->isDefaultArgument())
+  break;
+if (Arg != Node->arg_begin())
+  OS << ", ";
+(*Arg)->printPretty(OS, this, Policy);
+  }
+  if (Node->isStdInitListInitialization())
+/* See above. */;
+  else if (Node->isListInitialization())
+OS << "}";
+  else
+OS << ")";
+  return true;
+}
 return false;
   }
 
 private:
+  const ASTContext &Context;
   const PrintingPolicy Policy;
 };
 
@@ -3122,7 +3150,7 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-FailedBooleanConditionPrinterHelper Helper(getPrintingPolicy());
+FailedBooleanConditionPrinterHelper Helper(Context, getPrintingPolicy());
 FailedCond->printPretty(Out, &Helper, getPrintingPolicy());
   }
   return { FailedCond, Description };
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D58609: [clang-tidy] bugprone-string-integer-assignment: Reduce false positives.

2019-02-25 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 188316.
courbet added a comment.

- more tests


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D58609

Files:
  clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
  test/clang-tidy/bugprone-string-integer-assignment.cpp


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -59,4 +59,11 @@
   s += toupper(x);
   s += tolower(x);
   s += std::tolower(x);
+
+  // Likely character expressions.
+  s += x & 0xff;
+  s += 0xff & x;
+
+  s += 'a' + (x % 26);
+  s += (x % 10) + 'b';
 }
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -40,11 +40,44 @@
   this);
 }
 
+static bool isLikelyCharExpression(const Expr *Argument,
+   const ASTContext &Ctx) {
+  const auto *BinOp = dyn_cast(Argument);
+  if (!BinOp) {
+return false;
+  }
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  //  & , mask is a compile time constant.
+  Expr::EvalResult RHSVal;
+  if (BinOp->getOpcode() == BO_And &&
+  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
+   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects))) {
+return true;
+  }
+  //  + ( % ), where  is a char literal.
+  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
+const auto *ROp = dyn_cast(R);
+return ROp && ROp->getOpcode() == BO_Rem && isa(L);
+  };
+  if (BinOp->getOpcode() == BO_Add) {
+if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS)) {
+  return true;
+}
+  }
+  return false;
+}
+
 void StringIntegerAssignmentCheck::check(
 const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs("expr");
   SourceLocation Loc = Argument->getBeginLoc();
 
+  // Try to detect a few common expressions to reduce false positives.
+  if (isLikelyCharExpression(Argument, *Result.Context)) {
+return;
+  }
+
   auto Diag =
   diag(Loc, "an integer is interpreted as a character code when assigning "
 "it to a string; if this is intended, cast the integer to the "


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -59,4 +59,11 @@
   s += toupper(x);
   s += tolower(x);
   s += std::tolower(x);
+
+  // Likely character expressions.
+  s += x & 0xff;
+  s += 0xff & x;
+
+  s += 'a' + (x % 26);
+  s += (x % 10) + 'b';
 }
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -40,11 +40,44 @@
   this);
 }
 
+static bool isLikelyCharExpression(const Expr *Argument,
+   const ASTContext &Ctx) {
+  const auto *BinOp = dyn_cast(Argument);
+  if (!BinOp) {
+return false;
+  }
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  //  & , mask is a compile time constant.
+  Expr::EvalResult RHSVal;
+  if (BinOp->getOpcode() == BO_And &&
+  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
+   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects))) {
+return true;
+  }
+  //  + ( % ), where  is a char literal.
+  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
+const auto *ROp = dyn_cast(R);
+return ROp && ROp->getOpcode() == BO_Rem && isa(L);
+  };
+  if (BinOp->getOpcode() == BO_Add) {
+if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS)) {
+  return true;
+}
+  }
+  return false;
+}
+
 void StringIntegerAssignmentCheck::check(
 const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs("expr");
   SourceLocation Loc = Argument->getBeginLoc();
 
+  // Try to detect a few common expressions to reduce false positives.
+  if (isLikelyCharExpression(Argument, *Result.Context)) {
+return;
+  }
+
   auto Diag =
   diag(Loc, "an integer is interpreted as a character code when assigning "
 "it to a string; if this is intended, cast the integer to the "
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D58606: [clang-tidy] misc-string-integer-assignment: fix false positive

2019-02-26 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 188318.
courbet added a comment.

- add more tests
- Traverse using decls.


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D58606

Files:
  clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
  test/clang-tidy/bugprone-string-integer-assignment.cpp


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -53,8 +53,8 @@
 
   std::basic_string as;
   as = 6;
-// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a 
chara
-// CHECK-FIXES: {{^}}  as = 6;{{$}}
+  as = static_cast(6);
+  as = 'a';
 
   s += toupper(x);
   s += tolower(x);
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -26,7 +26,8 @@
 hasOverloadedOperatorName("+=")),
   callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
   hasName("::std::basic_string"),
-  hasTemplateArgument(0, 
refersToType(qualType().bind("type"))),
+  hasTemplateArgument(0, refersToType(hasCanonicalType(
+ qualType().bind("type",
   hasArgument(
   1,
   ignoringImpCasts(
@@ -34,7 +35,11 @@
// Ignore calls to tolower/toupper (see PR27723).
unless(callExpr(callee(functionDecl(
hasAnyName("tolower", "std::tolower", "toupper",
-  "std::toupper"))
+  "std::toupper"),
+   // Do not warn if assigning e.g. `CodePoint` to
+   // `basic_string`
+   unless(hasType(qualType(
+   hasCanonicalType(equalsBoundNode("type"))
   .bind("expr"))),
   unless(isInTemplateInstantiation())),
   this);


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -53,8 +53,8 @@
 
   std::basic_string as;
   as = 6;
-// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
-// CHECK-FIXES: {{^}}  as = 6;{{$}}
+  as = static_cast(6);
+  as = 'a';
 
   s += toupper(x);
   s += tolower(x);
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -26,7 +26,8 @@
 hasOverloadedOperatorName("+=")),
   callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
   hasName("::std::basic_string"),
-  hasTemplateArgument(0, refersToType(qualType().bind("type"))),
+  hasTemplateArgument(0, refersToType(hasCanonicalType(
+ qualType().bind("type",
   hasArgument(
   1,
   ignoringImpCasts(
@@ -34,7 +35,11 @@
// Ignore calls to tolower/toupper (see PR27723).
unless(callExpr(callee(functionDecl(
hasAnyName("tolower", "std::tolower", "toupper",
-  "std::toupper"))
+  "std::toupper"),
+   // Do not warn if assigning e.g. `CodePoint` to
+   // `basic_string`
+   unless(hasType(qualType(
+   hasCanonicalType(equalsBoundNode("type"))
   .bind("expr"))),
   unless(isInTemplateInstantiation())),
   this);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D58609: [clang-tidy] bugprone-string-integer-assignment: Reduce false positives.

2019-02-26 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 188367.
courbet marked an inline comment as done.
courbet added a comment.

- cosmetics


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D58609

Files:
  clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
  test/clang-tidy/bugprone-string-integer-assignment.cpp


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -59,4 +59,11 @@
   s += toupper(x);
   s += tolower(x);
   s += std::tolower(x);
+
+  // Likely character expressions.
+  s += x & 0xff;
+  s += 0xff & x;
+
+  s += 'a' + (x % 26);
+  s += (x % 10) + 'b';
 }
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -40,11 +40,41 @@
   this);
 }
 
+static bool isLikelyCharExpression(const Expr *Argument,
+   const ASTContext &Ctx) {
+  const auto *BinOp = dyn_cast(Argument);
+  if (!BinOp)
+return false;
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  //  & , mask is a compile time constant.
+  Expr::EvalResult RHSVal;
+  if (BinOp->getOpcode() == BO_And &&
+  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
+   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects))) {
+return true;
+  }
+  //  + ( % ), where  is a char literal.
+  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
+const auto *ROp = dyn_cast(R);
+return ROp && ROp->getOpcode() == BO_Rem && isa(L);
+  };
+  if (BinOp->getOpcode() == BO_Add) {
+if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS))
+  return true;
+  }
+  return false;
+}
+
 void StringIntegerAssignmentCheck::check(
 const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs("expr");
   SourceLocation Loc = Argument->getBeginLoc();
 
+  // Try to detect a few common expressions to reduce false positives.
+  if (isLikelyCharExpression(Argument, *Result.Context))
+return;
+
   auto Diag =
   diag(Loc, "an integer is interpreted as a character code when assigning "
 "it to a string; if this is intended, cast the integer to the "


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -59,4 +59,11 @@
   s += toupper(x);
   s += tolower(x);
   s += std::tolower(x);
+
+  // Likely character expressions.
+  s += x & 0xff;
+  s += 0xff & x;
+
+  s += 'a' + (x % 26);
+  s += (x % 10) + 'b';
 }
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -40,11 +40,41 @@
   this);
 }
 
+static bool isLikelyCharExpression(const Expr *Argument,
+   const ASTContext &Ctx) {
+  const auto *BinOp = dyn_cast(Argument);
+  if (!BinOp)
+return false;
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  //  & , mask is a compile time constant.
+  Expr::EvalResult RHSVal;
+  if (BinOp->getOpcode() == BO_And &&
+  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
+   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects))) {
+return true;
+  }
+  //  + ( % ), where  is a char literal.
+  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
+const auto *ROp = dyn_cast(R);
+return ROp && ROp->getOpcode() == BO_Rem && isa(L);
+  };
+  if (BinOp->getOpcode() == BO_Add) {
+if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS))
+  return true;
+  }
+  return false;
+}
+
 void StringIntegerAssignmentCheck::check(
 const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs("expr");
   SourceLocation Loc = Argument->getBeginLoc();
 
+  // Try to detect a few common expressions to reduce false positives.
+  if (isLikelyCharExpression(Argument, *Result.Context))
+return;
+
   auto Diag =
   diag(Loc, "an integer is interpreted as a character code when assigning "
 "it to a string; if this is intended, cast the integer to the "
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D58606: [clang-tidy] misc-string-integer-assignment: fix false positive

2019-02-28 Thread Clement Courbet via Phabricator via cfe-commits
courbet added a comment.

Thanks !

> is there a bug or similar? If yes please mention it somewhere in the summary 
> or so and close it :)

Yes, PR27723. Done.


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D58606



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


[PATCH] D58606: [clang-tidy] misc-string-integer-assignment: fix false positive

2019-02-28 Thread Clement Courbet via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL355076: [clang-tidy] misc-string-integer-assignment: fix 
false positive (authored by courbet, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

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

https://reviews.llvm.org/D58606

Files:
  clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
  clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp


Index: 
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -26,7 +26,8 @@
 hasOverloadedOperatorName("+=")),
   callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
   hasName("::std::basic_string"),
-  hasTemplateArgument(0, 
refersToType(qualType().bind("type"))),
+  hasTemplateArgument(0, refersToType(hasCanonicalType(
+ qualType().bind("type",
   hasArgument(
   1,
   ignoringImpCasts(
@@ -34,7 +35,11 @@
// Ignore calls to tolower/toupper (see PR27723).
unless(callExpr(callee(functionDecl(
hasAnyName("tolower", "std::tolower", "toupper",
-  "std::toupper"))
+  "std::toupper"),
+   // Do not warn if assigning e.g. `CodePoint` to
+   // `basic_string`
+   unless(hasType(qualType(
+   hasCanonicalType(equalsBoundNode("type"))
   .bind("expr"))),
   unless(isInTemplateInstantiation())),
   this);
Index: 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -53,8 +53,8 @@
 
   std::basic_string as;
   as = 6;
-// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a 
chara
-// CHECK-FIXES: {{^}}  as = 6;{{$}}
+  as = static_cast(6);
+  as = 'a';
 
   s += toupper(x);
   s += tolower(x);


Index: clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -26,7 +26,8 @@
 hasOverloadedOperatorName("+=")),
   callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
   hasName("::std::basic_string"),
-  hasTemplateArgument(0, refersToType(qualType().bind("type"))),
+  hasTemplateArgument(0, refersToType(hasCanonicalType(
+ qualType().bind("type",
   hasArgument(
   1,
   ignoringImpCasts(
@@ -34,7 +35,11 @@
// Ignore calls to tolower/toupper (see PR27723).
unless(callExpr(callee(functionDecl(
hasAnyName("tolower", "std::tolower", "toupper",
-  "std::toupper"))
+  "std::toupper"),
+   // Do not warn if assigning e.g. `CodePoint` to
+   // `basic_string`
+   unless(hasType(qualType(
+   hasCanonicalType(equalsBoundNode("type"))
   .bind("expr"))),
   unless(isInTemplateInstantiation())),
   this);
Index: clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -53,8 +53,8 @@
 
   std::basic_string as;
   as = 6;
-// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
-// CHECK-FIXES: {{^}}  as = 6;{{$}}
+  as = static_cast(6);
+  as = 'a';
 
   s += toupper(x);
   s += tolower(x);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D58609: [clang-tidy] bugprone-string-integer-assignment: Reduce false positives.

2019-02-28 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 188690.
courbet marked an inline comment as done.
courbet added a comment.

- rebase
- -more cosmetics


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D58609

Files:
  clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
  test/clang-tidy/bugprone-string-integer-assignment.cpp


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -59,4 +59,11 @@
   s += toupper(x);
   s += tolower(x);
   s += std::tolower(x);
+
+  // Likely character expressions.
+  s += x & 0xff;
+  s += 0xff & x;
+
+  s += 'a' + (x % 26);
+  s += (x % 10) + 'b';
 }
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -45,11 +45,40 @@
   this);
 }
 
+static bool isLikelyCharExpression(const Expr *Argument,
+   const ASTContext &Ctx) {
+  const auto *BinOp = dyn_cast(Argument);
+  if (!BinOp)
+return false;
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  //  & , mask is a compile time constant.
+  Expr::EvalResult RHSVal;
+  if (BinOp->getOpcode() == BO_And &&
+  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
+   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects)))
+return true;
+  //  + ( % ), where  is a char literal.
+  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
+const auto *ROp = dyn_cast(R);
+return ROp && ROp->getOpcode() == BO_Rem && isa(L);
+  };
+  if (BinOp->getOpcode() == BO_Add) {
+if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS))
+  return true;
+  }
+  return false;
+}
+
 void StringIntegerAssignmentCheck::check(
 const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs("expr");
   SourceLocation Loc = Argument->getBeginLoc();
 
+  // Try to detect a few common expressions to reduce false positives.
+  if (isLikelyCharExpression(Argument, *Result.Context))
+return;
+
   auto Diag =
   diag(Loc, "an integer is interpreted as a character code when assigning "
 "it to a string; if this is intended, cast the integer to the "


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -59,4 +59,11 @@
   s += toupper(x);
   s += tolower(x);
   s += std::tolower(x);
+
+  // Likely character expressions.
+  s += x & 0xff;
+  s += 0xff & x;
+
+  s += 'a' + (x % 26);
+  s += (x % 10) + 'b';
 }
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -45,11 +45,40 @@
   this);
 }
 
+static bool isLikelyCharExpression(const Expr *Argument,
+   const ASTContext &Ctx) {
+  const auto *BinOp = dyn_cast(Argument);
+  if (!BinOp)
+return false;
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  //  & , mask is a compile time constant.
+  Expr::EvalResult RHSVal;
+  if (BinOp->getOpcode() == BO_And &&
+  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
+   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects)))
+return true;
+  //  + ( % ), where  is a char literal.
+  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
+const auto *ROp = dyn_cast(R);
+return ROp && ROp->getOpcode() == BO_Rem && isa(L);
+  };
+  if (BinOp->getOpcode() == BO_Add) {
+if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS))
+  return true;
+  }
+  return false;
+}
+
 void StringIntegerAssignmentCheck::check(
 const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs("expr");
   SourceLocation Loc = Argument->getBeginLoc();
 
+  // Try to detect a few common expressions to reduce false positives.
+  if (isLikelyCharExpression(Argument, *Result.Context))
+return;
+
   auto Diag =
   diag(Loc, "an integer is interpreted as a character code when assigning "
 "it to a string; if this is intended, cast the integer to the "
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D58609: [clang-tidy] bugprone-string-integer-assignment: Reduce false positives.

2019-02-28 Thread Clement Courbet via Phabricator via cfe-commits
courbet added a comment.

Thanks.


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D58609



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


[PATCH] D58609: [clang-tidy] bugprone-string-integer-assignment: Reduce false positives.

2019-02-28 Thread Clement Courbet via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rCTE355089: [clang-tidy] bugprone-string-integer-assignment: 
Reduce false positives. (authored by courbet, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D58609?vs=188690&id=188722#toc

Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D58609

Files:
  clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
  test/clang-tidy/bugprone-string-integer-assignment.cpp


Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -45,11 +45,40 @@
   this);
 }
 
+static bool isLikelyCharExpression(const Expr *Argument,
+   const ASTContext &Ctx) {
+  const auto *BinOp = dyn_cast(Argument);
+  if (!BinOp)
+return false;
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  //  & , mask is a compile time constant.
+  Expr::EvalResult RHSVal;
+  if (BinOp->getOpcode() == BO_And &&
+  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
+   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects)))
+return true;
+  //  + ( % ), where  is a char literal.
+  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
+const auto *ROp = dyn_cast(R);
+return ROp && ROp->getOpcode() == BO_Rem && isa(L);
+  };
+  if (BinOp->getOpcode() == BO_Add) {
+if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS))
+  return true;
+  }
+  return false;
+}
+
 void StringIntegerAssignmentCheck::check(
 const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs("expr");
   SourceLocation Loc = Argument->getBeginLoc();
 
+  // Try to detect a few common expressions to reduce false positives.
+  if (isLikelyCharExpression(Argument, *Result.Context))
+return;
+
   auto Diag =
   diag(Loc, "an integer is interpreted as a character code when assigning "
 "it to a string; if this is intended, cast the integer to the "
Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -59,4 +59,11 @@
   s += toupper(x);
   s += tolower(x);
   s += std::tolower(x);
+
+  // Likely character expressions.
+  s += x & 0xff;
+  s += 0xff & x;
+
+  s += 'a' + (x % 26);
+  s += (x % 10) + 'b';
 }


Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -45,11 +45,40 @@
   this);
 }
 
+static bool isLikelyCharExpression(const Expr *Argument,
+   const ASTContext &Ctx) {
+  const auto *BinOp = dyn_cast(Argument);
+  if (!BinOp)
+return false;
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  //  & , mask is a compile time constant.
+  Expr::EvalResult RHSVal;
+  if (BinOp->getOpcode() == BO_And &&
+  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
+   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects)))
+return true;
+  //  + ( % ), where  is a char literal.
+  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
+const auto *ROp = dyn_cast(R);
+return ROp && ROp->getOpcode() == BO_Rem && isa(L);
+  };
+  if (BinOp->getOpcode() == BO_Add) {
+if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS))
+  return true;
+  }
+  return false;
+}
+
 void StringIntegerAssignmentCheck::check(
 const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs("expr");
   SourceLocation Loc = Argument->getBeginLoc();
 
+  // Try to detect a few common expressions to reduce false positives.
+  if (isLikelyCharExpression(Argument, *Result.Context))
+return;
+
   auto Diag =
   diag(Loc, "an integer is interpreted as a character code when assigning "
 "it to a string; if this is intended, cast the integer to the "
Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -59,4 +59,11 @@
   s += toupper(x);
   s += tolower(x);
   s += std::tolower(x);
+
+  // Likely character expressions.
+  s += x & 0xff;
+  s += 0xff & x;
+
+  s += 'a' + (x % 26);
+  s += (x % 10) + 'b';
 }
___

[PATCH] D59360: [clang-tidy] Fix more false positives for bugprone-string-integer-assignment

2019-03-14 Thread Clement Courbet via Phabricator via cfe-commits
courbet created this revision.
courbet added reviewers: JonasToth, alexfh, xazax.hun.
Herald added subscribers: jdoerfert, rnkovacs.
Herald added a project: clang.

And add various tests gleaned for our codebase.

See PR27723.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D59360

Files:
  clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
  clang-tools-extra/test/clang-tidy/bugprone-string-integer-assignment.cpp

Index: clang-tools-extra/test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- clang-tools-extra/test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ clang-tools-extra/test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -7,6 +7,8 @@
   basic_string& operator=(basic_string);
   basic_string& operator+=(T);
   basic_string& operator+=(basic_string);
+  const T &operator[](int i) const;
+  T &operator[](int i);
 };
 
 typedef basic_string string;
@@ -21,10 +23,13 @@
 
 typedef int MyArcaneChar;
 
+constexpr char kCharConstant = 'a';
+
 int main() {
   std::string s;
   std::wstring ws;
   int x = 5;
+  const char c = 'c';
 
   s = 6;
 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a character code when assigning {{.*}} [bugprone-string-integer-assignment]
@@ -58,12 +63,36 @@
 
   s += toupper(x);
   s += tolower(x);
-  s += std::tolower(x);
+  s += (std::tolower(x));
+
+  s += c & s[1];
+  s += c ^ s[1];
+  s += c | s[1];
+
+  s[x] += 1;
+  s += s[x];
+  as += as[x];
 
   // Likely character expressions.
   s += x & 0xff;
   s += 0xff & x;
+  s += x % 26;
+  s += 26 % x;
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
+  // CHECK-FIXES: {{^}}  s += std::to_string(26 % x);{{$}}
+  s += c | 0x80;
+  s += c | 0x8000;
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
+  // CHECK-FIXES: {{^}}  s += std::to_string(c | 0x8000);{{$}}
+  as += c | 0x8000;
 
   s += 'a' + (x % 26);
+  s += kCharConstant + (x % 26);
+  s += 'a' + (s[x] & 0xf);
   s += (x % 10) + 'b';
+
+  s += x > 255 ? c : x;
+  s += x > 255 ? 12 : x;
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
+  // CHECK-FIXES: {{^}}  s += std::to_string(x > 255 ? 12 : x);{{$}}
 }
Index: clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -45,38 +45,98 @@
   this);
 }
 
-static bool isLikelyCharExpression(const Expr *Argument,
-   const ASTContext &Ctx) {
-  const auto *BinOp = dyn_cast(Argument);
-  if (!BinOp)
+class CharExpressionDetector {
+public:
+  CharExpressionDetector(const QualType CharType, const ASTContext &Ctx)
+  : CharType(CharType), Ctx(Ctx) {}
+
+  bool isLikelyCharExpression(const Expr *E) const {
+if (isCharTyped(E))
+  return true;
+
+if (const auto *BinOp = dyn_cast(E)) {
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  // Handle both directions, e.g. `'a' + (i % 26)` and `(i % 26) + 'a'`.
+  if (BinOp->isAdditiveOp() || BinOp->isBitwiseOp())
+return handleBinaryOp(BinOp->getOpcode(), LHS, RHS) ||
+   handleBinaryOp(BinOp->getOpcode(), RHS, LHS);
+  // Except in the case of '%'.
+  if (BinOp->getOpcode() == BO_Rem)
+return handleBinaryOp(BinOp->getOpcode(), LHS, RHS);
+  return false;
+}
+
+// ternary where at least one branch is a likely char expression, e.g.
+//i < 265 ? i : ' '
+if (const auto *CondOp = dyn_cast(E))
+  return isLikelyCharExpression(
+ CondOp->getFalseExpr()->IgnoreParenImpCasts()) ||
+ isLikelyCharExpression(
+ CondOp->getTrueExpr()->IgnoreParenImpCasts());
 return false;
-  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
-  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
-  //  & , mask is a compile time constant.
-  Expr::EvalResult RHSVal;
-  if (BinOp->getOpcode() == BO_And &&
-  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
-   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects)))
-return true;
-  //  + ( % ), where  is a char literal.
-  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
-const auto *ROp = dyn_cast(R);
-return ROp && ROp->getOpcode() == BO_Rem && isa(L);
-  };
-  if (BinOp->getOpcode() == BO_Add) {
-if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS))
+  }
+
+private:
+  bool handleBinaryOp(clang::BinaryOperatorKind Opcode, const Expr *const LHS,
+  const Expr *const RHS) const {
+//(c++ integer promotion rules make this an
+// 

[PATCH] D59360: [clang-tidy] Fix more false positives for bugprone-string-integer-assignment

2019-03-14 Thread Clement Courbet via Phabricator via cfe-commits
courbet marked 3 inline comments as done.
courbet added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp:115
+Expr::EvalResult EvalResult;
+if (!E->EvaluateAsInt(EvalResult, Ctx, Expr::SE_AllowSideEffects))
+  return false;

alexfh wrote:
> I believe you should also check (or assert) that `E` is not 
> instantiation-dependent before running the evaluator.
Interesting. AFAICT if I don't check that , I end up warning in the cases when 
the instantiation does result in a too large constant, which is what we want 
(the user should add a cast if they want to silence this). 


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D59360



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


[PATCH] D59360: [clang-tidy] Fix more false positives for bugprone-string-integer-assignment

2019-03-14 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 190610.
courbet added a comment.

Address review comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D59360

Files:
  clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
  clang-tools-extra/test/clang-tidy/bugprone-string-integer-assignment.cpp

Index: clang-tools-extra/test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- clang-tools-extra/test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ clang-tools-extra/test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -7,6 +7,8 @@
   basic_string& operator=(basic_string);
   basic_string& operator+=(T);
   basic_string& operator+=(basic_string);
+  const T &operator[](int i) const;
+  T &operator[](int i);
 };
 
 typedef basic_string string;
@@ -21,10 +23,13 @@
 
 typedef int MyArcaneChar;
 
+constexpr char kCharConstant = 'a';
+
 int main() {
   std::string s;
   std::wstring ws;
   int x = 5;
+  const char c = 'c';
 
   s = 6;
 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a character code when assigning {{.*}} [bugprone-string-integer-assignment]
@@ -58,12 +63,36 @@
 
   s += toupper(x);
   s += tolower(x);
-  s += std::tolower(x);
+  s += (std::tolower(x));
+
+  s += c & s[1];
+  s += c ^ s[1];
+  s += c | s[1];
+
+  s[x] += 1;
+  s += s[x];
+  as += as[x];
 
   // Likely character expressions.
   s += x & 0xff;
   s += 0xff & x;
+  s += x % 26;
+  s += 26 % x;
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
+  // CHECK-FIXES: {{^}}  s += std::to_string(26 % x);{{$}}
+  s += c | 0x80;
+  s += c | 0x8000;
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
+  // CHECK-FIXES: {{^}}  s += std::to_string(c | 0x8000);{{$}}
+  as += c | 0x8000;
 
   s += 'a' + (x % 26);
+  s += kCharConstant + (x % 26);
+  s += 'a' + (s[x] & 0xf);
   s += (x % 10) + 'b';
+
+  s += x > 255 ? c : x;
+  s += x > 255 ? 12 : x;
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
+  // CHECK-FIXES: {{^}}  s += std::to_string(x > 255 ? 12 : x);{{$}}
 }
Index: clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -45,38 +45,98 @@
   this);
 }
 
-static bool isLikelyCharExpression(const Expr *Argument,
-   const ASTContext &Ctx) {
-  const auto *BinOp = dyn_cast(Argument);
-  if (!BinOp)
+class CharExpressionDetector {
+public:
+  CharExpressionDetector(QualType CharType, const ASTContext &Ctx)
+  : CharType(CharType), Ctx(Ctx) {}
+
+  bool isLikelyCharExpression(const Expr *E) const {
+if (isCharTyped(E))
+  return true;
+
+if (const auto *BinOp = dyn_cast(E)) {
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  // Handle both directions, e.g. `'a' + (i % 26)` and `(i % 26) + 'a'`.
+  if (BinOp->isAdditiveOp() || BinOp->isBitwiseOp())
+return handleBinaryOp(BinOp->getOpcode(), LHS, RHS) ||
+   handleBinaryOp(BinOp->getOpcode(), RHS, LHS);
+  // Except in the case of '%'.
+  if (BinOp->getOpcode() == BO_Rem)
+return handleBinaryOp(BinOp->getOpcode(), LHS, RHS);
+  return false;
+}
+
+// Ternary where at least one branch is a likely char expression, e.g.
+//i < 265 ? i : ' '
+if (const auto *CondOp = dyn_cast(E))
+  return isLikelyCharExpression(
+ CondOp->getFalseExpr()->IgnoreParenImpCasts()) ||
+ isLikelyCharExpression(
+ CondOp->getTrueExpr()->IgnoreParenImpCasts());
 return false;
-  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
-  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
-  //  & , mask is a compile time constant.
-  Expr::EvalResult RHSVal;
-  if (BinOp->getOpcode() == BO_And &&
-  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
-   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects)))
-return true;
-  //  + ( % ), where  is a char literal.
-  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
-const auto *ROp = dyn_cast(R);
-return ROp && ROp->getOpcode() == BO_Rem && isa(L);
-  };
-  if (BinOp->getOpcode() == BO_Add) {
-if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS))
+  }
+
+private:
+  bool handleBinaryOp(clang::BinaryOperatorKind Opcode, const Expr *const LHS,
+  const Expr *const RHS) const {
+//(c++ integer promotion rules make this an
+// int), e.g.
+//'a' + c
+if (isCharTyped(LHS) && isCharTyped

[PATCH] D59360: [clang-tidy] Fix more false positives for bugprone-string-integer-assignment

2019-03-22 Thread Clement Courbet via Phabricator via cfe-commits
courbet marked 2 inline comments as done.
courbet added inline comments.



Comment at: 
clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp:115
+Expr::EvalResult EvalResult;
+if (!E->EvaluateAsInt(EvalResult, Ctx, Expr::SE_AllowSideEffects))
+  return false;

alexfh wrote:
> courbet wrote:
> > alexfh wrote:
> > > I believe you should also check (or assert) that `E` is not 
> > > instantiation-dependent before running the evaluator.
> > Interesting. AFAICT if I don't check that , I end up warning in the cases 
> > when the instantiation does result in a too large constant, which is what 
> > we want (the user should add a cast if they want to silence this). 
> IIUC, expression evaluation is just not supposed to be used on 
> instantiation-dependent expressions. I've recently fixed a related crash 
> (https://reviews.llvm.org/rL355401). I guess, there's a similar possibility 
> here.
Thanks for the pointer.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D59360



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


[PATCH] D59360: [clang-tidy] Fix more false positives for bugprone-string-integer-assignment

2019-03-22 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 191885.
courbet added a comment.

Ignore template contexts and add a test.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D59360

Files:
  clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
  clang-tools-extra/test/clang-tidy/bugprone-string-integer-assignment.cpp

Index: clang-tools-extra/test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- clang-tools-extra/test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ clang-tools-extra/test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -7,6 +7,8 @@
   basic_string& operator=(basic_string);
   basic_string& operator+=(T);
   basic_string& operator+=(basic_string);
+  const T &operator[](int i) const;
+  T &operator[](int i);
 };
 
 typedef basic_string string;
@@ -21,10 +23,13 @@
 
 typedef int MyArcaneChar;
 
+constexpr char kCharConstant = 'a';
+
 int main() {
   std::string s;
   std::wstring ws;
   int x = 5;
+  const char c = 'c';
 
   s = 6;
 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: an integer is interpreted as a character code when assigning {{.*}} [bugprone-string-integer-assignment]
@@ -58,12 +63,47 @@
 
   s += toupper(x);
   s += tolower(x);
-  s += std::tolower(x);
+  s += (std::tolower(x));
+
+  s += c & s[1];
+  s += c ^ s[1];
+  s += c | s[1];
+
+  s[x] += 1;
+  s += s[x];
+  as += as[x];
 
   // Likely character expressions.
   s += x & 0xff;
   s += 0xff & x;
+  s += x % 26;
+  s += 26 % x;
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
+  // CHECK-FIXES: {{^}}  s += std::to_string(26 % x);{{$}}
+  s += c | 0x80;
+  s += c | 0x8000;
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
+  // CHECK-FIXES: {{^}}  s += std::to_string(c | 0x8000);{{$}}
+  as += c | 0x8000;
 
   s += 'a' + (x % 26);
+  s += kCharConstant + (x % 26);
+  s += 'a' + (s[x] & 0xf);
   s += (x % 10) + 'b';
+
+  s += x > 255 ? c : x;
+  s += x > 255 ? 12 : x;
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
+  // CHECK-FIXES: {{^}}  s += std::to_string(x > 255 ? 12 : x);{{$}}
+}
+
+namespace instantiation_dependent_exprs {
+template
+struct S {
+  static constexpr T t = 0x8000;
+  std::string s;
+  void f(char c) { s += c | static_cast(t); }
+};
+
+template S;
 }
Index: clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -45,38 +45,100 @@
   this);
 }
 
-static bool isLikelyCharExpression(const Expr *Argument,
-   const ASTContext &Ctx) {
-  const auto *BinOp = dyn_cast(Argument);
-  if (!BinOp)
+class CharExpressionDetector {
+public:
+  CharExpressionDetector(QualType CharType, const ASTContext &Ctx)
+  : CharType(CharType), Ctx(Ctx) {}
+
+  bool isLikelyCharExpression(const Expr *E) const {
+if (isCharTyped(E))
+  return true;
+
+if (const auto *BinOp = dyn_cast(E)) {
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  // Handle both directions, e.g. `'a' + (i % 26)` and `(i % 26) + 'a'`.
+  if (BinOp->isAdditiveOp() || BinOp->isBitwiseOp())
+return handleBinaryOp(BinOp->getOpcode(), LHS, RHS) ||
+   handleBinaryOp(BinOp->getOpcode(), RHS, LHS);
+  // Except in the case of '%'.
+  if (BinOp->getOpcode() == BO_Rem)
+return handleBinaryOp(BinOp->getOpcode(), LHS, RHS);
+  return false;
+}
+
+// Ternary where at least one branch is a likely char expression, e.g.
+//i < 265 ? i : ' '
+if (const auto *CondOp = dyn_cast(E))
+  return isLikelyCharExpression(
+ CondOp->getFalseExpr()->IgnoreParenImpCasts()) ||
+ isLikelyCharExpression(
+ CondOp->getTrueExpr()->IgnoreParenImpCasts());
 return false;
-  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
-  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
-  //  & , mask is a compile time constant.
-  Expr::EvalResult RHSVal;
-  if (BinOp->getOpcode() == BO_And &&
-  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
-   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects)))
-return true;
-  //  + ( % ), where  is a char literal.
-  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
-const auto *ROp = dyn_cast(R);
-return ROp && ROp->getOpcode() == BO_Rem && isa(L);
-  };
-  if (BinOp->getOpcode() == BO_Add) {
-if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS))
+  }
+
+private:
+  bool handleBinaryOp(clang::BinaryOperatorKind Opcode, con

[PATCH] D59360: [clang-tidy] Fix more false positives for bugprone-string-integer-assignment

2019-03-25 Thread Clement Courbet via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
courbet marked an inline comment as done.
Closed by commit rL356871: [clang-tidy] Fix more false positives for 
bugprone-string-integer-assignment (authored by courbet, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D59360?vs=191885&id=192054#toc

Repository:
  rL LLVM

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

https://reviews.llvm.org/D59360

Files:
  clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
  clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp

Index: clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -45,38 +45,100 @@
   this);
 }
 
-static bool isLikelyCharExpression(const Expr *Argument,
-   const ASTContext &Ctx) {
-  const auto *BinOp = dyn_cast(Argument);
-  if (!BinOp)
+class CharExpressionDetector {
+public:
+  CharExpressionDetector(QualType CharType, const ASTContext &Ctx)
+  : CharType(CharType), Ctx(Ctx) {}
+
+  bool isLikelyCharExpression(const Expr *E) const {
+if (isCharTyped(E))
+  return true;
+
+if (const auto *BinOp = dyn_cast(E)) {
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  // Handle both directions, e.g. `'a' + (i % 26)` and `(i % 26) + 'a'`.
+  if (BinOp->isAdditiveOp() || BinOp->isBitwiseOp())
+return handleBinaryOp(BinOp->getOpcode(), LHS, RHS) ||
+   handleBinaryOp(BinOp->getOpcode(), RHS, LHS);
+  // Except in the case of '%'.
+  if (BinOp->getOpcode() == BO_Rem)
+return handleBinaryOp(BinOp->getOpcode(), LHS, RHS);
+  return false;
+}
+
+// Ternary where at least one branch is a likely char expression, e.g.
+//i < 265 ? i : ' '
+if (const auto *CondOp = dyn_cast(E))
+  return isLikelyCharExpression(
+ CondOp->getFalseExpr()->IgnoreParenImpCasts()) ||
+ isLikelyCharExpression(
+ CondOp->getTrueExpr()->IgnoreParenImpCasts());
 return false;
-  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
-  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
-  //  & , mask is a compile time constant.
-  Expr::EvalResult RHSVal;
-  if (BinOp->getOpcode() == BO_And &&
-  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
-   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects)))
-return true;
-  //  + ( % ), where  is a char literal.
-  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
-const auto *ROp = dyn_cast(R);
-return ROp && ROp->getOpcode() == BO_Rem && isa(L);
-  };
-  if (BinOp->getOpcode() == BO_Add) {
-if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS))
+  }
+
+private:
+  bool handleBinaryOp(clang::BinaryOperatorKind Opcode, const Expr *const LHS,
+  const Expr *const RHS) const {
+//(c++ integer promotion rules make this an
+// int), e.g.
+//'a' + c
+if (isCharTyped(LHS) && isCharTyped(RHS))
   return true;
+
+//  &  or  % , e.g.
+//i & 0xff
+if ((Opcode == BO_And || Opcode == BO_Rem) && isCharValuedConstant(RHS))
+  return true;
+
+//  | , e.g.
+//c | 0x80
+if (Opcode == BO_Or && isCharTyped(LHS) && isCharValuedConstant(RHS))
+  return true;
+
+//  + , e.g.
+//'a' + (i % 26)
+if (Opcode == BO_Add)
+  return isCharConstant(LHS) && isLikelyCharExpression(RHS);
+
+return false;
   }
-  return false;
-}
+
+  // Returns true if `E` is an character constant.
+  bool isCharConstant(const Expr *E) const {
+return isCharTyped(E) && isCharValuedConstant(E);
+  };
+
+  // Returns true if `E` is an integer constant which fits in `CharType`.
+  bool isCharValuedConstant(const Expr *E) const {
+if (E->isInstantiationDependent())
+  return false;
+Expr::EvalResult EvalResult;
+if (!E->EvaluateAsInt(EvalResult, Ctx, Expr::SE_AllowSideEffects))
+  return false;
+return EvalResult.Val.getInt().getActiveBits() <= Ctx.getTypeSize(CharType);
+  };
+
+  // Returns true if `E` has the right character type.
+  bool isCharTyped(const Expr *E) const {
+return E->getType().getCanonicalType().getTypePtr() ==
+   CharType.getTypePtr();
+  };
+
+  const QualType CharType;
+  const ASTContext &Ctx;
+};
 
 void StringIntegerAssignmentCheck::check(
 const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs("expr");
+  const auto CharType =
+  Result.Nodes.getNodeAs("type")->getC

[PATCH] D60719: Demonstrate how to fix freestanding for memcpy

2019-04-17 Thread Clement Courbet via Phabricator via cfe-commits
courbet added a comment.

As discussed offline, I think this should go through an RFC process.

I guess the main reservation that people will have is that this might generate 
a very large number of load stores (because we don't have a good way to 
generate loops here). This is not an issue for X86 because of REPMOVS, but it 
would be cool to have the opinion of people familiar with other architectures. 
One way to tackle this issue could be to expand existing `mem*` functions 
before the DAG. This is already happening for `memcmp` in `ExpandMemcmp`, which 
could be made aware of this flag. Similar approaches could be used for other 
`mem*` functions. But eventually this has to be handled here as the dag itself 
can call `getMemcpy()`.

Also, the current approach does not protect against current users and future 
unsavvy users calling `SelectionDAG::getMemcpy` with `AlwaysAlign == false`, so 
what about actually retrieving the flag //within// the function instead of 
outside ? This happens e.g. in `SelectionDAG::visitMemPCpyCall()`m 
`AArch64TargetLowering::LowerCall` and others.




Comment at: clang/test/CodeGen/freestanding-disables-libc.c:6
+
+// NOTE: Test that assembly doesn't call memcpy function in freestanding mode.
+// RUN: %clang_cc1 -triple i386-unknown-unknown -O2 -S %s -o - | grep 'memcpy'

That's the responsibility of LLVM, so this test should be in 
`llvm/test/Codegen`.



Comment at: llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp:6093
 
+  assert(MF->getFunction().getParent()->getModuleFlag("force-inline-libc") ==
+ nullptr);

Please add an error message (maybe "modules with 'force-inline-libc' should 
never emit library calls")



Comment at: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp:5483
 
+static bool IsForceInlineLibc(const SelectionDAG &DAG) {
+  const Module *M = DAG.getMachineFunction().getFunction().getParent();

isForceInlineLibc


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D60719



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


[PATCH] D58120: [Builtins] Treat `bcmp` as a builtin.

2019-02-12 Thread Clement Courbet via Phabricator via cfe-commits
courbet created this revision.
courbet added a reviewer: jyknight.
Herald added a subscriber: kristina.
Herald added a project: clang.

This makes it consistent with `memcmp` and `__builtin_bcmp`.

Also see the discussion in https://reviews.llvm.org/D56593.


Repository:
  rC Clang

https://reviews.llvm.org/D58120

Files:
  include/clang/Basic/Builtins.def
  lib/AST/Decl.cpp
  lib/AST/ExprConstant.cpp
  lib/Sema/SemaChecking.cpp

Index: lib/Sema/SemaChecking.cpp
===
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -9174,23 +9174,23 @@
 getContainedDynamicClass(PointeeTy, IsContained)) {
 
   unsigned OperationType = 0;
+  const bool IsCmp = BId == Builtin::BImemcmp || BId == Builtin::BIbcmp;
   // "overwritten" if we're warning about the destination for any call
   // but memcmp; otherwise a verb appropriate to the call.
-  if (ArgIdx != 0 || BId == Builtin::BImemcmp) {
+  if (ArgIdx != 0 || IsCmp) {
 if (BId == Builtin::BImemcpy)
   OperationType = 1;
 else if(BId == Builtin::BImemmove)
   OperationType = 2;
-else if (BId == Builtin::BImemcmp)
+else if (IsCmp)
   OperationType = 3;
   }
 
-  DiagRuntimeBehavior(
-Dest->getExprLoc(), Dest,
-PDiag(diag::warn_dyn_class_memaccess)
-  << (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx)
-  << FnName << IsContained << ContainedRD << OperationType
-  << Call->getCallee()->getSourceRange());
+  DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
+  PDiag(diag::warn_dyn_class_memaccess)
+  << (IsCmp ? ArgIdx + 2 : ArgIdx) << FnName
+  << IsContained << ContainedRD << OperationType
+  << Call->getCallee()->getSourceRange());
 } else if (PointeeTy.hasNonTrivialObjCLifetime() &&
  BId != Builtin::BImemset)
   DiagRuntimeBehavior(
Index: lib/AST/ExprConstant.cpp
===
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -8426,6 +8426,7 @@
   case Builtin::BIstrncmp:
   case Builtin::BIwcsncmp:
   case Builtin::BImemcmp:
+  case Builtin::BIbcmp:
   case Builtin::BIwmemcmp:
 // A call to strlen is not a constant expression.
 if (Info.getLangOpts().CPlusPlus11)
@@ -8440,6 +8441,7 @@
   case Builtin::BI__builtin_strncmp:
   case Builtin::BI__builtin_wcsncmp:
   case Builtin::BI__builtin_memcmp:
+  case Builtin::BI__builtin_bcmp:
   case Builtin::BI__builtin_wmemcmp: {
 LValue String1, String2;
 if (!EvaluatePointer(E->getArg(0), String1, Info) ||
@@ -8470,7 +8472,9 @@
 QualType CharTy2 = String2.Designator.getType(Info.Ctx);
 
 bool IsRawByte = BuiltinOp == Builtin::BImemcmp ||
- BuiltinOp == Builtin::BI__builtin_memcmp;
+ BuiltinOp == Builtin::BIbcmp ||
+ BuiltinOp == Builtin::BI__builtin_memcmp ||
+ BuiltinOp == Builtin::BI__builtin_bcmp;
 
 assert(IsRawByte ||
(Info.Ctx.hasSameUnqualifiedType(
@@ -8538,10 +8542,12 @@
   return Success(0, E);
 }
 
-bool StopAtNull = (BuiltinOp != Builtin::BImemcmp &&
-   BuiltinOp != Builtin::BIwmemcmp &&
-   BuiltinOp != Builtin::BI__builtin_memcmp &&
-   BuiltinOp != Builtin::BI__builtin_wmemcmp);
+bool StopAtNull =
+(BuiltinOp != Builtin::BImemcmp && BuiltinOp != Builtin::BIbcmp &&
+ BuiltinOp != Builtin::BIwmemcmp &&
+ BuiltinOp != Builtin::BI__builtin_memcmp &&
+ BuiltinOp != Builtin::BI__builtin_bcmp &&
+ BuiltinOp != Builtin::BI__builtin_wmemcmp);
 bool IsWide = BuiltinOp == Builtin::BIwcscmp ||
   BuiltinOp == Builtin::BIwcsncmp ||
   BuiltinOp == Builtin::BIwmemcmp ||
Index: lib/AST/Decl.cpp
===
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -3672,6 +3672,10 @@
   case Builtin::BImemcmp:
 return Builtin::BImemcmp;
 
+  case Builtin::BI__builtin_bcmp:
+  case Builtin::BIbcmp:
+return Builtin::BIbcmp;
+
   case Builtin::BI__builtin_strncpy:
   case Builtin::BI__builtin___strncpy_chk:
   case Builtin::BIstrncpy:
@@ -3712,6 +3716,8 @@
 return Builtin::BImemmove;
   else if (FnInfo->isStr("memcmp"))
 return Builtin::BImemcmp;
+  else if (FnInfo->isStr("bcmp"))
+return Builtin::BIbcmp;
   else if (FnInfo->isStr("strncpy"))
 return Builtin::BIstrncpy;
   else if (FnInfo->isStr("strncmp"))
Index: include/clang/Basic/Builtins.def
===
--- include/clang/Basic/Builtins.def
+++ include/clang/Basic/Builtins.def
@@ -953,6 +953,7 @@
 LIBBUILTIN(index, "c*cC*i",   "f", "strings.h", ALL_

[PATCH] D58120: [Builtins] Treat `bcmp` as a builtin.

2019-02-13 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 186644.
courbet added a comment.
Herald added a subscriber: jdoerfert.

- Add tests for warnings.
- Fix signature for intrinsic.


Repository:
  rC Clang

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

https://reviews.llvm.org/D58120

Files:
  include/clang/Basic/Builtins.def
  lib/AST/Decl.cpp
  lib/AST/ExprConstant.cpp
  lib/Sema/SemaChecking.cpp
  test/SemaCXX/constexpr-string.cpp
  test/SemaCXX/warn-bad-memaccess.cpp

Index: test/SemaCXX/warn-bad-memaccess.cpp
===
--- test/SemaCXX/warn-bad-memaccess.cpp
+++ test/SemaCXX/warn-bad-memaccess.cpp
@@ -3,7 +3,8 @@
 extern "C" void *memset(void *, int, unsigned);
 extern "C" void *memmove(void *s1, const void *s2, unsigned n);
 extern "C" void *memcpy(void *s1, const void *s2, unsigned n);
-extern "C" void *memcmp(void *s1, const void *s2, unsigned n);
+extern "C" int memcmp(void *s1, const void *s2, unsigned n);
+extern "C" int bcmp(void *s1, const void *s2, unsigned n);
 
 
 // Redeclare without the extern "C" to test that we still figure out that this
@@ -59,6 +60,12 @@
   memcmp(0, &x1, sizeof x1); // \
   // expected-warning{{second operand of this 'memcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
   // expected-note {{explicitly cast the pointer to silence this warning}}
+  bcmp(&x1, 0, sizeof x1); // \
+  // expected-warning{{first operand of this 'bcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
+  // expected-note {{explicitly cast the pointer to silence this warning}}
+  bcmp(0, &x1, sizeof x1); // \
+  // expected-warning{{second operand of this 'bcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
+  // expected-note {{explicitly cast the pointer to silence this warning}}
 
   __builtin_memset(&x1, 0, sizeof x1); // \
   // expected-warning {{destination for this '__builtin_memset' call is a pointer to dynamic class}} \
Index: test/SemaCXX/constexpr-string.cpp
===
--- test/SemaCXX/constexpr-string.cpp
+++ test/SemaCXX/constexpr-string.cpp
@@ -1,7 +1,9 @@
 // RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension
+// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=gnu++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -DGNUMODE
 // RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-signed-char
 // RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-wchar -DNO_PREDEFINED_WCHAR_T
 // RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension
+// RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=gnu++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -DGNUMODE
 // RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-signed-char
 // RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-wchar -DNO_PREDEFINED_WCHAR_T
 
@@ -15,6 +17,10 @@
   extern int strncmp(const char *s1, const char *s2, size_t n);
   extern int memcmp(const void *s1, const void *s2, size_t n);
 
+#ifdef GNUMODE
+  extern int bcmp(const void *s1, const void *s2, size_t n);
+#endif
+
   extern char *strchr(const char *s, int c);
   extern void *memchr(const void *s, int c, size_t n);
 
@@ -151,6 +157,10 @@
   constexpr int a = strcmp("hello", "world"); // expected-error {{constant expression}} expected-note {{non-constexpr function 'strcmp' cannot be used in a constant expression}}
   constexpr int b = strncmp("hello", "world", 3); // expected-error {{constant expression}} expected-note {{non-constexpr function 'strncmp' cannot be used in a constant expression}}
   constexpr int c = memcmp("hello", "world", 3); // expected-error {{constant expression}} expected-note {{non-constexpr function 'memcmp' cannot be used in a constant expression}}
+
+#ifdef GNUMODE
+  constexpr int d = bcmp("hello", "world", 3); // expected-error {{constant expression}} expected-note {{non-constexpr function 'bcmp' cannot be used in a constant expression}}
+#endif
 }
 
 namespace MultibyteElementTests {
Index: lib/Sema/SemaChecking.cpp
===
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -9174,23 +9174,23 @@
 getContainedDynamicClass(PointeeTy, IsContained)) {
 
   unsigned OperationType = 0;
+  const bool IsCmp = BId == Builtin::BImemcmp || BId == Builtin::BIbcmp;
   // "overwritten" if we're warning about the destination for any call
   // but memcmp; otherwise a verb appropriate to the call.
-  if (ArgIdx != 0 || BId == Builtin::BImemcmp) 

[PATCH] D58120: [Builtins] Treat `bcmp` as a builtin.

2019-02-13 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 186645.
courbet added a comment.

- add __builtin_bcmp constant evaluation tests.


Repository:
  rC Clang

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

https://reviews.llvm.org/D58120

Files:
  include/clang/Basic/Builtins.def
  lib/AST/Decl.cpp
  lib/AST/ExprConstant.cpp
  lib/Sema/SemaChecking.cpp
  test/SemaCXX/constexpr-string.cpp
  test/SemaCXX/warn-bad-memaccess.cpp

Index: test/SemaCXX/warn-bad-memaccess.cpp
===
--- test/SemaCXX/warn-bad-memaccess.cpp
+++ test/SemaCXX/warn-bad-memaccess.cpp
@@ -3,7 +3,8 @@
 extern "C" void *memset(void *, int, unsigned);
 extern "C" void *memmove(void *s1, const void *s2, unsigned n);
 extern "C" void *memcpy(void *s1, const void *s2, unsigned n);
-extern "C" void *memcmp(void *s1, const void *s2, unsigned n);
+extern "C" int memcmp(void *s1, const void *s2, unsigned n);
+extern "C" int bcmp(void *s1, const void *s2, unsigned n);
 
 
 // Redeclare without the extern "C" to test that we still figure out that this
@@ -59,6 +60,12 @@
   memcmp(0, &x1, sizeof x1); // \
   // expected-warning{{second operand of this 'memcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
   // expected-note {{explicitly cast the pointer to silence this warning}}
+  bcmp(&x1, 0, sizeof x1); // \
+  // expected-warning{{first operand of this 'bcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
+  // expected-note {{explicitly cast the pointer to silence this warning}}
+  bcmp(0, &x1, sizeof x1); // \
+  // expected-warning{{second operand of this 'bcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
+  // expected-note {{explicitly cast the pointer to silence this warning}}
 
   __builtin_memset(&x1, 0, sizeof x1); // \
   // expected-warning {{destination for this '__builtin_memset' call is a pointer to dynamic class}} \
Index: test/SemaCXX/constexpr-string.cpp
===
--- test/SemaCXX/constexpr-string.cpp
+++ test/SemaCXX/constexpr-string.cpp
@@ -1,7 +1,9 @@
 // RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension
+// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=gnu++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -DGNUMODE
 // RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-signed-char
 // RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-wchar -DNO_PREDEFINED_WCHAR_T
 // RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension
+// RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=gnu++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -DGNUMODE
 // RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-signed-char
 // RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-wchar -DNO_PREDEFINED_WCHAR_T
 
@@ -15,6 +17,10 @@
   extern int strncmp(const char *s1, const char *s2, size_t n);
   extern int memcmp(const void *s1, const void *s2, size_t n);
 
+#ifdef GNUMODE
+  extern int bcmp(const void *s1, const void *s2, size_t n);
+#endif
+
   extern char *strchr(const char *s, int c);
   extern void *memchr(const void *s, int c, size_t n);
 
@@ -101,12 +107,28 @@
   static_assert(__builtin_memcmp("abab\0banana", "abab\0canada", 6) == -1);
   static_assert(__builtin_memcmp("abab\0banana", "abab\0canada", 5) == 0);
 
+  static_assert(__builtin_bcmp("abaa", "abba", 3) != 0);
+  static_assert(__builtin_bcmp("abaa", "abba", 2) == 0);
+  static_assert(__builtin_bcmp("a\203", "a", 2) != 0);
+  static_assert(__builtin_bcmp("a\203", "a\003", 2) != 0);
+  static_assert(__builtin_bcmp(0, 0, 0) == 0);
+  static_assert(__builtin_bcmp("abab\0banana", "abab\0banana", 100) == 0); // expected-error {{not an integral constant}} expected-note {{dereferenced one-past-the-end}}
+  static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 100) != 0); // FIXME: Should we reject this?
+  static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 7) != 0);
+  static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 6) != 0);
+  static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 5) == 0);
+
   extern struct Incomplete incomplete;
   static_assert(__builtin_memcmp(&incomplete, "", 0u) == 0);
   static_assert(__builtin_memcmp("", &incomplete, 0u) == 0);
   static_assert(__builtin_memcmp(&incomplete, "", 1u) == 42); // expected-error {{not an integral constant}} expected-note {{read of incomplete type 'struct Incomplete'}}
   static_assert(__builtin_memcmp("", &incomplete, 1u) == 42); // expected-error {{not an integral constant}} expecte

[PATCH] D58120: [Builtins] Treat `bcmp` as a builtin.

2019-02-13 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 186651.
courbet added a comment.

Update tests after constness changes.


Repository:
  rC Clang

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

https://reviews.llvm.org/D58120

Files:
  include/clang/Basic/Builtins.def
  lib/AST/Decl.cpp
  lib/AST/ExprConstant.cpp
  lib/Sema/SemaChecking.cpp
  test/Analysis/bstring.c
  test/Analysis/security-syntax-checks.m
  test/SemaCXX/constexpr-string.cpp
  test/SemaCXX/warn-bad-memaccess.cpp

Index: test/SemaCXX/warn-bad-memaccess.cpp
===
--- test/SemaCXX/warn-bad-memaccess.cpp
+++ test/SemaCXX/warn-bad-memaccess.cpp
@@ -3,7 +3,8 @@
 extern "C" void *memset(void *, int, unsigned);
 extern "C" void *memmove(void *s1, const void *s2, unsigned n);
 extern "C" void *memcpy(void *s1, const void *s2, unsigned n);
-extern "C" void *memcmp(void *s1, const void *s2, unsigned n);
+extern "C" int memcmp(void *s1, const void *s2, unsigned n);
+extern "C" int bcmp(void *s1, const void *s2, unsigned n);
 
 
 // Redeclare without the extern "C" to test that we still figure out that this
@@ -59,6 +60,12 @@
   memcmp(0, &x1, sizeof x1); // \
   // expected-warning{{second operand of this 'memcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
   // expected-note {{explicitly cast the pointer to silence this warning}}
+  bcmp(&x1, 0, sizeof x1); // \
+  // expected-warning{{first operand of this 'bcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
+  // expected-note {{explicitly cast the pointer to silence this warning}}
+  bcmp(0, &x1, sizeof x1); // \
+  // expected-warning{{second operand of this 'bcmp' call is a pointer to dynamic class 'X1'; vtable pointer will be compared}} \
+  // expected-note {{explicitly cast the pointer to silence this warning}}
 
   __builtin_memset(&x1, 0, sizeof x1); // \
   // expected-warning {{destination for this '__builtin_memset' call is a pointer to dynamic class}} \
Index: test/SemaCXX/constexpr-string.cpp
===
--- test/SemaCXX/constexpr-string.cpp
+++ test/SemaCXX/constexpr-string.cpp
@@ -1,7 +1,9 @@
 // RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension
+// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=gnu++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -DGNUMODE
 // RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-signed-char
 // RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-wchar -DNO_PREDEFINED_WCHAR_T
 // RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension
+// RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=gnu++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -DGNUMODE
 // RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-signed-char
 // RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-wchar -DNO_PREDEFINED_WCHAR_T
 
@@ -15,6 +17,10 @@
   extern int strncmp(const char *s1, const char *s2, size_t n);
   extern int memcmp(const void *s1, const void *s2, size_t n);
 
+#ifdef GNUMODE
+  extern int bcmp(const void *s1, const void *s2, size_t n);
+#endif
+
   extern char *strchr(const char *s, int c);
   extern void *memchr(const void *s, int c, size_t n);
 
@@ -101,12 +107,28 @@
   static_assert(__builtin_memcmp("abab\0banana", "abab\0canada", 6) == -1);
   static_assert(__builtin_memcmp("abab\0banana", "abab\0canada", 5) == 0);
 
+  static_assert(__builtin_bcmp("abaa", "abba", 3) != 0);
+  static_assert(__builtin_bcmp("abaa", "abba", 2) == 0);
+  static_assert(__builtin_bcmp("a\203", "a", 2) != 0);
+  static_assert(__builtin_bcmp("a\203", "a\003", 2) != 0);
+  static_assert(__builtin_bcmp(0, 0, 0) == 0);
+  static_assert(__builtin_bcmp("abab\0banana", "abab\0banana", 100) == 0); // expected-error {{not an integral constant}} expected-note {{dereferenced one-past-the-end}}
+  static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 100) != 0); // FIXME: Should we reject this?
+  static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 7) != 0);
+  static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 6) != 0);
+  static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 5) == 0);
+
   extern struct Incomplete incomplete;
   static_assert(__builtin_memcmp(&incomplete, "", 0u) == 0);
   static_assert(__builtin_memcmp("", &incomplete, 0u) == 0);
   static_assert(__builtin_memcmp(&incomplete, "", 1u) == 42); // expected-error {{not an integral constant}} expected-note {{read of incomplete type 'struct Incomplete'}}
   static_assert(__builtin_memcmp("", &incomplete, 1u) == 42

[PATCH] D58120: [Builtins] Treat `bcmp` as a builtin.

2019-02-14 Thread Clement Courbet via Phabricator via cfe-commits
courbet added a comment.

Thanks.


Repository:
  rC Clang

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

https://reviews.llvm.org/D58120



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


[PATCH] D58120: [Builtins] Treat `bcmp` as a builtin.

2019-02-14 Thread Clement Courbet via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC354023: [Builtins] Treat `bcmp` as a builtin. (authored by 
courbet, committed by ).

Changed prior to commit:
  https://reviews.llvm.org/D58120?vs=186651&id=186814#toc

Repository:
  rC Clang

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

https://reviews.llvm.org/D58120

Files:
  include/clang/Basic/Builtins.def
  lib/AST/Decl.cpp
  lib/AST/ExprConstant.cpp
  lib/Sema/SemaChecking.cpp
  test/Analysis/bstring.c
  test/Analysis/security-syntax-checks.m
  test/SemaCXX/constexpr-string.cpp
  test/SemaCXX/warn-bad-memaccess.cpp

Index: include/clang/Basic/Builtins.def
===
--- include/clang/Basic/Builtins.def
+++ include/clang/Basic/Builtins.def
@@ -448,7 +448,7 @@
 BUILTIN(__builtin_va_copy, "vAA", "n")
 BUILTIN(__builtin_stdarg_start, "vA.", "n")
 BUILTIN(__builtin_assume_aligned, "v*vC*z.", "nc")
-BUILTIN(__builtin_bcmp, "iv*v*z", "Fn")
+BUILTIN(__builtin_bcmp, "ivC*vC*z", "Fn")
 BUILTIN(__builtin_bcopy, "vv*v*z", "n")
 BUILTIN(__builtin_bzero, "vv*z", "nF")
 BUILTIN(__builtin_fprintf, "iP*cC*.", "Fp:1:")
@@ -953,6 +953,7 @@
 LIBBUILTIN(index, "c*cC*i",   "f", "strings.h", ALL_GNU_LANGUAGES)
 LIBBUILTIN(rindex, "c*cC*i",  "f", "strings.h", ALL_GNU_LANGUAGES)
 LIBBUILTIN(bzero, "vv*z", "f", "strings.h", ALL_GNU_LANGUAGES)
+LIBBUILTIN(bcmp, "ivC*vC*z",  "f", "strings.h", ALL_GNU_LANGUAGES)
 // In some systems str[n]casejmp is a macro that expands to _str[n]icmp.
 // We undefine then here to avoid wrong name.
 #undef strcasecmp
Index: test/Analysis/bstring.c
===
--- test/Analysis/bstring.c
+++ test/Analysis/bstring.c
@@ -361,8 +361,7 @@
 #ifdef VARIANT
 
 #define bcmp BUILTIN(bcmp)
-// __builtin_bcmp is not defined with const in Builtins.def.
-int bcmp(/*const*/ void *s1, /*const*/ void *s2, size_t n);
+int bcmp(const void *s1, const void *s2, size_t n);
 #define memcmp bcmp
 // 
 #else /* VARIANT */
Index: test/Analysis/security-syntax-checks.m
===
--- test/Analysis/security-syntax-checks.m
+++ test/Analysis/security-syntax-checks.m
@@ -41,7 +41,7 @@
 }
 
 // Obsolete function bcmp
-int bcmp(void *, void *, size_t);
+int bcmp(const void *, const void *, size_t);
 
 int test_bcmp(void *a, void *b, size_t n) {
   return bcmp(a, b, n); // expected-warning{{The bcmp() function is obsoleted by memcmp()}}
Index: test/SemaCXX/constexpr-string.cpp
===
--- test/SemaCXX/constexpr-string.cpp
+++ test/SemaCXX/constexpr-string.cpp
@@ -1,7 +1,9 @@
 // RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension
+// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=gnu++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -DGNUMODE
 // RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-signed-char
 // RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-wchar -DNO_PREDEFINED_WCHAR_T
 // RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension
+// RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=gnu++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -DGNUMODE
 // RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-signed-char
 // RUN: %clang_cc1 %s -triple armebv7-unknown-linux -std=c++2a -fsyntax-only -verify -pedantic -Wno-vla-extension -fno-wchar -DNO_PREDEFINED_WCHAR_T
 
@@ -15,6 +17,10 @@
   extern int strncmp(const char *s1, const char *s2, size_t n);
   extern int memcmp(const void *s1, const void *s2, size_t n);
 
+#ifdef GNUMODE
+  extern int bcmp(const void *s1, const void *s2, size_t n);
+#endif
+
   extern char *strchr(const char *s, int c);
   extern void *memchr(const void *s, int c, size_t n);
 
@@ -101,12 +107,28 @@
   static_assert(__builtin_memcmp("abab\0banana", "abab\0canada", 6) == -1);
   static_assert(__builtin_memcmp("abab\0banana", "abab\0canada", 5) == 0);
 
+  static_assert(__builtin_bcmp("abaa", "abba", 3) != 0);
+  static_assert(__builtin_bcmp("abaa", "abba", 2) == 0);
+  static_assert(__builtin_bcmp("a\203", "a", 2) != 0);
+  static_assert(__builtin_bcmp("a\203", "a\003", 2) != 0);
+  static_assert(__builtin_bcmp(0, 0, 0) == 0);
+  static_assert(__builtin_bcmp("abab\0banana", "abab\0banana", 100) == 0); // expected-error {{not an integral constant}} expected-note {{dereferenced one-past-the-end}}
+  static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 100) != 0); // FIXME: Should we reject this?
+  static_assert(__builtin_bcmp("abab\0banana", "abab\0canada", 7) != 0);
+  static_assert(__builtin_bcmp("abab\0

[PATCH] D58604: [clang-tidy] misc-string-integer-assignment: ignore toupper/tolower

2019-02-25 Thread Clement Courbet via Phabricator via cfe-commits
courbet created this revision.
courbet added reviewers: xazax.hun, alexfh.
Herald added subscribers: cfe-commits, rnkovacs.
Herald added a project: clang.

Tis represents ~20% of false positives. See PR27723.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D58604

Files:
  clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
  test/clang-tidy/bugprone-string-integer-assignment.cpp


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -11,8 +11,14 @@
 
 typedef basic_string string;
 typedef basic_string wstring;
+
+int tolower(int i);
+int toupper(int i);
 }
 
+int tolower(int i);
+int toupper(int i);
+
 typedef int MyArcaneChar;
 
 int main() {
@@ -50,4 +56,7 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a 
chara
 // CHECK-FIXES: {{^}}  as = 6;{{$}}
 
+  s += toupper(x);
+  s += tolower(x);
+  s += std::tolower(x);
 }
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -27,10 +27,15 @@
   callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
   hasName("::std::basic_string"),
   hasTemplateArgument(0, 
refersToType(qualType().bind("type"))),
-  hasArgument(1,
-  ignoringImpCasts(expr(hasType(isInteger()),
-unless(hasType(isAnyCharacter(
-   .bind("expr"))),
+  hasArgument(
+  1,
+  ignoringImpCasts(
+  expr(hasType(isInteger()), unless(hasType(isAnyCharacter())),
+   // Ignore calls to tolower/toupper (see PR27723).
+   unless(callExpr(callee(functionDecl(
+   hasAnyName("tolower", "std::tolower", "toupper",
+  "std::toupper"))
+  .bind("expr"))),
   unless(isInTemplateInstantiation())),
   this);
 }


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -11,8 +11,14 @@
 
 typedef basic_string string;
 typedef basic_string wstring;
+
+int tolower(int i);
+int toupper(int i);
 }
 
+int tolower(int i);
+int toupper(int i);
+
 typedef int MyArcaneChar;
 
 int main() {
@@ -50,4 +56,7 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
 // CHECK-FIXES: {{^}}  as = 6;{{$}}
 
+  s += toupper(x);
+  s += tolower(x);
+  s += std::tolower(x);
 }
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -27,10 +27,15 @@
   callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
   hasName("::std::basic_string"),
   hasTemplateArgument(0, refersToType(qualType().bind("type"))),
-  hasArgument(1,
-  ignoringImpCasts(expr(hasType(isInteger()),
-unless(hasType(isAnyCharacter(
-   .bind("expr"))),
+  hasArgument(
+  1,
+  ignoringImpCasts(
+  expr(hasType(isInteger()), unless(hasType(isAnyCharacter())),
+   // Ignore calls to tolower/toupper (see PR27723).
+   unless(callExpr(callee(functionDecl(
+   hasAnyName("tolower", "std::tolower", "toupper",
+  "std::toupper"))
+  .bind("expr"))),
   unless(isInTemplateInstantiation())),
   this);
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D58606: [clang-tidy] misc-string-integer-assignment: fix false positive

2019-02-25 Thread Clement Courbet via Phabricator via cfe-commits
courbet created this revision.
courbet added reviewers: xazax.hun, alexfh.
Herald added subscribers: cfe-commits, rnkovacs.
Herald added a project: clang.

using CodePoint = uint32_t;
CodePoint cp;
casic_string s;
s += cp;


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D58606

Files:
  clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp


Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -29,7 +29,9 @@
   hasTemplateArgument(0, 
refersToType(qualType().bind("type"))),
   hasArgument(1,
   ignoringImpCasts(expr(hasType(isInteger()),
-unless(hasType(isAnyCharacter(
+unless(hasType(isAnyCharacter())),
+// Do not warn if assigning e.g. 
`CodePoint` to `basic_string`
+
unless(hasType(type(equalsBoundNode("type")
.bind("expr"))),
   unless(isInTemplateInstantiation())),
   this);


Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -29,7 +29,9 @@
   hasTemplateArgument(0, refersToType(qualType().bind("type"))),
   hasArgument(1,
   ignoringImpCasts(expr(hasType(isInteger()),
-unless(hasType(isAnyCharacter(
+unless(hasType(isAnyCharacter())),
+// Do not warn if assigning e.g. `CodePoint` to `basic_string`
+unless(hasType(type(equalsBoundNode("type")
.bind("expr"))),
   unless(isInTemplateInstantiation())),
   this);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D58609: [clang-tidy] bugprone-string-integer-assignment: Reduce false positives.

2019-02-25 Thread Clement Courbet via Phabricator via cfe-commits
courbet created this revision.
courbet added reviewers: xazax.hun, alexfh.
Herald added subscribers: cfe-commits, jdoerfert, rnkovacs.
Herald added a project: clang.

Detect a few expressions as likely character expressions, see PR27723.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D58609

Files:
  clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
  test/clang-tidy/bugprone-string-integer-assignment.cpp


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -50,4 +50,8 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a 
chara
 // CHECK-FIXES: {{^}}  as = 6;{{$}}
 
+  // Likely character expressions.
+  s += x & 0xff;
+
+  s += 'a' + (x % 26);
 }
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -35,11 +35,42 @@
   this);
 }
 
+static bool isLikelyCharExpression(const Expr* Argument, const ASTContext 
&Ctx) {
+  const auto* BinOp = dyn_cast(Argument);
+  if (!BinOp) {
+return false;
+  }
+  const auto* LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto* RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  //  & , mask is a compile time constant.
+  Expr::EvalResult RHSVal;
+  if (BinOp->getOpcode() == BO_And &&
+  BinOp->getRHS()->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects)) {
+  return true;
+  }
+  //  + ( % ), where  is a char literal.
+  BinOp->dump();
+  llvm::errs() << "A " << isa(LHS) << " " << 
(BinOp->getOpcode() == BO_Add)<< "\n";
+  if (isa(LHS) && BinOp->getOpcode() == BO_Add) {
+const auto* RHSOp = dyn_cast(RHS);
+llvm::errs() << "B " << RHSOp << " " << (RHSOp ? RHSOp->getOpcode() == 
BO_Rem : false)<< "\n";
+if (RHSOp && RHSOp->getOpcode() == BO_Rem) {
+  return true;
+}
+  }
+  return false;
+}
+
 void StringIntegerAssignmentCheck::check(
 const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs("expr");
   SourceLocation Loc = Argument->getBeginLoc();
 
+  // Try to detect a few common expressions to reduce false positives.
+  if (isLikelyCharExpression(Argument, *Result.Context)) {
+return;
+  }
+
   auto Diag =
   diag(Loc, "an integer is interpreted as a character code when assigning "
 "it to a string; if this is intended, cast the integer to the "


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -50,4 +50,8 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
 // CHECK-FIXES: {{^}}  as = 6;{{$}}
 
+  // Likely character expressions.
+  s += x & 0xff;
+
+  s += 'a' + (x % 26);
 }
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -35,11 +35,42 @@
   this);
 }
 
+static bool isLikelyCharExpression(const Expr* Argument, const ASTContext &Ctx) {
+  const auto* BinOp = dyn_cast(Argument);
+  if (!BinOp) {
+return false;
+  }
+  const auto* LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto* RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  //  & , mask is a compile time constant.
+  Expr::EvalResult RHSVal;
+  if (BinOp->getOpcode() == BO_And &&
+  BinOp->getRHS()->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects)) {
+  return true;
+  }
+  //  + ( % ), where  is a char literal.
+  BinOp->dump();
+  llvm::errs() << "A " << isa(LHS) << " " << (BinOp->getOpcode() == BO_Add)<< "\n";
+  if (isa(LHS) && BinOp->getOpcode() == BO_Add) {
+const auto* RHSOp = dyn_cast(RHS);
+llvm::errs() << "B " << RHSOp << " " << (RHSOp ? RHSOp->getOpcode() == BO_Rem : false)<< "\n";
+if (RHSOp && RHSOp->getOpcode() == BO_Rem) {
+  return true;
+}
+  }
+  return false;
+}
+
 void StringIntegerAssignmentCheck::check(
 const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs("expr");
   SourceLocation Loc = Argument->getBeginLoc();
 
+  // Try to detect a few common expressions to reduce false positives.
+  if (isLikelyCharExpression(Argument, *Result.Context)) {
+return;
+  }
+
   auto Diag =
   diag(Loc, "an integer is interpreted as a character code when assigning "
 "it to a string; if this is intended, cast the integer to the "
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lis

[PATCH] D58604: [clang-tidy] misc-string-integer-assignment: ignore toupper/tolower

2019-02-25 Thread Clement Courbet via Phabricator via cfe-commits
courbet added a comment.

Thanks.


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D58604



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


[PATCH] D58604: [clang-tidy] misc-string-integer-assignment: ignore toupper/tolower

2019-02-25 Thread Clement Courbet via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL354780: [clang-tidy] misc-string-integer-assignment: ignore 
toupper/tolower (authored by courbet, committed by ).
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Repository:
  rL LLVM

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

https://reviews.llvm.org/D58604

Files:
  clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
  clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp


Index: 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ 
clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -11,8 +11,14 @@
 
 typedef basic_string string;
 typedef basic_string wstring;
+
+int tolower(int i);
+int toupper(int i);
 }
 
+int tolower(int i);
+int toupper(int i);
+
 typedef int MyArcaneChar;
 
 int main() {
@@ -50,4 +56,7 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a 
chara
 // CHECK-FIXES: {{^}}  as = 6;{{$}}
 
+  s += toupper(x);
+  s += tolower(x);
+  s += std::tolower(x);
 }
Index: 
clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -27,10 +27,15 @@
   callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
   hasName("::std::basic_string"),
   hasTemplateArgument(0, 
refersToType(qualType().bind("type"))),
-  hasArgument(1,
-  ignoringImpCasts(expr(hasType(isInteger()),
-unless(hasType(isAnyCharacter(
-   .bind("expr"))),
+  hasArgument(
+  1,
+  ignoringImpCasts(
+  expr(hasType(isInteger()), unless(hasType(isAnyCharacter())),
+   // Ignore calls to tolower/toupper (see PR27723).
+   unless(callExpr(callee(functionDecl(
+   hasAnyName("tolower", "std::tolower", "toupper",
+  "std::toupper"))
+  .bind("expr"))),
   unless(isInTemplateInstantiation())),
   this);
 }


Index: clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ clang-tools-extra/trunk/test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -11,8 +11,14 @@
 
 typedef basic_string string;
 typedef basic_string wstring;
+
+int tolower(int i);
+int toupper(int i);
 }
 
+int tolower(int i);
+int toupper(int i);
+
 typedef int MyArcaneChar;
 
 int main() {
@@ -50,4 +56,7 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
 // CHECK-FIXES: {{^}}  as = 6;{{$}}
 
+  s += toupper(x);
+  s += tolower(x);
+  s += std::tolower(x);
 }
Index: clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tools-extra/trunk/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -27,10 +27,15 @@
   callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
   hasName("::std::basic_string"),
   hasTemplateArgument(0, refersToType(qualType().bind("type"))),
-  hasArgument(1,
-  ignoringImpCasts(expr(hasType(isInteger()),
-unless(hasType(isAnyCharacter(
-   .bind("expr"))),
+  hasArgument(
+  1,
+  ignoringImpCasts(
+  expr(hasType(isInteger()), unless(hasType(isAnyCharacter())),
+   // Ignore calls to tolower/toupper (see PR27723).
+   unless(callExpr(callee(functionDecl(
+   hasAnyName("tolower", "std::tolower", "toupper",
+  "std::toupper"))
+  .bind("expr"))),
   unless(isInTemplateInstantiation())),
   this);
 }
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D58609: [clang-tidy] bugprone-string-integer-assignment: Reduce false positives.

2019-02-25 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 188165.
courbet marked 3 inline comments as done.
courbet added a comment.

- address review comments


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D58609

Files:
  clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
  test/clang-tidy/bugprone-string-integer-assignment.cpp


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -50,4 +50,8 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a 
chara
 // CHECK-FIXES: {{^}}  as = 6;{{$}}
 
+  // Likely character expressions.
+  s += x & 0xff;
+
+  s += 'a' + (x % 26);
 }
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -35,11 +35,44 @@
   this);
 }
 
+static bool isLikelyCharExpression(const Expr *Argument,
+   const ASTContext &Ctx) {
+  const auto *BinOp = dyn_cast(Argument);
+  if (!BinOp) {
+return false;
+  }
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  //  & , mask is a compile time constant.
+  Expr::EvalResult RHSVal;
+  if (BinOp->getOpcode() == BO_And &&
+  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
+   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects))) {
+return true;
+  }
+  //  + ( % ), where  is a char literal.
+  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
+const auto *ROp = dyn_cast(R);
+return ROp && ROp->getOpcode() == BO_Rem && isa(L);
+  };
+  if (BinOp->getOpcode() == BO_Add) {
+if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS)) {
+  return true;
+}
+  }
+  return false;
+}
+
 void StringIntegerAssignmentCheck::check(
 const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs("expr");
   SourceLocation Loc = Argument->getBeginLoc();
 
+  // Try to detect a few common expressions to reduce false positives.
+  if (isLikelyCharExpression(Argument, *Result.Context)) {
+return;
+  }
+
   auto Diag =
   diag(Loc, "an integer is interpreted as a character code when assigning "
 "it to a string; if this is intended, cast the integer to the "


Index: test/clang-tidy/bugprone-string-integer-assignment.cpp
===
--- test/clang-tidy/bugprone-string-integer-assignment.cpp
+++ test/clang-tidy/bugprone-string-integer-assignment.cpp
@@ -50,4 +50,8 @@
 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: an integer is interpreted as a chara
 // CHECK-FIXES: {{^}}  as = 6;{{$}}
 
+  // Likely character expressions.
+  s += x & 0xff;
+
+  s += 'a' + (x % 26);
 }
Index: clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
===
--- clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
+++ clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp
@@ -35,11 +35,44 @@
   this);
 }
 
+static bool isLikelyCharExpression(const Expr *Argument,
+   const ASTContext &Ctx) {
+  const auto *BinOp = dyn_cast(Argument);
+  if (!BinOp) {
+return false;
+  }
+  const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
+  const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
+  //  & , mask is a compile time constant.
+  Expr::EvalResult RHSVal;
+  if (BinOp->getOpcode() == BO_And &&
+  (RHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects) ||
+   LHS->EvaluateAsInt(RHSVal, Ctx, Expr::SE_AllowSideEffects))) {
+return true;
+  }
+  //  + ( % ), where  is a char literal.
+  const auto IsCharPlusModExpr = [](const Expr *L, const Expr *R) {
+const auto *ROp = dyn_cast(R);
+return ROp && ROp->getOpcode() == BO_Rem && isa(L);
+  };
+  if (BinOp->getOpcode() == BO_Add) {
+if (IsCharPlusModExpr(LHS, RHS) || IsCharPlusModExpr(RHS, LHS)) {
+  return true;
+}
+  }
+  return false;
+}
+
 void StringIntegerAssignmentCheck::check(
 const MatchFinder::MatchResult &Result) {
   const auto *Argument = Result.Nodes.getNodeAs("expr");
   SourceLocation Loc = Argument->getBeginLoc();
 
+  // Try to detect a few common expressions to reduce false positives.
+  if (isLikelyCharExpression(Argument, *Result.Context)) {
+return;
+  }
+
   auto Diag =
   diag(Loc, "an integer is interpreted as a character code when assigning "
 "it to a string; if this is intended, cast the integer to the "
___
cfe-commits mailing list
cfe-commits@lists

[PATCH] D58609: [clang-tidy] bugprone-string-integer-assignment: Reduce false positives.

2019-02-25 Thread Clement Courbet via Phabricator via cfe-commits
courbet added a comment.

Thanks.


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D58609



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


[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] D55552: [Sema] Better static assert diagnostics for expressions involving temporaries.

2018-12-12 Thread Clement Courbet via Phabricator via cfe-commits
courbet planned changes to this revision.
courbet marked an inline comment as done.
courbet added inline comments.



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

Quuxplusone wrote:
> Conspicuously missing any test for lines 3081–3106 above. IIUC, those lines 
> would trigger on things like
> 
> ```
> template struct X { int i=0, j=0; constexpr operator bool() const { 
> return false; } };
> template void test() {
> static_assert(X{});
> static_assert(X{1,2});
> static_assert(T{0});
> static_assert(T(0));
> }
> template void test();
> ```
> 
> But I guess I don't see why extra code is needed to handle those; shouldn't 
> the pretty-printer handle them already? What do the current diagnostics look 
> like for my example?
Note: Your examples are `CXXFunctionalCastExpr`, and 
`CXXUnresolvedConstructExpr` respectively, not `CXXTemporaryObjectExpr`, so 
they are not handled by this change.

They are correctly printed before this change with `T==int`.

The issue comes when adding an extra layer of indirection:

```
struct ExampleTypes {
  explicit ExampleTypes(int);
  using T = int;
  using U = float;
};

template struct X {
  int i=0;
  int j=0;
  constexpr operator bool() const { return false; }
};

template void foo6() {
static_assert(X());
static_assert(X{});
static_assert(X{1,2});
static_assert(X({1,2}));
static_assert(typename T::T{0});
static_assert(typename T::T(0));
}
template void foo6();
```

The errors before the change are:
```
File 
/usr/local/google/home/courbet/llvm/llvm/tools/clang/test/SemaCXX/static-assert-cxx17.cpp
 Line 71: static_assert failed due to requirement 'X()'
  File 
/usr/local/google/home/courbet/llvm/llvm/tools/clang/test/SemaCXX/static-assert-cxx17.cpp
 Line 72: static_assert failed due to requirement 'X{}'
  File 
/usr/local/google/home/courbet/llvm/llvm/tools/clang/test/SemaCXX/static-assert-cxx17.cpp
 Line 73: static_assert failed due to requirement 'X{1, 2}'
  File 
/usr/local/google/home/courbet/llvm/llvm/tools/clang/test/SemaCXX/static-assert-cxx17.cpp
 Line 74: static_assert failed due to requirement 'X({1, 2})'
  File 
/usr/local/google/home/courbet/llvm/llvm/tools/clang/test/SemaCXX/static-assert-cxx17.cpp
 Line 75: static_assert failed due to requirement 'typename ExampleTypes::T{0}'
  File 
/usr/local/google/home/courbet/llvm/llvm/tools/clang/test/SemaCXX/static-assert-cxx17.cpp
 Line 76: static_assert failed due to requirement 'typename ExampleTypes::T(0)'
```

I must admit that I did not think of handling these, and now I think it would 
actually be better to tap into the pretty printer to avoid code duplication. 


Repository:
  rC Clang

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

https://reviews.llvm.org/D2



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


[PATCH] D55552: [Sema] Better static assert diagnostics for expressions involving temporaries.

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

Handle remaining static_assert categories inside the prettyprinter.


Repository:
  rC Clang

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

https://reviews.llvm.org/D2

Files:
  include/clang/AST/Stmt.h
  lib/AST/StmtPrinter.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
@@ -76,6 +76,8 @@
   static const Tp value = v;
   typedef Tp value_type;
   typedef integral_constant type;
+  constexpr operator value_type() const noexcept { return value; }
+  constexpr value_type operator()() const noexcept { return value; }
 };
 
 template 
@@ -103,6 +105,7 @@
 } // namespace std
 
 struct ExampleTypes {
+  explicit ExampleTypes(int);
   using T = int;
   using U = float;
 };
@@ -119,6 +122,18 @@
 // 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"}}
+static_assert(std::is_const(), "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_const()' "message"}}
+static_assert(!(std::is_const()()), "message");
+// expected-error@-1{{static_assert failed due to requirement '!(std::is_const()())' "message"}}
+static_assert(std::is_same()), int>::value, "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::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: test/SemaCXX/static-assert-cxx17.cpp
===
--- test/SemaCXX/static-assert-cxx17.cpp
+++ test/SemaCXX/static-assert-cxx17.cpp
@@ -54,3 +54,42 @@
 }
 template void foo5();
 // expected-note@-1{{in instantiation of function template specialization 'foo5' requested here}}
+
+struct ExampleTypes {
+  explicit ExampleTypes(int);
+  using T = int;
+  using U = float;
+};
+
+template struct X {
+  int i=0;
+  int j=0;
+  constexpr operator bool() const { return false; }
+};
+
+template void foo6() {
+static_assert(X());
+// expected-error@-1{{static_assert failed due to requirement 'X()'}}
+static_assert(X{});
+// expected-error@-1{{static_assert failed due to requirement 'X{}'}}
+static_assert(X{1,2});
+// expected-error@-1{{static_assert failed due to requirement 'X{1, 2}'}}
+static_assert(X({1,2}));
+// expected-error@-1{{static_assert failed due to requirement 'X({1, 2})'}}
+static_assert(typename T::T{0});
+// expected-error@-1{{static_assert failed due to requirement 'int{0}'}}
+static_assert(typename T::T(0));
+// expected-error@-1{{static_assert failed due to requirement 'int(0)'}}
+static_assert(sizeof(X) == 0);
+// expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+static_assert((const X*)nullptr);
+// expected-error@-1{{static_assert failed due to requirement '(const X *)nullptr'}}
+static_assert(static_cast*>(nullptr));
+// expected-error@-1{{static_assert failed due to requirement 'static_cast *>(nullptr)'}}
+static_assert((const X[]){} == nullptr);
+// expected-error@-1{{static_assert failed due to requirement '(X const[0]){} == nullptr'}}
+static_assert(sizeof(X().X::~X())>) == 0);
+// expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+}
+template void foo6();
+// expected-note@-1{{in instantiation of function template specialization 'foo6' requested here}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3059,8 +3059,9 @@
 // for actual types.
 class FailedBooleanConditionPrinterHelper : public PrinterHelper {
 public:
-  explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &P)
-  : Policy(P) {}
+  FailedBooleanConditionPrinterHelper(const ASTContext &Context,
+  const PrintingPolicy &P)
+  : Context(Context), Policy(P) {}
 
   bool handledStmt(Stmt *E, raw_ostream &OS) override {
 const auto *DR = dyn_cast(E);
@@ -3081,6 +3082,7 @@
   }
 
 private:
+  const ASTContext &Context;
   const PrintingPolicy Policy;
 };
 
@@ -312

[PATCH] D55552: [Sema] Better static assert diagnostics for expressions involving temporaries.

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

clang-format patch


Repository:
  rC Clang

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

https://reviews.llvm.org/D2

Files:
  include/clang/AST/Stmt.h
  lib/AST/StmtPrinter.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
@@ -76,6 +76,8 @@
   static const Tp value = v;
   typedef Tp value_type;
   typedef integral_constant type;
+  constexpr operator value_type() const noexcept { return value; }
+  constexpr value_type operator()() const noexcept { return value; }
 };
 
 template 
@@ -103,6 +105,7 @@
 } // namespace std
 
 struct ExampleTypes {
+  explicit ExampleTypes(int);
   using T = int;
   using U = float;
 };
@@ -119,6 +122,18 @@
 // 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"}}
+static_assert(std::is_const(), "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_const()' "message"}}
+static_assert(!(std::is_const()()), "message");
+// expected-error@-1{{static_assert failed due to requirement '!(std::is_const()())' "message"}}
+static_assert(std::is_same()), int>::value, "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::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: test/SemaCXX/static-assert-cxx17.cpp
===
--- test/SemaCXX/static-assert-cxx17.cpp
+++ test/SemaCXX/static-assert-cxx17.cpp
@@ -54,3 +54,44 @@
 }
 template void foo5();
 // expected-note@-1{{in instantiation of function template specialization 'foo5' requested here}}
+
+struct ExampleTypes {
+  explicit ExampleTypes(int);
+  using T = int;
+  using U = float;
+};
+
+template 
+struct X {
+  int i = 0;
+  int j = 0;
+  constexpr operator bool() const { return false; }
+};
+
+template 
+void foo6() {
+  static_assert(X());
+  // expected-error@-1{{static_assert failed due to requirement 'X()'}}
+  static_assert(X{});
+  // expected-error@-1{{static_assert failed due to requirement 'X{}'}}
+  static_assert(X{1, 2});
+  // expected-error@-1{{static_assert failed due to requirement 'X{1, 2}'}}
+  static_assert(X({1, 2}));
+  // expected-error@-1{{static_assert failed due to requirement 'X({1, 2})'}}
+  static_assert(typename T::T{0});
+  // expected-error@-1{{static_assert failed due to requirement 'int{0}'}}
+  static_assert(typename T::T(0));
+  // expected-error@-1{{static_assert failed due to requirement 'int(0)'}}
+  static_assert(sizeof(X) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+  static_assert((const X *)nullptr);
+  // expected-error@-1{{static_assert failed due to requirement '(const X *)nullptr'}}
+  static_assert(static_cast *>(nullptr));
+  // expected-error@-1{{static_assert failed due to requirement 'static_cast *>(nullptr)'}}
+  static_assert((const X[]){} == nullptr);
+  // expected-error@-1{{static_assert failed due to requirement '(X const[0]){} == nullptr'}}
+  static_assert(sizeof(X().X::~X())>) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+}
+template void foo6();
+// expected-note@-1{{in instantiation of function template specialization 'foo6' requested here}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3059,8 +3059,9 @@
 // for actual types.
 class FailedBooleanConditionPrinterHelper : public PrinterHelper {
 public:
-  explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &P)
-  : Policy(P) {}
+  FailedBooleanConditionPrinterHelper(const ASTContext &Context,
+  const PrintingPolicy &P)
+  : Context(Context), Policy(P) {}
 
   bool handledStmt(Stmt *E, raw_ostream &OS) override {
 const auto *DR = dyn_cast(E);
@@ -3081,6 +3082,7 @@
   }
 
 private:
+  const ASTContext &Context;
   const PrintingPolicy Policy;
 };
 
@@ -3122,8 +3124,9 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out

[PATCH] D55552: [Sema] Better static assert diagnostics for expressions involving temporaries.

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

revert now unneeded changes.


Repository:
  rC Clang

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

https://reviews.llvm.org/D2

Files:
  include/clang/AST/Stmt.h
  lib/AST/StmtPrinter.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
@@ -76,6 +76,8 @@
   static const Tp value = v;
   typedef Tp value_type;
   typedef integral_constant type;
+  constexpr operator value_type() const noexcept { return value; }
+  constexpr value_type operator()() const noexcept { return value; }
 };
 
 template 
@@ -103,6 +105,7 @@
 } // namespace std
 
 struct ExampleTypes {
+  explicit ExampleTypes(int);
   using T = int;
   using U = float;
 };
@@ -119,6 +122,18 @@
 // 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"}}
+static_assert(std::is_const(), "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_const()' "message"}}
+static_assert(!(std::is_const()()), "message");
+// expected-error@-1{{static_assert failed due to requirement '!(std::is_const()())' "message"}}
+static_assert(std::is_same()), int>::value, "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::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: test/SemaCXX/static-assert-cxx17.cpp
===
--- test/SemaCXX/static-assert-cxx17.cpp
+++ test/SemaCXX/static-assert-cxx17.cpp
@@ -54,3 +54,44 @@
 }
 template void foo5();
 // expected-note@-1{{in instantiation of function template specialization 'foo5' requested here}}
+
+struct ExampleTypes {
+  explicit ExampleTypes(int);
+  using T = int;
+  using U = float;
+};
+
+template 
+struct X {
+  int i = 0;
+  int j = 0;
+  constexpr operator bool() const { return false; }
+};
+
+template 
+void foo6() {
+  static_assert(X());
+  // expected-error@-1{{static_assert failed due to requirement 'X()'}}
+  static_assert(X{});
+  // expected-error@-1{{static_assert failed due to requirement 'X{}'}}
+  static_assert(X{1, 2});
+  // expected-error@-1{{static_assert failed due to requirement 'X{1, 2}'}}
+  static_assert(X({1, 2}));
+  // expected-error@-1{{static_assert failed due to requirement 'X({1, 2})'}}
+  static_assert(typename T::T{0});
+  // expected-error@-1{{static_assert failed due to requirement 'int{0}'}}
+  static_assert(typename T::T(0));
+  // expected-error@-1{{static_assert failed due to requirement 'int(0)'}}
+  static_assert(sizeof(X) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+  static_assert((const X *)nullptr);
+  // expected-error@-1{{static_assert failed due to requirement '(const X *)nullptr'}}
+  static_assert(static_cast *>(nullptr));
+  // expected-error@-1{{static_assert failed due to requirement 'static_cast *>(nullptr)'}}
+  static_assert((const X[]){} == nullptr);
+  // expected-error@-1{{static_assert failed due to requirement '(X const[0]){} == nullptr'}}
+  static_assert(sizeof(X().X::~X())>) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+}
+template void foo6();
+// expected-note@-1{{in instantiation of function template specialization 'foo6' requested here}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3059,8 +3059,7 @@
 // for actual types.
 class FailedBooleanConditionPrinterHelper : public PrinterHelper {
 public:
-  explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &P)
-  : Policy(P) {}
+  FailedBooleanConditionPrinterHelper(const PrintingPolicy &P) : Policy(P) {}
 
   bool handledStmt(Stmt *E, raw_ostream &OS) override {
 const auto *DR = dyn_cast(E);
@@ -3123,7 +3122,8 @@
   {
 llvm::raw_string_ostream Out(Description);
 FailedBooleanConditionPrinterHelper Helper(getPrintingPolicy());
-FailedCond->printPretty(Out, &Helper, getPrintingPolicy());
+FailedCond->printPretty(Out, &Helper, getPrintingPolicy(), 0,

[PATCH] D55552: [Sema] Better static assert diagnostics for expressions involving temporaries.

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

move PrintQualifiedTypes to PrintingPolicy


Repository:
  rC Clang

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

https://reviews.llvm.org/D2

Files:
  include/clang/AST/PrettyPrinter.h
  include/clang/AST/Type.h
  lib/AST/StmtPrinter.cpp
  lib/AST/TypePrinter.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
@@ -76,6 +76,8 @@
   static const Tp value = v;
   typedef Tp value_type;
   typedef integral_constant type;
+  constexpr operator value_type() const noexcept { return value; }
+  constexpr value_type operator()() const noexcept { return value; }
 };
 
 template 
@@ -103,6 +105,7 @@
 } // namespace std
 
 struct ExampleTypes {
+  explicit ExampleTypes(int);
   using T = int;
   using U = float;
 };
@@ -119,6 +122,18 @@
 // 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"}}
+static_assert(std::is_const(), "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_const()' "message"}}
+static_assert(!(std::is_const()()), "message");
+// expected-error@-1{{static_assert failed due to requirement '!(std::is_const()())' "message"}}
+static_assert(std::is_same()), int>::value, "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::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: test/SemaCXX/static-assert-cxx17.cpp
===
--- test/SemaCXX/static-assert-cxx17.cpp
+++ test/SemaCXX/static-assert-cxx17.cpp
@@ -54,3 +54,44 @@
 }
 template void foo5();
 // expected-note@-1{{in instantiation of function template specialization 'foo5' requested here}}
+
+struct ExampleTypes {
+  explicit ExampleTypes(int);
+  using T = int;
+  using U = float;
+};
+
+template 
+struct X {
+  int i = 0;
+  int j = 0;
+  constexpr operator bool() const { return false; }
+};
+
+template 
+void foo6() {
+  static_assert(X());
+  // expected-error@-1{{static_assert failed due to requirement 'X()'}}
+  static_assert(X{});
+  // expected-error@-1{{static_assert failed due to requirement 'X{}'}}
+  static_assert(X{1, 2});
+  // expected-error@-1{{static_assert failed due to requirement 'X{1, 2}'}}
+  static_assert(X({1, 2}));
+  // expected-error@-1{{static_assert failed due to requirement 'X({1, 2})'}}
+  static_assert(typename T::T{0});
+  // expected-error@-1{{static_assert failed due to requirement 'int{0}'}}
+  static_assert(typename T::T(0));
+  // expected-error@-1{{static_assert failed due to requirement 'int(0)'}}
+  static_assert(sizeof(X) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+  static_assert((const X *)nullptr);
+  // expected-error@-1{{static_assert failed due to requirement '(const X *)nullptr'}}
+  static_assert(static_cast *>(nullptr));
+  // expected-error@-1{{static_assert failed due to requirement 'static_cast *>(nullptr)'}}
+  static_assert((const X[]){} == nullptr);
+  // expected-error@-1{{static_assert failed due to requirement '(X const[0]){} == nullptr'}}
+  static_assert(sizeof(X().X::~X())>) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+}
+template void foo6();
+// expected-note@-1{{in instantiation of function template specialization 'foo6' requested here}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3059,8 +3059,7 @@
 // for actual types.
 class FailedBooleanConditionPrinterHelper : public PrinterHelper {
 public:
-  explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &P)
-  : Policy(P) {}
+  FailedBooleanConditionPrinterHelper(const PrintingPolicy &P) : Policy(P) {}
 
   bool handledStmt(Stmt *E, raw_ostream &OS) override {
 const auto *DR = dyn_cast(E);
@@ -3122,8 +3121,10 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-FailedBooleanConditionPrinterHelper Helper(getPri

[PATCH] D55552: [Sema] Better static assert diagnostics for expressions involving temporaries.

2018-12-19 Thread Clement Courbet via Phabricator via cfe-commits
courbet added inline comments.



Comment at: include/clang/AST/Stmt.h:847
+   const ASTContext *Context = nullptr,
+   bool PrintCanonicalTypes = false) const;
 

aaron.ballman wrote:
> I'm pretty wary of long lists of parameters that include booleans with 
> default values. Why is `PrintCanonicalTypes` not part of the printing policy? 
> I think that's where we should keep all the knobs relating to how the 
> printing happens.
Good point, done.


Repository:
  rC Clang

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

https://reviews.llvm.org/D2



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


[PATCH] D55552: [Sema] Better static assert diagnostics for expressions involving temporaries.

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



Comment at: lib/AST/TypePrinter.cpp:165
 
+static SplitQualType splitAccordingToPolicy(QualType t,
+const PrintingPolicy &Policy) {

aaron.ballman wrote:
> `t` doesn't meet the usual naming requirements; how about `QT`?
I was keeping it for consistency with `TypePrinter::print(QualType t,`, but 
done.



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

aaron.ballman wrote:
> Why are you dropping the `explicit` here?
Sorry, this is a revert of an approach where it had two parameters.


Repository:
  rC Clang

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

https://reviews.llvm.org/D2



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


[PATCH] D55552: [Sema] Better static assert diagnostics for expressions involving temporaries.

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

address review comments


Repository:
  rC Clang

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

https://reviews.llvm.org/D2

Files:
  include/clang/AST/PrettyPrinter.h
  include/clang/AST/Type.h
  lib/AST/TypePrinter.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
@@ -76,6 +76,8 @@
   static const Tp value = v;
   typedef Tp value_type;
   typedef integral_constant type;
+  constexpr operator value_type() const noexcept { return value; }
+  constexpr value_type operator()() const noexcept { return value; }
 };
 
 template 
@@ -103,6 +105,7 @@
 } // namespace std
 
 struct ExampleTypes {
+  explicit ExampleTypes(int);
   using T = int;
   using U = float;
 };
@@ -119,6 +122,18 @@
 // 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"}}
+static_assert(std::is_const(), "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_const()' "message"}}
+static_assert(!(std::is_const()()), "message");
+// expected-error@-1{{static_assert failed due to requirement '!(std::is_const()())' "message"}}
+static_assert(std::is_same()), int>::value, "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::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: test/SemaCXX/static-assert-cxx17.cpp
===
--- test/SemaCXX/static-assert-cxx17.cpp
+++ test/SemaCXX/static-assert-cxx17.cpp
@@ -54,3 +54,44 @@
 }
 template void foo5();
 // expected-note@-1{{in instantiation of function template specialization 'foo5' requested here}}
+
+struct ExampleTypes {
+  explicit ExampleTypes(int);
+  using T = int;
+  using U = float;
+};
+
+template 
+struct X {
+  int i = 0;
+  int j = 0;
+  constexpr operator bool() const { return false; }
+};
+
+template 
+void foo6() {
+  static_assert(X());
+  // expected-error@-1{{static_assert failed due to requirement 'X()'}}
+  static_assert(X{});
+  // expected-error@-1{{static_assert failed due to requirement 'X{}'}}
+  static_assert(X{1, 2});
+  // expected-error@-1{{static_assert failed due to requirement 'X{1, 2}'}}
+  static_assert(X({1, 2}));
+  // expected-error@-1{{static_assert failed due to requirement 'X({1, 2})'}}
+  static_assert(typename T::T{0});
+  // expected-error@-1{{static_assert failed due to requirement 'int{0}'}}
+  static_assert(typename T::T(0));
+  // expected-error@-1{{static_assert failed due to requirement 'int(0)'}}
+  static_assert(sizeof(X) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+  static_assert((const X *)nullptr);
+  // expected-error@-1{{static_assert failed due to requirement '(const X *)nullptr'}}
+  static_assert(static_cast *>(nullptr));
+  // expected-error@-1{{static_assert failed due to requirement 'static_cast *>(nullptr)'}}
+  static_assert((const X[]){} == nullptr);
+  // expected-error@-1{{static_assert failed due to requirement '(X const[0]){} == nullptr'}}
+  static_assert(sizeof(X().X::~X())>) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+}
+template void foo6();
+// expected-note@-1{{in instantiation of function template specialization 'foo6' requested here}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3122,8 +3122,10 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-FailedBooleanConditionPrinterHelper Helper(getPrintingPolicy());
-FailedCond->printPretty(Out, &Helper, getPrintingPolicy());
+PrintingPolicy Policy = getPrintingPolicy();
+Policy.PrintCanonicalTypes = true;
+FailedBooleanConditionPrinterHelper Helper(Policy);
+FailedCond->printPretty(Out, &Helper, Policy, 0, "\n", nullptr);
   }
   return { FailedCond, Description };
 }
Index: lib/AST/TypePrinter.cpp
==

[PATCH] D55552: [Sema] Better static assert diagnostics for expressions involving temporaries.

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

clang-format diff


Repository:
  rC Clang

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

https://reviews.llvm.org/D2

Files:
  include/clang/AST/PrettyPrinter.h
  include/clang/AST/Type.h
  lib/AST/TypePrinter.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
@@ -76,6 +76,8 @@
   static const Tp value = v;
   typedef Tp value_type;
   typedef integral_constant type;
+  constexpr operator value_type() const noexcept { return value; }
+  constexpr value_type operator()() const noexcept { return value; }
 };
 
 template 
@@ -103,6 +105,7 @@
 } // namespace std
 
 struct ExampleTypes {
+  explicit ExampleTypes(int);
   using T = int;
   using U = float;
 };
@@ -119,6 +122,18 @@
 // 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"}}
+static_assert(std::is_const(), "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_const()' "message"}}
+static_assert(!(std::is_const()()), "message");
+// expected-error@-1{{static_assert failed due to requirement '!(std::is_const()())' "message"}}
+static_assert(std::is_same()), int>::value, "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::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: test/SemaCXX/static-assert-cxx17.cpp
===
--- test/SemaCXX/static-assert-cxx17.cpp
+++ test/SemaCXX/static-assert-cxx17.cpp
@@ -54,3 +54,44 @@
 }
 template void foo5();
 // expected-note@-1{{in instantiation of function template specialization 'foo5' requested here}}
+
+struct ExampleTypes {
+  explicit ExampleTypes(int);
+  using T = int;
+  using U = float;
+};
+
+template 
+struct X {
+  int i = 0;
+  int j = 0;
+  constexpr operator bool() const { return false; }
+};
+
+template 
+void foo6() {
+  static_assert(X());
+  // expected-error@-1{{static_assert failed due to requirement 'X()'}}
+  static_assert(X{});
+  // expected-error@-1{{static_assert failed due to requirement 'X{}'}}
+  static_assert(X{1, 2});
+  // expected-error@-1{{static_assert failed due to requirement 'X{1, 2}'}}
+  static_assert(X({1, 2}));
+  // expected-error@-1{{static_assert failed due to requirement 'X({1, 2})'}}
+  static_assert(typename T::T{0});
+  // expected-error@-1{{static_assert failed due to requirement 'int{0}'}}
+  static_assert(typename T::T(0));
+  // expected-error@-1{{static_assert failed due to requirement 'int(0)'}}
+  static_assert(sizeof(X) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+  static_assert((const X *)nullptr);
+  // expected-error@-1{{static_assert failed due to requirement '(const X *)nullptr'}}
+  static_assert(static_cast *>(nullptr));
+  // expected-error@-1{{static_assert failed due to requirement 'static_cast *>(nullptr)'}}
+  static_assert((const X[]){} == nullptr);
+  // expected-error@-1{{static_assert failed due to requirement '(X const[0]){} == nullptr'}}
+  static_assert(sizeof(X().X::~X())>) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+}
+template void foo6();
+// expected-note@-1{{in instantiation of function template specialization 'foo6' requested here}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3122,8 +3122,10 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-FailedBooleanConditionPrinterHelper Helper(getPrintingPolicy());
-FailedCond->printPretty(Out, &Helper, getPrintingPolicy());
+PrintingPolicy Policy = getPrintingPolicy();
+Policy.PrintCanonicalTypes = true;
+FailedBooleanConditionPrinterHelper Helper(Policy);
+FailedCond->printPretty(Out, &Helper, Policy, 0, "\n", nullptr);
   }
   return { FailedCond, Description };
 }
Index: lib/AST/TypePrinter.cpp
===
--- lib/AST/TypePrinter.cpp
+++ lib/AS

[PATCH] D55552: [Sema] Better static assert diagnostics for expressions involving temporaries.

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

address review comments


Repository:
  rC Clang

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

https://reviews.llvm.org/D2

Files:
  include/clang/AST/PrettyPrinter.h
  include/clang/AST/Type.h
  lib/AST/TypePrinter.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
@@ -76,6 +76,8 @@
   static const Tp value = v;
   typedef Tp value_type;
   typedef integral_constant type;
+  constexpr operator value_type() const noexcept { return value; }
+  constexpr value_type operator()() const noexcept { return value; }
 };
 
 template 
@@ -103,6 +105,7 @@
 } // namespace std
 
 struct ExampleTypes {
+  explicit ExampleTypes(int);
   using T = int;
   using U = float;
 };
@@ -119,6 +122,18 @@
 // 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"}}
+static_assert(std::is_const(), "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_const()' "message"}}
+static_assert(!(std::is_const()()), "message");
+// expected-error@-1{{static_assert failed due to requirement '!(std::is_const()())' "message"}}
+static_assert(std::is_same()), int>::value, "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::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: test/SemaCXX/static-assert-cxx17.cpp
===
--- test/SemaCXX/static-assert-cxx17.cpp
+++ test/SemaCXX/static-assert-cxx17.cpp
@@ -54,3 +54,44 @@
 }
 template void foo5();
 // expected-note@-1{{in instantiation of function template specialization 'foo5' requested here}}
+
+struct ExampleTypes {
+  explicit ExampleTypes(int);
+  using T = int;
+  using U = float;
+};
+
+template 
+struct X {
+  int i = 0;
+  int j = 0;
+  constexpr operator bool() const { return false; }
+};
+
+template 
+void foo6() {
+  static_assert(X());
+  // expected-error@-1{{static_assert failed due to requirement 'X()'}}
+  static_assert(X{});
+  // expected-error@-1{{static_assert failed due to requirement 'X{}'}}
+  static_assert(X{1, 2});
+  // expected-error@-1{{static_assert failed due to requirement 'X{1, 2}'}}
+  static_assert(X({1, 2}));
+  // expected-error@-1{{static_assert failed due to requirement 'X({1, 2})'}}
+  static_assert(typename T::T{0});
+  // expected-error@-1{{static_assert failed due to requirement 'int{0}'}}
+  static_assert(typename T::T(0));
+  // expected-error@-1{{static_assert failed due to requirement 'int(0)'}}
+  static_assert(sizeof(X) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+  static_assert((const X *)nullptr);
+  // expected-error@-1{{static_assert failed due to requirement '(const X *)nullptr'}}
+  static_assert(static_cast *>(nullptr));
+  // expected-error@-1{{static_assert failed due to requirement 'static_cast *>(nullptr)'}}
+  static_assert((const X[]){} == nullptr);
+  // expected-error@-1{{static_assert failed due to requirement '(X const[0]){} == nullptr'}}
+  static_assert(sizeof(X().X::~X())>) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+}
+template void foo6();
+// expected-note@-1{{in instantiation of function template specialization 'foo6' requested here}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3122,8 +3122,10 @@
   std::string Description;
   {
 llvm::raw_string_ostream Out(Description);
-FailedBooleanConditionPrinterHelper Helper(getPrintingPolicy());
-FailedCond->printPretty(Out, &Helper, getPrintingPolicy());
+PrintingPolicy Policy = getPrintingPolicy();
+Policy.PrintCanonicalTypes = true;
+FailedBooleanConditionPrinterHelper Helper(Policy);
+FailedCond->printPretty(Out, &Helper, Policy, 0, "\n", nullptr);
   }
   return { FailedCond, Description };
 }
Index: lib/AST/TypePrinter.cpp
==

[PATCH] D55552: [Sema] Better static assert diagnostics for expressions involving temporaries.

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

Thanks for the comments !




Comment at: include/clang/AST/Type.h:995
   void getAsStringInternal(std::string &Str,
-   const PrintingPolicy &Policy) const {
-return getAsStringInternal(split(), Str, Policy);
-  }
+   const PrintingPolicy &Policy) const;
 

Quuxplusone wrote:
> Nit: could this function have been left in-line, and just changed `split()` 
> to `splitAccordingToPolicy(this, Policy)`?
> Even simpler, could `splitAccordingToPolicy` be made a member function of 
> `QualType`, so that most of these diffs could be simply 
> `s/split()/splitAccordingToPolicy(Policy)/` without introducing any new 
> temporary variables or anything?  I.e.
> ```
> void getAsStringInternal(std::string &Str,
>   const PrintingPolicy &Policy) const {
> return getAsStringInternal(splitAccordingToPolicy(Policy), Str, 
> Policy);
> }
> ```
> But if that would make the code harder to read instead of easier, then don't 
> mind me.
I'd rather avoid polluting the `QualType` API with `splitAccordingToPolicy()` 
which is really only useful for this use case.

>  without introducing any new temporary variables or anything? i.e.

Actually this is independent of the above change, done.


Repository:
  rC Clang

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

https://reviews.llvm.org/D2



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


[PATCH] D55552: [Sema] Better static assert diagnostics for expressions involving temporaries.

2018-12-20 Thread Clement Courbet via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL349729: [Sema] Better static assert diagnostics for 
expressions involving… (authored by courbet, committed by ).

Repository:
  rL LLVM

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

https://reviews.llvm.org/D2

Files:
  cfe/trunk/include/clang/AST/PrettyPrinter.h
  cfe/trunk/include/clang/AST/Type.h
  cfe/trunk/lib/AST/TypePrinter.cpp
  cfe/trunk/lib/Sema/SemaTemplate.cpp
  cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp
  cfe/trunk/test/SemaCXX/static-assert.cpp

Index: cfe/trunk/include/clang/AST/PrettyPrinter.h
===
--- cfe/trunk/include/clang/AST/PrettyPrinter.h
+++ cfe/trunk/include/clang/AST/PrettyPrinter.h
@@ -51,7 +51,7 @@
 MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true),
 MSVCFormatting(false), ConstantsAsWritten(false),
 SuppressImplicitBase(false), FullyQualifiedName(false),
-RemapFilePaths(false) {}
+RemapFilePaths(false), PrintCanonicalTypes(false) {}
 
   /// Adjust this printing policy for cases where it's known that we're
   /// printing C++ code (for instance, if AST dumping reaches a C++-only
@@ -228,6 +228,9 @@
   /// Whether to apply -fdebug-prefix-map to any file paths.
   unsigned RemapFilePaths : 1;
 
+  /// Whether to print types as written or canonically.
+  unsigned PrintCanonicalTypes : 1;
+
   /// When RemapFilePaths is true, this function performs the action.
   std::function remapPath;
 };
Index: cfe/trunk/include/clang/AST/Type.h
===
--- cfe/trunk/include/clang/AST/Type.h
+++ cfe/trunk/include/clang/AST/Type.h
@@ -980,9 +980,7 @@
 
   void print(raw_ostream &OS, const PrintingPolicy &Policy,
  const Twine &PlaceHolder = Twine(),
- unsigned Indentation = 0) const {
-print(split(), OS, Policy, PlaceHolder, Indentation);
-  }
+ unsigned Indentation = 0) const;
 
   static void print(SplitQualType split, raw_ostream &OS,
 const PrintingPolicy &policy, const Twine &PlaceHolder,
@@ -996,9 +994,7 @@
 unsigned Indentation = 0);
 
   void getAsStringInternal(std::string &Str,
-   const PrintingPolicy &Policy) const {
-return getAsStringInternal(split(), Str, Policy);
-  }
+   const PrintingPolicy &Policy) const;
 
   static void getAsStringInternal(SplitQualType split, std::string &out,
   const PrintingPolicy &policy) {
Index: cfe/trunk/test/SemaCXX/static-assert.cpp
===
--- cfe/trunk/test/SemaCXX/static-assert.cpp
+++ cfe/trunk/test/SemaCXX/static-assert.cpp
@@ -76,6 +76,8 @@
   static const Tp value = v;
   typedef Tp value_type;
   typedef integral_constant type;
+  constexpr operator value_type() const noexcept { return value; }
+  constexpr value_type operator()() const noexcept { return value; }
 };
 
 template 
@@ -103,6 +105,7 @@
 } // namespace std
 
 struct ExampleTypes {
+  explicit ExampleTypes(int);
   using T = int;
   using U = float;
 };
@@ -119,6 +122,18 @@
 // 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"}}
+static_assert(std::is_const(), "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_const()' "message"}}
+static_assert(!(std::is_const()()), "message");
+// expected-error@-1{{static_assert failed due to requirement '!(std::is_const()())' "message"}}
+static_assert(std::is_same()), int>::value, "message");
+// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::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: cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp
===
--- cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp
+++ cfe/trunk/test/SemaCXX/static-assert-cxx17.cpp
@@ -54,3 +54,44 @@
 }
 template void foo5();
 // expected-note@-1{{in instantiation of function template specialization 'foo5' requested here}}
+
+struct ExampleTypes {
+  explicit ExampleTypes(int);
+  using T = int;
+  using U = float;
+};
+
+template 
+struct X {
+  int i = 0;
+  int j = 

[PATCH] D55932: [Sema] Simplfy static_assert diagnostic code.

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

We can now remove the specific handling of NestedNameQualifiers as
it's now handled by the type printer as of r349729.


Repository:
  rC Clang

https://reviews.llvm.org/D55932

Files:
  include/clang/AST/NestedNameSpecifier.h
  lib/AST/NestedNameSpecifier.cpp
  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
@@ -127,7 +127,7 @@
 static_assert(!(std::is_const()()), "message");
 // expected-error@-1{{static_assert failed due to requirement '!(std::is_const()())' "message"}}
 static_assert(std::is_same()), int>::value, "message");
-// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::value' "message"}}
+// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::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");
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,40 +3052,6 @@
   return Cond;
 }
 
-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 &P)
-  : Policy(P) {}
-
-  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 false;
-  }
-
-private:
-  const PrintingPolicy Policy;
-};
-
-} // end anonymous namespace
-
 std::pair
 Sema::findFailedBooleanCondition(Expr *Cond) {
   Cond = lookThroughRangesV3Condition(PP, Cond);
@@ -3124,8 +3090,7 @@
 llvm::raw_string_ostream Out(Description);
 PrintingPolicy Policy = getPrintingPolicy();
 Policy.PrintCanonicalTypes = true;
-FailedBooleanConditionPrinterHelper Helper(Policy);
-FailedCond->printPretty(Out, &Helper, Policy, 0, "\n", nullptr);
+FailedCond->printPretty(Out, nullptr, Policy, 0, "\n", nullptr);
   }
   return { FailedCond, Description };
 }
Index: lib/AST/NestedNameSpecifier.cpp
===
--- lib/AST/NestedNameSpecifier.cpp
+++ lib/AST/NestedNameSpecifier.cpp
@@ -271,8 +271,7 @@
 
 /// Print this nested name specifier to the given output
 /// stream.
-void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
-bool ResolveTemplateArguments) const {
+void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy) const {
   if (getPrefix())
 getPrefix()->print(OS, Policy);
 
@@ -305,15 +304,6 @@
 LLVM_FALLTHROUGH;
 
   case TypeSpec: {
-const auto *Record =
-dyn_cast_or_null(getAsRecordDecl());
-if (ResolveTemplateArguments && Record) {
-// Print the type trait with resolved template parameters.
-Record->printName(OS);
-printTemplateArgumentList(OS, Record->getTemplateArgs().asArray(),
-  Policy);
-break;
-}
 const Type *T = getAsType();
 
 PrintingPolicy InnerPolicy(Policy);
Index: include/clang/AST/NestedNameSpecifier.h
===
--- include/clang/AST/NestedNameSpecifier.h
+++ include/clang/AST/NestedNameSpecifier.h
@@ -212,12 +212,8 @@
   /// parameter pack (for C++11 variadic templates).
   bool containsUnexpandedParameterPack() const;
 
-  /// Print this nested name specifier to the given output stream. If
-  /// `ResolveTemplateArguments` is true, we'll print actual types, e.g.
-  /// `ns::SomeTemplate` instead of
-  /// `ns::SomeTemplate`.
-  void print(raw_ostream &OS, const PrintingPolicy &Policy,
- bool ResolveTemplateArguments = false) const;
+  /// Print this nested name specifier to the given output stream.
+  void print(raw_ostream &OS, const PrintingPolicy &Policy) const;
 
   void Profile(llvm::FoldingSetNodeID &ID) const {
 ID.AddPointer(Prefix.getO

[PATCH] D55933: [Sema] Do not print default template parameters.

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

As a followup to D55270 .


Repository:
  rC Clang

https://reviews.llvm.org/D55933

Files:
  include/clang/AST/NestedNameSpecifier.h
  lib/AST/NestedNameSpecifier.cpp
  lib/AST/TypePrinter.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
@@ -127,7 +127,7 @@
 static_assert(!(std::is_const()()), "message");
 // expected-error@-1{{static_assert failed due to requirement '!(std::is_const()())' "message"}}
 static_assert(std::is_same()), int>::value, "message");
-// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::value' "message"}}
+// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::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");
Index: test/SemaCXX/static-assert-cxx17.cpp
===
--- test/SemaCXX/static-assert-cxx17.cpp
+++ test/SemaCXX/static-assert-cxx17.cpp
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1z -triple=x86_64-linux-gnu
 
-template 
+template 
 struct S1 {
   static constexpr const bool value = false;
 };
@@ -14,7 +14,7 @@
   static inline constexpr bool var = global_inline_var;
 };
 
-template 
+template 
 inline constexpr bool constexpr_return_false() {
   return false;
 }
@@ -23,6 +23,8 @@
 void foo() {
   static_assert(S1::value);
   // expected-error@-1{{static_assert failed due to requirement 'S1::value'}}
+  static_assert(S1::value);
+  // expected-error@-1{{static_assert failed due to requirement 'S1::value'}}
 }
 template void foo();
 // expected-note@-1{{in instantiation of function template specialization 'foo' requested here}}
@@ -66,7 +68,7 @@
   using U = float;
 };
 
-template 
+template 
 struct X {
   int i = 0;
   int j = 0;
@@ -94,11 +96,41 @@
   static_assert(static_cast *>(nullptr));
   // expected-error@-1{{static_assert failed due to requirement 'static_cast *>(nullptr)'}}
   static_assert((const X[]){} == nullptr);
-  // expected-error@-1{{static_assert failed due to requirement '(X const[0]){} == nullptr'}}
+  // expected-error@-1{{static_assert failed due to requirement '(const X [0]){} == nullptr'}}
   static_assert(sizeof(X().X::~X())>) == 0);
   // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
-  static_assert(constexpr_return_false());
-  // expected-error@-1{{static_assert failed due to requirement 'constexpr_return_false()'}}
+  static_assert(constexpr_return_false());
+  // expected-error@-1{{static_assert failed due to requirement 'constexpr_return_false()'}}
 }
 template void foo6();
 // expected-note@-1{{in instantiation of function template specialization 'foo6' requested here}}
+
+template 
+void foo7() {
+  static_assert(X());
+  // expected-error@-1{{static_assert failed due to requirement 'X()'}}
+  static_assert(X{});
+  // expected-error@-1{{static_assert failed due to requirement 'X{}'}}
+  static_assert(X{1, 2});
+  // expected-error@-1{{static_assert failed due to requirement 'X{1, 2}'}}
+  static_assert(X({1, 2}));
+  // expected-error@-1{{static_assert failed due to requirement 'X({1, 2})'}}
+  static_assert(typename T::T{0});
+  // expected-error@-1{{static_assert failed due to requirement 'int{0}'}}
+  static_assert(typename T::T(0));
+  // expected-error@-1{{static_assert failed due to requirement 'int(0)'}}
+  static_assert(sizeof(X) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+  static_assert((const X *)nullptr);
+  // expected-error@-1{{static_assert failed due to requirement '(const X *)nullptr'}}
+  static_assert(static_cast *>(nullptr));
+  // expected-error@-1{{static_assert failed due to requirement 'static_cast *>(nullptr)'}}
+  static_assert((const X[]){} == nullptr);
+  // expected-error@-1{{static_assert failed due to requirement '(const X [0]){} == nullptr'}}
+  static_assert(sizeof(X().X::~X()), float>) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+  static_assert(constexpr_return_false());
+  // expected-error@-1{{static_assert failed due to requirement 'constexpr_return_false()'}}
+}
+template void foo7();
+// expected-note@-1{{in instantiation of function template specialization 'foo7' requested here}}
Index: lib/Sema/SemaTemplate.cpp
===
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -3052,40 +3052,6 @@
   return Cond;
 }
 
-namespace {
-
-// A PrinterHelper that prints more h

[PATCH] D55933: [Sema] Do not print default template parameters.

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



Comment at: lib/AST/TypePrinter.cpp:173
+  // information about whether default template parameters were actually
+  // written.
+  switch (QT.getTypePtr()->getTypeClass()) {

Quuxplusone wrote:
> FWIW, I don't understand this comment's terminology. "Whether default 
> template parameters were actually written": should that say something like 
> "whether a template parameter came from a default argument"?
> And why are the `Pointer`, `VariableArray`, etc. cases here? What goes wrong 
> if you remove them?
I've expanded the comments.



Comment at: test/SemaCXX/static-assert-cxx17.cpp:99
   static_assert((const X[]){} == nullptr);
-  // expected-error@-1{{static_assert failed due to requirement '(X 
const[0]){} == nullptr'}}
+  // expected-error@-1{{static_assert failed due to requirement '(const X 
[0]){} == nullptr'}}
   static_assert(sizeof(X().X::~X())>) 
== 0);

Quuxplusone wrote:
> (1) This cosmetic change is produced by the `case IncompleteArray:` that I 
> questioned above, right? I'm surprised that the pretty-printed type changes 
> from "east const" to "west const." But that's fine.
> 
> (2) Sorry I didn't notice before: surely where the message currently says 
> `[0]` it should say `[]` instead! That's an existing bug in the 
> pretty-printer, going back super far: https://godbolt.org/z/y9KzEq  So I 
> guess it's not your responsibility to fix. But I hope there's a bug open 
> about it somewhere?
> (1) This cosmetic change is produced by the case IncompleteArray: that I 
> questioned above, right? I'm surprised that the pretty-printed type changes 
> from "east const" to "west const." But that's fine.

Indeed. There's some logic in the printer to see where the const should go. 

> (2) Sorry I didn't notice before: surely where the message currently says [0] 
> it should say [] instead! That's an existing bug in the pretty-printer, going 
> back super far: https://godbolt.org/z/y9KzEq So I guess it's not your 
> responsibility to fix. But I hope there's a bug open about it somewhere?

Is it actually a bug ? In the godbolt example I actually thing putting the zero 
there actually clarifies the semantics of the expression for the reader, so I 
would'nt say it hurts.




Comment at: test/SemaCXX/static-assert-cxx17.cpp:103
+  static_assert(constexpr_return_false());
+  // expected-error@-1{{static_assert failed due to requirement 
'constexpr_return_false()'}}
 }

Quuxplusone wrote:
> Please keep the old test case 
> 
> static_assert(constexpr_return_false());
> // expected-error@-1{{static_assert failed due to requirement 
> 'constexpr_return_false()'}}
> 
> and then //add// this new test case. My understanding is that the old test 
> case should still pass, even after your change.
The old one is in foo7().



Comment at: test/SemaCXX/static-assert-cxx17.cpp:109
+template 
+void foo7() {
+  static_assert(X());

Quuxplusone wrote:
> None of these new test cases actually involve the default template argument.
> 
> I'd like to see two test cases explicitly mimicking `vector`. (Warning: I 
> didn't run this code!)
> ```
> template struct A {};
> template> struct V {};
> template void testx() {
> static_assert(std::is_same::value, "");
> // expected-error@-1{{due to requirement 'std::is_same*, 
> void>::value'}}
> }
> template testx>();
> template struct PMRA {};
> template using PMRV = V>;
> template void test() {
> static_assert(std::is_same::value, "");
> // expected-error@-1{{due to requirement 'std::is_same PMRA>*, void>::value'}}
> // expected-error@-2{{due to requirement 'std::is_same*, 
> void>::value'}}
> }
> template testy>();
> ```
> The `expected-error@-2` above is my fantasy world. I don't think it's 
> possible to achieve in real life. :)
> None of these new test cases actually involve the default template argument.

This one is to check that we actually do print when specified explicitly. foo6 
above tests  the default template arguments (notice the change from `template 
 struct X to `template  struct X` above). 
I've renamed `foo6` and `foo7` to make that clear.

Before this change, static_asserts in `foo6` and `foo7` printed the same thing. 
Now they don't.

> I'd like to see two test cases explicitly mimicking vector.

OK, I think I misunderstood what you wanted here. I don't think what you want 
is actually doable, because by the time you're in `test()`, C is just a type 
without any way of knowing whether the user explicitly provided the template 
parameter or relied on the default.

What we could do though is **always** erase template parameters that are the 
same as default ones. But that would mean printing `due to requirement 
'std::is_same*, void>::value'` even when the user wrote `template 
testx>>();`.
WDYT ?





Comment at: test/Sem

[PATCH] D55932: [Sema] Simplfy static_assert diagnostic code.

2019-01-02 Thread Clement Courbet via Phabricator via cfe-commits
courbet marked an inline comment as done.
courbet added inline comments.



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

aaron.ballman wrote:
> Any idea why the `std::` was dropped here?
`NestedNameSpecifier::print()` explicitly does:

```
 PrintingPolicy InnerPolicy(Policy);
 InnerPolicy.SuppressScope = true;
```



Repository:
  rC Clang

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

https://reviews.llvm.org/D55932



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


[PATCH] D55932: [Sema] Simplfy static_assert diagnostic code.

2019-01-02 Thread Clement Courbet via Phabricator via cfe-commits
courbet added inline comments.



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

aaron.ballman wrote:
> courbet wrote:
> > aaron.ballman wrote:
> > > Any idea why the `std::` was dropped here?
> > `NestedNameSpecifier::print()` explicitly does:
> > 
> > ```
> >  PrintingPolicy InnerPolicy(Policy);
> >  InnerPolicy.SuppressScope = true;
> > ```
> > 
> Ah, good point, but is that a good behavioral change? I slightly prefer 
> printing the namespace name there -- it will likely be redundant information 
> most of the time, but when the namespace actually matters, having it printed 
> could save someone a lot of head scratching.
> I slightly prefer printing the namespace name there

I tend to agree, so it's more a trade-off of code complexity vs better 
diagnostic - I tend to err on the side of simplifying the code :)

Another option is to add yet another boolean to PrintingPolicy, but I htink 
this is too narrow a use case.


Repository:
  rC Clang

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

https://reviews.llvm.org/D55932



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


[PATCH] D55932: [Sema] Simplfy static_assert diagnostic code.

2019-01-03 Thread Clement Courbet via Phabricator via cfe-commits
courbet marked an inline comment as done.
courbet added inline comments.



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

aaron.ballman wrote:
> courbet wrote:
> > aaron.ballman wrote:
> > > courbet wrote:
> > > > aaron.ballman wrote:
> > > > > Any idea why the `std::` was dropped here?
> > > > `NestedNameSpecifier::print()` explicitly does:
> > > > 
> > > > ```
> > > >  PrintingPolicy InnerPolicy(Policy);
> > > >  InnerPolicy.SuppressScope = true;
> > > > ```
> > > > 
> > > Ah, good point, but is that a good behavioral change? I slightly prefer 
> > > printing the namespace name there -- it will likely be redundant 
> > > information most of the time, but when the namespace actually matters, 
> > > having it printed could save someone a lot of head scratching.
> > > I slightly prefer printing the namespace name there
> > 
> > I tend to agree, so it's more a trade-off of code complexity vs better 
> > diagnostic - I tend to err on the side of simplifying the code :)
> > 
> > Another option is to add yet another boolean to PrintingPolicy, but I htink 
> > this is too narrow a use case.
> Heh, I tend to err on the side of helping the user unless the code will be 
> truly awful. I agree that another option on PrintingPolicy may not be the 
> best approach. Do you know why the namespace is being suppressed in the first 
> place? Another option would be to always print the namespace, but I don't 
> know what that might regress (if anything).
Unfortunately always printing the qualification breaks 30 tests, including some 
in a very bad way:

```
/usr/local/google/home/courbet/llvm/llvm/tools/clang/test/AST/ast-print-out-of-line-func.cpp:29:11:
 error: CHECK: expected string not found in input
// CHECK: void Wrapper::Inner::operator+=(int)
  ^
:14:43: note: scanning from here
 ns::Wrapper::ns::Wrapper::Inner::Inner() {
  ^
:16:19: note: possible intended match here
 void ns::Wrapper::ns::Wrapper::Inner::operator+=(int) {
```


Repository:
  rC Clang

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

https://reviews.llvm.org/D55932



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


[PATCH] D55933: [Sema] Do not print default template parameters.

2019-01-03 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 180035.
courbet marked 2 inline comments as done.
courbet added a comment.

Add more tests as suggested in the comments.


Repository:
  rC Clang

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

https://reviews.llvm.org/D55933

Files:
  include/clang/AST/NestedNameSpecifier.h
  lib/AST/NestedNameSpecifier.cpp
  lib/AST/TypePrinter.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
@@ -127,7 +127,7 @@
 static_assert(!(std::is_const()()), "message");
 // expected-error@-1{{static_assert failed due to requirement '!(std::is_const()())' "message"}}
 static_assert(std::is_same()), int>::value, "message");
-// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::value' "message"}}
+// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::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");
Index: test/SemaCXX/static-assert-cxx17.cpp
===
--- test/SemaCXX/static-assert-cxx17.cpp
+++ test/SemaCXX/static-assert-cxx17.cpp
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1z -triple=x86_64-linux-gnu
 
-template 
+template 
 struct S1 {
   static constexpr const bool value = false;
 };
@@ -14,7 +14,7 @@
   static inline constexpr bool var = global_inline_var;
 };
 
-template 
+template 
 inline constexpr bool constexpr_return_false() {
   return false;
 }
@@ -23,6 +23,8 @@
 void foo() {
   static_assert(S1::value);
   // expected-error@-1{{static_assert failed due to requirement 'S1::value'}}
+  static_assert(S1::value);
+  // expected-error@-1{{static_assert failed due to requirement 'S1::value'}}
 }
 template void foo();
 // expected-note@-1{{in instantiation of function template specialization 'foo' requested here}}
@@ -66,7 +68,7 @@
   using U = float;
 };
 
-template 
+template 
 struct X {
   int i = 0;
   int j = 0;
@@ -74,7 +76,7 @@
 };
 
 template 
-void foo6() {
+void test_template_parameter_from_default() {
   static_assert(X());
   // expected-error@-1{{static_assert failed due to requirement 'X()'}}
   static_assert(X{});
@@ -94,11 +96,55 @@
   static_assert(static_cast *>(nullptr));
   // expected-error@-1{{static_assert failed due to requirement 'static_cast *>(nullptr)'}}
   static_assert((const X[]){} == nullptr);
-  // expected-error@-1{{static_assert failed due to requirement '(X const[0]){} == nullptr'}}
+  // expected-error@-1{{static_assert failed due to requirement '(const X [0]){} == nullptr'}}
   static_assert(sizeof(X().X::~X())>) == 0);
   // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+  static_assert(constexpr_return_false());
+  // expected-error@-1{{static_assert failed due to requirement 'constexpr_return_false()'}}
+}
+template void test_template_parameter_from_default();
+// expected-note@-1{{in instantiation of function template specialization 'test_template_parameter_from_default' requested here}}
+
+template 
+void test_template_parameter_as_written() {
+  static_assert(X());
+  // expected-error@-1{{static_assert failed due to requirement 'X()'}}
+  static_assert(sizeof(X) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
   static_assert(constexpr_return_false());
   // expected-error@-1{{static_assert failed due to requirement 'constexpr_return_false()'}}
 }
-template void foo6();
-// expected-note@-1{{in instantiation of function template specialization 'foo6' requested here}}
+template void test_template_parameter_as_written();
+// expected-note@-1{{in instantiation of function template specialization 'test_template_parameter_as_written' requested here}}
+
+
+template
+struct is_pointerable { static constexpr bool value = false; };
+
+template
+struct is_pointerable { static constexpr bool value = true; };
+
+template
+void test_is_pointerable()
+{
+static_assert(is_pointerable::value);
+// expected-error@-1{{due to requirement 'is_pointerable::value'}}
+static_assert(not is_pointerable::value);
+// expected-error@-1{{due to requirement '!is_pointerable::value'}}
+}
+template void test_is_pointerable();
+// expected-note@-1{{in instantiation of function template specialization 'test_is_pointerable' requested here}}
+template void test_is_pointerable();
+// expected-note@-1{{in instantiation of function template specialization 'test_is_pointerable' requested here}}
+
+
+// This test emulates std::vector with a default allocator.
+// FIXME: Ideally we would like to avoid printing the default here (print 'S1 *, void>::

[PATCH] D55933: [Sema] Do not print default template parameters.

2019-01-03 Thread Clement Courbet via Phabricator via cfe-commits
courbet added inline comments.



Comment at: test/SemaCXX/static-assert-cxx17.cpp:109
+template 
+void foo7() {
+  static_assert(X());

Quuxplusone wrote:
> courbet wrote:
> > Quuxplusone wrote:
> > > None of these new test cases actually involve the default template 
> > > argument.
> > > 
> > > I'd like to see two test cases explicitly mimicking `vector`. (Warning: I 
> > > didn't run this code!)
> > > ```
> > > template struct A {};
> > > template> struct V {};
> > > template void testx() {
> > > static_assert(std::is_same::value, "");
> > > // expected-error@-1{{due to requirement 'std::is_same*, 
> > > void>::value'}}
> > > }
> > > template testx>();
> > > template struct PMRA {};
> > > template using PMRV = V>;
> > > template void test() {
> > > static_assert(std::is_same::value, "");
> > > // expected-error@-1{{due to requirement 'std::is_same > > PMRA>*, void>::value'}}
> > > // expected-error@-2{{due to requirement 'std::is_same*, 
> > > void>::value'}}
> > > }
> > > template testy>();
> > > ```
> > > The `expected-error@-2` above is my fantasy world. I don't think it's 
> > > possible to achieve in real life. :)
> > > None of these new test cases actually involve the default template 
> > > argument.
> > 
> > This one is to check that we actually do print when specified explicitly. 
> > foo6 above tests  the default template arguments (notice the change from 
> > `template  struct X to `template  
> > struct X` above). I've renamed `foo6` and `foo7` to make that clear.
> > 
> > Before this change, static_asserts in `foo6` and `foo7` printed the same 
> > thing. Now they don't.
> > 
> > > I'd like to see two test cases explicitly mimicking vector.
> > 
> > OK, I think I misunderstood what you wanted here. I don't think what you 
> > want is actually doable, because by the time you're in `test()`, C is just 
> > a type without any way of knowing whether the user explicitly provided the 
> > template parameter or relied on the default.
> > 
> > What we could do though is **always** erase template parameters that are 
> > the same as default ones. But that would mean printing `due to requirement 
> > 'std::is_same*, void>::value'` even when the user wrote `template 
> > testx>>();`.
> > WDYT ?
> > 
> > 
> Here's what I wrote over on D55270.
> 
> >>! In D55270#1327704, @Quuxplusone wrote:
> > @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`!)
> 
> So does this patch (D55933) actually change the message printed by Peter's 
> https://godbolt.org/z/TM0UHc ? (I think it does not.)
> Does it change the message printed by https://godbolt.org/z/Q0AD70 ? (I think 
> it does.)
> 
> I think most of your new test cases in `foo7` are redundant and don't really 
> need to be there. Contrariwise, I would like to see one new test case 
> isomorphic to https://godbolt.org/z/Q0AD70 , because that strikes me as a 
> very realistic case that we want to protect against regressions.
> So does this patch (D55933) actually change the message printed by Peter's 
> https://godbolt.org/z/TM0UHc ? (I think it does not.)

This is correct, it does not.

> Does it change the message printed by https://godbolt.org/z/Q0AD70 ? (I think 
> it does.)

It does.

> I think most of your new test cases in foo7 are redundant and don't really 
> need to be there. 

Sound good, but I've still kept a few cases for coverage.

> Contrariwise, I would like to see one new test case isomorphic to 
> https://godbolt.org/z/Q0AD70 , because that strikes me as a very realistic 
> case that we want to protect against regressions.

Done.


Repository:
  rC Clang

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

https://reviews.llvm.org/D55933



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


[PATCH] D55933: [Sema] Do not print default template parameters.

2019-01-04 Thread Clement Courbet via Phabricator via cfe-commits
courbet updated this revision to Diff 180220.
courbet marked 2 inline comments as done.
courbet added a comment.

Handle {L,R}Value references.


Repository:
  rC Clang

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

https://reviews.llvm.org/D55933

Files:
  include/clang/AST/NestedNameSpecifier.h
  lib/AST/NestedNameSpecifier.cpp
  lib/AST/TypePrinter.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
@@ -127,7 +127,7 @@
 static_assert(!(std::is_const()()), "message");
 // expected-error@-1{{static_assert failed due to requirement '!(std::is_const()())' "message"}}
 static_assert(std::is_same()), int>::value, "message");
-// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::value' "message"}}
+// expected-error@-1{{static_assert failed due to requirement 'std::is_same, int>::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");
Index: test/SemaCXX/static-assert-cxx17.cpp
===
--- test/SemaCXX/static-assert-cxx17.cpp
+++ test/SemaCXX/static-assert-cxx17.cpp
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1z -triple=x86_64-linux-gnu
 
-template 
+template 
 struct S1 {
   static constexpr const bool value = false;
 };
@@ -14,7 +14,7 @@
   static inline constexpr bool var = global_inline_var;
 };
 
-template 
+template 
 inline constexpr bool constexpr_return_false() {
   return false;
 }
@@ -23,6 +23,8 @@
 void foo() {
   static_assert(S1::value);
   // expected-error@-1{{static_assert failed due to requirement 'S1::value'}}
+  static_assert(S1::value);
+  // expected-error@-1{{static_assert failed due to requirement 'S1::value'}}
 }
 template void foo();
 // expected-note@-1{{in instantiation of function template specialization 'foo' requested here}}
@@ -66,7 +68,7 @@
   using U = float;
 };
 
-template 
+template 
 struct X {
   int i = 0;
   int j = 0;
@@ -74,7 +76,8 @@
 };
 
 template 
-void foo6() {
+void test_template_parameter_from_default() {
+  X x;
   static_assert(X());
   // expected-error@-1{{static_assert failed due to requirement 'X()'}}
   static_assert(X{});
@@ -93,12 +96,60 @@
   // expected-error@-1{{static_assert failed due to requirement '(const X *)nullptr'}}
   static_assert(static_cast *>(nullptr));
   // expected-error@-1{{static_assert failed due to requirement 'static_cast *>(nullptr)'}}
+  static_assert(static_cast &>(x));
+  // expected-error@-1{{static_assert failed due to requirement 'static_cast &>(x)'}}
+  static_assert(static_cast &&>(x));
+  // expected-error@-1{{static_assert failed due to requirement 'static_cast &&>(x)'}}
   static_assert((const X[]){} == nullptr);
-  // expected-error@-1{{static_assert failed due to requirement '(X const[0]){} == nullptr'}}
+  // expected-error@-1{{static_assert failed due to requirement '(const X [0]){} == nullptr'}}
   static_assert(sizeof(X().X::~X())>) == 0);
   // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
+  static_assert(constexpr_return_false());
+  // expected-error@-1{{static_assert failed due to requirement 'constexpr_return_false()'}}
+}
+template void test_template_parameter_from_default();
+// expected-note@-1{{in instantiation of function template specialization 'test_template_parameter_from_default' requested here}}
+
+template 
+void test_template_parameter_as_written() {
+  static_assert(X());
+  // expected-error@-1{{static_assert failed due to requirement 'X()'}}
+  static_assert(sizeof(X) == 0);
+  // expected-error@-1{{static_assert failed due to requirement 'sizeof(X) == 0'}}
   static_assert(constexpr_return_false());
   // expected-error@-1{{static_assert failed due to requirement 'constexpr_return_false()'}}
 }
-template void foo6();
-// expected-note@-1{{in instantiation of function template specialization 'foo6' requested here}}
+template void test_template_parameter_as_written();
+// expected-note@-1{{in instantiation of function template specialization 'test_template_parameter_as_written' requested here}}
+
+
+template
+struct is_pointerable { static constexpr bool value = false; };
+
+template
+struct is_pointerable { static constexpr bool value = true; };
+
+template
+void test_is_pointerable()
+{
+static_assert(is_pointerable::value);
+// expected-error@-1{{due to requirement 'is_pointerable::value'}}
+static_assert(not is_pointerable::value);
+// expected-error@-1{{due to requirement '!is_pointerable::value'}}
+}
+template void test_is_pointerable();
+// expected-note@-1{{in instantiation of function template specialization 'test_is_point

[PATCH] D55933: [Sema] Do not print default template parameters.

2019-01-04 Thread Clement Courbet via Phabricator via cfe-commits
courbet added inline comments.



Comment at: lib/AST/TypePrinter.cpp:179
+// `X` gets canonicalized to `X`. We disable
+// canonicalization so that `printTag()`` can see the template parameters 
as
+// written.

Quuxplusone wrote:
> Nit: there's an extra ` on this line.
> 
> I think I vaguely understand the purpose of this switch now. It feels ugly, 
> but I have no concrete suggestion for improvement. Do you not need a case 
> here to delay canonicalization of `X&` also?
Indeed. Fixed + added tests.


Repository:
  rC Clang

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

https://reviews.llvm.org/D55933



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


[PATCH] D67499: [Alignment] Move OffsetToAlignment to Alignment.h

2019-09-12 Thread Clement Courbet via Phabricator via cfe-commits
courbet added inline comments.



Comment at: llvm/lib/Target/ARM/ARMConstantIslandPass.cpp:1024
 NextBlockOffset = BBInfo[Water->getNumber()].postOffset();
-NextBlockLogAlignment = 0;
+NextBlockAlignment = llvm::Align();
   } else {

this statement is now useless.



Comment at: llvm/lib/Target/Mips/MipsSERegisterInfo.cpp:216
+const llvm::Align OffsetAlign =
+llvm::Align(getLoadStoreOffsetAlign(MI.getOpcode()));
 

what about:

```
const llvm::Align OffsetAlign =
llvm::Align(llvm::Align(getLoadStoreOffsetAlign(MI.getOpcode();
```

:)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D67499



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


[PATCH] D68141: [Alignment][NFC] Remove AllocaInst::setAlignment(unsigned)

2019-09-27 Thread Clement Courbet via Phabricator via cfe-commits
courbet added inline comments.



Comment at: llvm/lib/Target/AArch64/AArch64StackTagging.cpp:461
 void AArch64StackTagging::alignAndPadAlloca(AllocaInfo &Info) {
-  unsigned NewAlignment = std::max(Info.AI->getAlignment(), kTagGranuleSize);
+  MaybeAlign NewAlignment(std::max(Info.AI->getAlignment(), kTagGranuleSize));
   Info.AI->setAlignment(NewAlignment);

This could be an align, with a static_assert that  `kTagGranuleSize` is > 0



Comment at: llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp:2909
   ".byval");
-  AI->setAlignment(Align);
+  AI->setAlignment(MaybeAlign(Align));
   Arg.replaceAllUsesWith(AI);

This is an `Align` because the `0` case has been checked just above.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D68141



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


  1   2   3   >