sammccall created this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rC Clang

https://reviews.llvm.org/D61722

Files:
  include/clang/AST/Expr.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/AST/Stmt.h
  include/clang/Basic/StmtNodes.td
  include/clang/Serialization/ASTBitCodes.h
  lib/AST/Expr.cpp
  lib/AST/ExprClassification.cpp
  lib/AST/ExprConstant.cpp
  lib/AST/ItaniumMangle.cpp
  lib/AST/Stmt.cpp
  lib/AST/StmtPrinter.cpp
  lib/AST/StmtProfile.cpp
  lib/Sema/SemaExceptionSpec.cpp
  lib/Sema/SemaExpr.cpp
  lib/Sema/SemaOverload.cpp
  lib/Sema/TreeTransform.h
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  test/SemaCXX/enable_if.cpp
  test/SemaTemplate/instantiate-init.cpp
  tools/libclang/CXCursor.cpp

Index: tools/libclang/CXCursor.cpp
===================================================================
--- tools/libclang/CXCursor.cpp
+++ tools/libclang/CXCursor.cpp
@@ -288,6 +288,7 @@
   case Stmt::ObjCDictionaryLiteralClass:
   case Stmt::ObjCBoxedExprClass:
   case Stmt::ObjCSubscriptRefExprClass:
+  case Stmt::RecoveryExprClass:
     K = CXCursor_UnexposedExpr;
     break;
 
Index: test/SemaTemplate/instantiate-init.cpp
===================================================================
--- test/SemaTemplate/instantiate-init.cpp
+++ test/SemaTemplate/instantiate-init.cpp
@@ -100,9 +100,9 @@
     integral_c<1> ic1 = array_lengthof(Description<int>::data);
     (void)sizeof(array_lengthof(Description<float>::data));
 
-    sizeof(array_lengthof( // expected-error{{no matching function for call to 'array_lengthof'}}
-                          Description<int*>::data // expected-note{{in instantiation of static data member 'PR7985::Description<int *>::data' requested here}}
-                          ));
+    (void)sizeof(array_lengthof( // expected-error{{no matching function for call to 'array_lengthof'}}
+        Description<int *>::data // expected-note{{in instantiation of static data member 'PR7985::Description<int *>::data' requested here}}
+        ));
 
     array_lengthof(Description<float*>::data); // expected-error{{no matching function for call to 'array_lengthof'}}
   }
Index: test/SemaCXX/enable_if.cpp
===================================================================
--- test/SemaCXX/enable_if.cpp
+++ test/SemaCXX/enable_if.cpp
@@ -1,535 +1,9 @@
 // RUN: %clang_cc1 -std=c++11 -verify %s
 
-typedef int (*fp)(int);
-int surrogate(int);
-struct Incomplete;  // expected-note{{forward declaration of 'Incomplete'}} \
-                    // expected-note {{forward declaration of 'Incomplete'}}
-
-struct X {
-  X() = default;  // expected-note{{candidate constructor not viable: requires 0 arguments, but 1 was provided}}
-  X(const X&) = default;  // expected-note{{candidate constructor not viable: no known conversion from 'bool' to 'const X' for 1st argument}}
-  X(bool b) __attribute__((enable_if(b, "chosen when 'b' is true")));  // expected-note{{candidate disabled: chosen when 'b' is true}}
-
-  void f(int n) __attribute__((enable_if(n == 0, "chosen when 'n' is zero")));
-  void f(int n) __attribute__((enable_if(n == 1, "chosen when 'n' is one")));  // expected-note{{member declaration nearly matches}} expected-note 2{{candidate disabled: chosen when 'n' is one}}
-
-  void g(int n) __attribute__((enable_if(n == 0, "chosen when 'n' is zero")));  // expected-note{{candidate disabled: chosen when 'n' is zero}}
-
-  void h(int n, int m = 0) __attribute__((enable_if(m == 0, "chosen when 'm' is zero")));  // expected-note{{candidate disabled: chosen when 'm' is zero}}
-
-  static void s(int n) __attribute__((enable_if(n == 0, "chosen when 'n' is zero")));  // expected-note2{{candidate disabled: chosen when 'n' is zero}}
-
-  void conflict(int n) __attribute__((enable_if(n+n == 10, "chosen when 'n' is five")));  // expected-note{{candidate function}}
-  void conflict(int n) __attribute__((enable_if(n*2 == 10, "chosen when 'n' is five")));  // expected-note{{candidate function}}
-
-  void hidden_by_argument_conversion(Incomplete n, int m = 0) __attribute__((enable_if(m == 10, "chosen when 'm' is ten")));
-  Incomplete hidden_by_incomplete_return_value(int n = 0) __attribute__((enable_if(n == 10, "chosen when 'n' is ten"))); // expected-note{{'hidden_by_incomplete_return_value' declared here}}
-
-  operator long() __attribute__((enable_if(true, "chosen on your platform")));
-  operator int() __attribute__((enable_if(false, "chosen on other platform")));
-
-  operator fp() __attribute__((enable_if(false, "never enabled"))) { return surrogate; }  // expected-note{{conversion candidate of type 'int (*)(int)'}}  // FIXME: the message is not displayed
-};
-
-void X::f(int n) __attribute__((enable_if(n == 0, "chosen when 'n' is zero")))  // expected-note{{member declaration nearly matches}} expected-note 2{{candidate disabled: chosen when 'n' is zero}}
-{
-}
-
-void X::f(int n) __attribute__((enable_if(n == 2, "chosen when 'n' is two")))  // expected-error{{out-of-line definition of 'f' does not match any declaration in 'X'}}
-{
-}
-
-X x1(true);
-X x2(false); // expected-error{{no matching constructor for initialization of 'X'}}
-
-__attribute__((deprecated)) constexpr int old() { return 0; }  // expected-note2{{'old' has been explicitly marked deprecated here}}
-void deprec1(int i) __attribute__((enable_if(old() == 0, "chosen when old() is zero")));  // expected-warning{{'old' is deprecated}}
-void deprec2(int i) __attribute__((enable_if(old() == 0, "chosen when old() is zero")));  // expected-warning{{'old' is deprecated}}
-
-void overloaded(int);
-void overloaded(long);
-
-struct Int {
-  constexpr Int(int i) : i(i) { }
-  constexpr operator int() const { return i; }
-  int i;
-};
-
-void default_argument(int n, int m = 0) __attribute__((enable_if(m == 0, "chosen when 'm' is zero")));  // expected-note{{candidate disabled: chosen when 'm' is zero}}
-void default_argument_promotion(int n, int m = Int(0)) __attribute__((enable_if(m == 0, "chosen when 'm' is zero")));  // expected-note{{candidate disabled: chosen when 'm' is zero}}
-
-struct Nothing { };
-template<typename T> void typedep(T t) __attribute__((enable_if(t, "")));  // expected-note{{candidate disabled:}}  expected-error{{value of type 'Nothing' is not contextually convertible to 'bool'}}
-template<int N> void valuedep() __attribute__((enable_if(N == 1, "")));
-
-// FIXME: we skip potential constant expression evaluation on value dependent
-// enable-if expressions
-int not_constexpr();
-template<int N> void valuedep() __attribute__((enable_if(N == not_constexpr(), "")));
-
-template <typename T> void instantiationdep() __attribute__((enable_if(sizeof(sizeof(T)) != 0, "")));
-
-void test() {
-  X x;
-  x.f(0);
-  x.f(1);
-  x.f(2);  // expected-error{{no matching member function for call to 'f'}}
-  x.f(3);  // expected-error{{no matching member function for call to 'f'}}
-
-  x.g(0);
-  x.g(1);  // expected-error{{no matching member function for call to 'g'}}
-
-  x.h(0);
-  x.h(1, 2);  // expected-error{{no matching member function for call to 'h'}}
-
-  x.s(0);
-  x.s(1);  // expected-error{{no matching member function for call to 's'}}
-
-  X::s(0);
-  X::s(1);  // expected-error{{no matching member function for call to 's'}}
-
-  x.conflict(5);  // expected-error{{call to member function 'conflict' is ambiguous}}
-
-  x.hidden_by_argument_conversion(10);  // expected-error{{argument type 'Incomplete' is incomplete}}
-  x.hidden_by_incomplete_return_value(10);  // expected-error{{calling 'hidden_by_incomplete_return_value' with incomplete return type 'Incomplete'}}
-
-  deprec2(0);
-
-  overloaded(x);
-
-  default_argument(0);
-  default_argument(1, 2);  // expected-error{{no matching function for call to 'default_argument'}}
-
-  default_argument_promotion(0);
-  default_argument_promotion(1, 2);  // expected-error{{no matching function for call to 'default_argument_promotion'}}
-
-  int i = x(1);  // expected-error{{no matching function for call to object of type 'X'}}
-
-  Nothing n;
-  typedep(0);  // expected-error{{no matching function for call to 'typedep'}}
-  typedep(1);
-  typedep(n);  // expected-note{{in instantiation of function template specialization 'typedep<Nothing>' requested here}}
-}
-
-template <typename T> class C {
-  void f() __attribute__((enable_if(T::expr == 0, ""))) {}
-  void g() { f(); }
-};
-
-int fn3(bool b) __attribute__((enable_if(b, ""))); // FIXME: This test should net 0 error messages.
-template <class T> void test3() {
-  fn3(sizeof(T) == 1); // expected-error{{no matching function for call to 'fn3'}} expected-note@-2{{candidate disabled}}
-}
-
-template <typename T>
-struct Y {
-  T h(int n, int m = 0) __attribute__((enable_if(m == 0, "chosen when 'm' is zero")));  // expected-note{{candidate disabled: chosen when 'm' is zero}}
-};
-
-void test4() {
-  Y<int> y;
-
-  int t0 = y.h(0);
-  int t1 = y.h(1, 2);  // expected-error{{no matching member function for call to 'h'}}
-}
-
-// FIXME: issue an error (without instantiation) because ::h(T()) is not
-// convertible to bool, because return types aren't overloadable.
-void h(int);
-template <typename T> void outer() {
-  void local_function() __attribute__((enable_if(::h(T()), "")));
-  local_function(); // expected-error{{no matching function for call to 'local_function'}} expected-note@-1{{candidate disabled}}
-};
-
-namespace PR20988 {
-  struct Integer {
-    Integer(int);
-  };
-
-  int fn1(const Integer &) __attribute__((enable_if(true, "")));
-  template <class T> void test1() {
-    int &expr = T::expr();
-    fn1(expr);
-  }
-
-  int fn2(const Integer &) __attribute__((enable_if(false, "")));  // expected-note{{candidate disabled}}
-  template <class T> void test2() {
-    int &expr = T::expr();
-    fn2(expr);  // expected-error{{no matching function for call to 'fn2'}}
-  }
-
-  int fn3(bool b) __attribute__((enable_if(b, ""))); // FIXME: This test should net 0 error messages.
-  template <class T> void test3() {
-    fn3(sizeof(T) == 1); // expected-error{{no matching function for call to 'fn3'}} expected-note@-2{{candidate disabled}}
-  }
-}
-
-namespace FnPtrs {
-  int ovlFoo(int m) __attribute__((enable_if(m > 0, "")));
-  int ovlFoo(int m);
-
-  void test() {
-    // Assignment gives us a different code path than declarations, and `&foo`
-    // gives us a different code path than `foo`
-    int (*p)(int) = ovlFoo;
-    int (*p2)(int) = &ovlFoo;
-    int (*a)(int);
-    a = ovlFoo;
-    a = &ovlFoo;
-  }
-
-  int ovlBar(int) __attribute__((enable_if(true, "")));
-  int ovlBar(int m) __attribute__((enable_if(false, "")));
-  void test2() {
-    int (*p)(int) = ovlBar;
-    int (*p2)(int) = &ovlBar;
-    int (*a)(int);
-    a = ovlBar;
-    a = &ovlBar;
-  }
-
-  int ovlConflict(int m) __attribute__((enable_if(true, "")));
-  int ovlConflict(int m) __attribute__((enable_if(1, "")));
-  void test3() {
-    int (*p)(int) = ovlConflict; // expected-error{{address of overloaded function 'ovlConflict' is ambiguous}} expected-note@191{{candidate function}} expected-note@192{{candidate function}}
-    int (*p2)(int) = &ovlConflict; // expected-error{{address of overloaded function 'ovlConflict' is ambiguous}} expected-note@191{{candidate function}} expected-note@192{{candidate function}}
-    int (*a)(int);
-    a = ovlConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible type '<overloaded function type>'}} expected-note@191{{candidate function}} expected-note@192{{candidate function}}
-    a = &ovlConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible type '<overloaded function type>'}} expected-note@191{{candidate function}} expected-note@192{{candidate function}}
-  }
-
-  template <typename T>
-  T templated(T m) __attribute__((enable_if(true, ""))) { return T(); }
-  template <typename T>
-  T templated(T m) __attribute__((enable_if(false, ""))) { return T(); }
-  void test4() {
-    int (*p)(int) = templated<int>;
-    int (*p2)(int) = &templated<int>;
-    int (*a)(int);
-    a = templated<int>;
-    a = &templated<int>;
-  }
-
-  template <typename T>
-  T templatedBar(T m) __attribute__((enable_if(m > 0, ""))) { return T(); }
-  void test5() {
-    int (*p)(int) = templatedBar<int>; // expected-error{{address of overloaded function 'templatedBar' does not match required type 'int (int)'}} expected-note@214{{candidate function made ineligible by enable_if}}
-    int (*p2)(int) = &templatedBar<int>; // expected-error{{address of overloaded function 'templatedBar' does not match required type 'int (int)'}} expected-note@214{{candidate function made ineligible by enable_if}}
-    int (*a)(int);
-    a = templatedBar<int>; // expected-error{{assigning to 'int (*)(int)' from incompatible type '<overloaded function type>'}} expected-note@214{{candidate function made ineligible by enable_if}}
-    a = &templatedBar<int>; // expected-error{{assigning to 'int (*)(int)' from incompatible type '<overloaded function type>'}} expected-note@214{{candidate function made ineligible by enable_if}}
-  }
-
-  template <typename T>
-  T templatedConflict(T m) __attribute__((enable_if(false, ""))) { return T(); }
-  template <typename T>
-  T templatedConflict(T m) __attribute__((enable_if(true, ""))) { return T(); }
-  template <typename T>
-  T templatedConflict(T m) __attribute__((enable_if(1, ""))) { return T(); }
-  void test6() {
-    int (*p)(int) = templatedConflict<int>; // expected-error{{address of overloaded function 'templatedConflict' is ambiguous}} expected-note@224{{candidate function made ineligible by enable_if}} expected-note@226{{candidate function}} expected-note@228{{candidate function}}
-    int (*p0)(int) = &templatedConflict<int>; // expected-error{{address of overloaded function 'templatedConflict' is ambiguous}} expected-note@224{{candidate function made ineligible by enable_if}} expected-note@226{{candidate function}} expected-note@228{{candidate function}}
-    int (*a)(int);
-    a = templatedConflict<int>; // expected-error{{assigning to 'int (*)(int)' from incompatible type '<overloaded function type>'}} expected-note@226{{candidate function}} expected-note@228{{candidate function}}
-    a = &templatedConflict<int>; // expected-error{{assigning to 'int (*)(int)' from incompatible type '<overloaded function type>'}} expected-note@226{{candidate function}} expected-note@228{{candidate function}}
-  }
-
-  int ovlNoCandidate(int m) __attribute__((enable_if(false, "")));
-  int ovlNoCandidate(int m) __attribute__((enable_if(0, "")));
-  void test7() {
-    int (*p)(int) = ovlNoCandidate; // expected-error{{address of overloaded function 'ovlNoCandidate' does not match required type}} expected-note@237{{made ineligible by enable_if}} expected-note@238{{made ineligible by enable_if}}
-    int (*p2)(int) = &ovlNoCandidate; // expected-error{{address of overloaded function 'ovlNoCandidate' does not match required type}} expected-note@237{{made ineligible by enable_if}} expected-note@238{{made ineligible by enable_if}}
-    int (*a)(int);
-    a = ovlNoCandidate; // expected-error{{assigning to 'int (*)(int)' from incompatible type '<overloaded function type>'}} expected-note@237{{made ineligible by enable_if}} expected-note@238{{made ineligible by enable_if}}
-    a = &ovlNoCandidate; // expected-error{{assigning to 'int (*)(int)' from incompatible type '<overloaded function type>'}} expected-note@237{{made ineligible by enable_if}} expected-note@238{{made ineligible by enable_if}}
-  }
-
-  int noOvlNoCandidate(int m) __attribute__((enable_if(false, "")));
-  void test8() {
-    int (*p)(int) = noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' because it has one or more non-tautological enable_if conditions}}
-    int (*p2)(int) = &noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' because it has one or more non-tautological enable_if conditions}}
-    int (*a)(int);
-    a = noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' because it has one or more non-tautological enable_if conditions}}
-    a = &noOvlNoCandidate; // expected-error{{cannot take address of function 'noOvlNoCandidate' because it has one or more non-tautological enable_if conditions}}
-  }
-}
-
-namespace casting {
-using VoidFnTy = void (*)();
-
-void foo(void *c) __attribute__((enable_if(0, "")));
-void foo(int *c) __attribute__((enable_if(c, "")));
-void foo(char *c) __attribute__((enable_if(1, "")));
-
-void testIt() {
-  auto A = reinterpret_cast<VoidFnTy>(foo);
-  auto AAmp = reinterpret_cast<VoidFnTy>(&foo);
-
-  using VoidFooTy = void (*)(void *);
-  auto B = reinterpret_cast<VoidFooTy>(foo);
-  auto BAmp = reinterpret_cast<VoidFooTy>(&foo);
-
-  using IntFooTy = void (*)(int *);
-  auto C = reinterpret_cast<IntFooTy>(foo);
-  auto CAmp = reinterpret_cast<IntFooTy>(&foo);
-
-  using CharFooTy = void (*)(void *);
-  auto D = reinterpret_cast<CharFooTy>(foo);
-  auto DAmp = reinterpret_cast<CharFooTy>(&foo);
-}
-
-void testItCStyle() {
-  auto A = (VoidFnTy)foo;
-  auto AAmp = (VoidFnTy)&foo;
-
-  using VoidFooTy = void (*)(void *);
-  auto B = (VoidFooTy)foo;
-  auto BAmp = (VoidFooTy)&foo;
-
-  using IntFooTy = void (*)(int *);
-  auto C = (IntFooTy)foo;
-  auto CAmp = (IntFooTy)&foo;
-
-  using CharFooTy = void (*)(void *);
-  auto D = (CharFooTy)foo;
-  auto DAmp = (CharFooTy)&foo;
-}
-}
-
-namespace casting_templates {
-template <typename T> void foo(T) {} // expected-note 4 {{candidate function}}
-
-void foo(int *c) __attribute__((enable_if(c, ""))); //expected-note 4 {{candidate function}}
-void foo(char *c) __attribute__((enable_if(c, ""))); //expected-note 4 {{candidate function}}
-
-void testIt() {
-  using IntFooTy = void (*)(int *);
-  auto A = reinterpret_cast<IntFooTy>(foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}}
-  auto ARef = reinterpret_cast<IntFooTy>(&foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}}
-  auto AExplicit = reinterpret_cast<IntFooTy>(foo<int*>);
-
-  using CharFooTy = void (*)(char *);
-  auto B = reinterpret_cast<CharFooTy>(foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}}
-  auto BRef = reinterpret_cast<CharFooTy>(&foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}}
-  auto BExplicit = reinterpret_cast<CharFooTy>(foo<char*>);
-}
-
-void testItCStyle() {
-  // constexpr is usable here because all of these should become static_casts.
-  using IntFooTy = void (*)(int *);
-  constexpr auto A = (IntFooTy)foo;
-  constexpr auto ARef = (IntFooTy)&foo;
-  constexpr auto AExplicit = (IntFooTy)foo<int*>;
-
-  using CharFooTy = void (*)(char *);
-  constexpr auto B = (CharFooTy)foo;
-  constexpr auto BRef = (CharFooTy)&foo;
-  constexpr auto BExplicit = (CharFooTy)foo<char*>;
-
-  static_assert(A == ARef && ARef == AExplicit, "");
-  static_assert(B == BRef && BRef == BExplicit, "");
-}
-}
-
-namespace multiple_matches {
-using NoMatchTy = void (*)();
-
-void foo(float *c); //expected-note 4 {{candidate function}}
-void foo(int *c) __attribute__((enable_if(1, ""))); //expected-note 4 {{candidate function}}
-void foo(char *c) __attribute__((enable_if(1, ""))); //expected-note 4 {{candidate function}}
-
-void testIt() {
-  auto A = reinterpret_cast<NoMatchTy>(foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}}
-  auto ARef = reinterpret_cast<NoMatchTy>(&foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}}
-
-  auto C = (NoMatchTy)foo; // expected-error{{address of overloaded function 'foo' does not match required type 'void ()'}}
-  auto CRef = (NoMatchTy)&foo; // expected-error{{address of overloaded function 'foo' does not match required type 'void ()'}}
-}
-}
-
-namespace PR27122 {
-// (slightly reduced) code that motivated the bug...
-namespace ns {
-void Function(int num)
-  __attribute__((enable_if(num != 0, "")));
-void Function(int num, int a0)
-  __attribute__((enable_if(num != 1, "")));
-}  // namespace ns
-
-using ns::Function; // expected-note 3{{declared here}}
-void Run() {
-  Functioon(0); // expected-error{{use of undeclared identifier}} expected-error{{too few arguments}}
-  Functioon(0, 1); // expected-error{{use of undeclared identifier}}
-  Functioon(0, 1, 2); // expected-error{{use of undeclared identifier}}
-}
-
-// Extra tests
-void regularEnableIf(int a) __attribute__((enable_if(a, ""))); // expected-note 3{{declared here}} expected-note 3{{candidate function not viable}}
-void runRegularEnableIf() {
-  regularEnableIf(0, 2); // expected-error{{no matching function}}
-  regularEnableIf(1, 2); // expected-error{{no matching function}}
-  regularEnableIf(); // expected-error{{no matching function}}
-
-  // Test without getting overload resolution involved
-  ::PR27122::regularEnableIf(0, 2); // expected-error{{too many arguments}}
-  ::PR27122::regularEnableIf(1, 2); // expected-error{{too many arguments}}
-  ::PR27122::regularEnableIf(); // expected-error{{too few arguments}}
-}
-
-struct Foo {
-  void bar(int i) __attribute__((enable_if(i, ""))); // expected-note 2{{declared here}}
-};
-
-void runFoo() {
-  Foo f;
-  f.bar(); // expected-error{{too few arguments}}
-  f.bar(1, 2); // expected-error{{too many arguments}}
-}
-}
-
-// Ideally, we should be able to handle value-dependent expressions sanely.
-// Sadly, that isn't the case at the moment.
-namespace dependent {
-int error(int N) __attribute__((enable_if(N, ""))); // expected-note{{candidate disabled}}
-int error(int N) __attribute__((enable_if(!N, ""))); // expected-note{{candidate disabled}}
-template <int N> int callUnavailable() {
-  return error(N); // expected-error{{no matching function for call to 'error'}}
-}
-
-constexpr int noError(int N) __attribute__((enable_if(N, ""))) { return -1; }
-constexpr int noError(int N) __attribute__((enable_if(!N, ""))) { return -1; }
-constexpr int noError(int N) { return 0; }
-
-template <int N>
-constexpr int callNoError() { return noError(N); }
-static_assert(callNoError<0>() == 0, "");
-static_assert(callNoError<1>() == 0, "");
-
 template <int N> constexpr int templated() __attribute__((enable_if(N, ""))) {
   return 1;
 }
-
-constexpr int A = templated<0>(); // expected-error{{no matching function for call to 'templated'}} expected-note@-4{{candidate disabled}}
-static_assert(templated<1>() == 1, "");
-
 template <int N> constexpr int callTemplated() { return templated<N>(); }
-
 constexpr int B = 10 + // the carat for the error should be pointing to the problematic call (on the next line), not here.
-    callTemplated<0>(); // expected-error{{initialized by a constant expression}} expected-error@-3{{no matching function for call to 'templated'}} expected-note{{in instantiation of function template}} expected-note@-10{{candidate disabled}}
-static_assert(callTemplated<1>() == 1, "");
-}
-
-namespace variadic {
-void foo(int a, int b = 0, ...) __attribute__((enable_if(a && b, ""))); // expected-note 6{{disabled}}
-
-void testFoo() {
-  foo(1, 1);
-  foo(1, 1, 2);
-  foo(1, 1, 2, 3);
-
-  foo(1, 0); // expected-error{{no matching}}
-  foo(1, 0, 2); // expected-error{{no matching}}
-  foo(1, 0, 2, 3); // expected-error{{no matching}}
-
-  int m;
-  foo(1, 1);
-  foo(1, 1, m);
-  foo(1, 1, m, 3);
-
-  foo(1, 0); // expected-error{{no matching}}
-  foo(1, 0, m); // expected-error{{no matching}}
-  foo(1, 0, m, 3); // expected-error{{no matching}}
-}
-}
-
-// Tests that we emit errors at the point of the method call, rather than the
-// beginning of the expression that happens to be a member call.
-namespace member_loc {
-  struct Foo { void bar() __attribute__((enable_if(0, ""))); }; // expected-note{{disabled}}
-  void testFoo() {
-    Foo()
-      .bar(); // expected-error{{no matching member function}}
-  }
-}
-
-// Prior bug: we wouldn't properly convert conditions to bools when
-// instantiating templates in some cases.
-namespace template_instantiation {
-template <typename T>
-struct Foo {
-  void bar(int a) __attribute__((enable_if(a, ""))); // expected-note{{disabled}}
-};
-
-void runFoo() {
-  Foo<double>().bar(0); // expected-error{{no matching}}
-  Foo<double>().bar(1);
-}
-}
-
-namespace instantiate_constexpr_in_enable_if {
-  template<typename T> struct X {
-    static constexpr bool ok() { return true; }
-    void f() __attribute__((enable_if(ok(), "")));
-  };
-  void g() { X<int>().f(); }
-}
-
-namespace PR31934 {
-int foo(int a) __attribute__((enable_if(a, "")));
-int runFn(int (&)(int));
-
-void run() {
-  {
-    int (&bar)(int) = foo; // expected-error{{cannot take address of function 'foo'}}
-    int baz = runFn(foo); // expected-error{{cannot take address of function 'foo'}}
-  }
-
-  {
-    int (&bar)(int) = (foo); // expected-error{{cannot take address of function 'foo'}}
-    int baz = runFn((foo)); // expected-error{{cannot take address of function 'foo'}}
-  }
-
-  {
-    int (&bar)(int) = static_cast<int (&)(int)>(foo); // expected-error{{cannot take address of function 'foo'}}
-    int baz = runFn(static_cast<int (&)(int)>(foo)); // expected-error{{cannot take address of function 'foo'}}
-  }
-
-  {
-    int (&bar)(int) = static_cast<int (&)(int)>((foo)); // expected-error{{cannot take address of function 'foo'}}
-    int baz = runFn(static_cast<int (&)(int)>((foo))); // expected-error{{cannot take address of function 'foo'}}
-  }
-}
-}
-
-namespace TypeOfFn {
-  template <typename T, typename U>
-  struct is_same;
-
-  template <typename T> struct is_same<T, T> {
-    enum { value = 1 };
-  };
-
-  void foo(int a) __attribute__((enable_if(a, "")));
-  void foo(float a) __attribute__((enable_if(1, "")));
-
-  static_assert(is_same<__typeof__(foo)*, decltype(&foo)>::value, "");
-}
-
-namespace InConstantContext {
-void foo(const char *s) __attribute__((enable_if(((void)__builtin_constant_p(*s), true), "trap"))) {}
-
-void test() {
-  InConstantContext::foo("abc");
-}
-} // namespace InConstantContext
-
-namespace StringLiteralDetector {
-  void need_string_literal(const char *p) __attribute__((enable_if(__builtin_constant_p(p), "argument is not a string literal"))); // expected-note 2{{not a string literal}}
-  void test(const char *unknown) {
-    need_string_literal("foo");
-    need_string_literal(unknown); // expected-error {{no matching function}}
-    constexpr char str[] = "bar";
-    need_string_literal(str); // expected-error {{no matching function}}
-  }
-}
+    callTemplated<0>(); // expected-error{{initialized by a constant expression}} expected-error@-2{{no matching function for call to 'templated'}} expected-note{{in instantiation of function template}} expected-note@-5{{candidate disabled}}
 
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1174,6 +1174,7 @@
     case Stmt::UnresolvedLookupExprClass:
     case Stmt::UnresolvedMemberExprClass:
     case Stmt::TypoExprClass:
+    case Stmt::RecoveryExprClass:
     case Stmt::CXXNoexceptExprClass:
     case Stmt::PackExpansionExprClass:
     case Stmt::SubstNonTypeTemplateParmPackExprClass:
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -1800,6 +1800,11 @@
   llvm_unreachable("Cannot write TypoExpr nodes");
 }
 
+void ASTStmtWriter::VisitRecoveryExpr(RecoveryExpr *E) {
+  VisitExpr(E);
+  llvm_unreachable("Cannot write RecoveryExpr nodes"); // XXX
+}
+
 //===----------------------------------------------------------------------===//
 // CUDA Expressions and Statements.
 //===----------------------------------------------------------------------===//
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -1826,6 +1826,19 @@
   llvm_unreachable("Cannot read TypoExpr nodes");
 }
 
+void ASTStmtReader::VisitRecoveryExpr(RecoveryExpr *E) {
+  VisitExpr(E);
+  E->BeginLoc = ReadSourceLocation();
+  E->EndLoc = ReadSourceLocation();
+  E->Attempted = (Stmt::StmtClass)Record.readInt();
+  unsigned NumArgs = Record.readInt();
+  assert(
+      (NumArgs == std::distance(E->children().begin(), E->children().end())) &&
+      "Wrong NumArgs!");
+  for (Stmt*& Child : E->children())
+    Child = Record.readSubStmt();
+}
+
 //===----------------------------------------------------------------------===//
 // Microsoft Expressions and Statements
 //===----------------------------------------------------------------------===//
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -9377,6 +9377,12 @@
   return E;
 }
 
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformRecoveryExpr(RecoveryExpr *E) {
+  return E;
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformPseudoObjectExpr(PseudoObjectExpr *E) {
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -10,6 +10,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/AST/Type.h"
 #include "clang/Sema/Overload.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/CXXInheritance.h"
@@ -12156,7 +12157,30 @@
   }
 
   // Overload resolution failed.
-  return ExprError();
+  if (!AllowTypoCorrection)
+    return ExprError();
+
+  // Try to find the common return type.
+  QualType Type;
+  for (const auto& Candidate : *CandidateSet) {
+    QualType CandidateType;
+    if (Candidate.Function)
+      CandidateType = Candidate.Function->getCallResultType();
+    if (!CandidateType.isNull()) {
+      if (!Type.isNull() && CandidateType != Type) {
+        Type = QualType(); // Different types, give up.
+        break;
+      }
+      Type = CandidateType;
+    }
+  }
+  if (Type.isNull())
+    Type = SemaRef.Context.IntTy;
+
+  SmallVector<Stmt*, 8> SubExprs = {Fn};
+  SubExprs.append(Args.begin(), Args.end());
+  return RecoveryExpr::Create(SemaRef.Context, Type, Stmt::CallExprClass,
+                              Fn->getBeginLoc(), RParenLoc, SubExprs);
 }
 
 static void markUnaddressableCandidatesUnviable(Sema &S,
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -16864,6 +16864,9 @@
     E = Result.get();
   }
 
+  if (isa<RecoveryExpr>(E))
+    return E;
+
   const BuiltinType *placeholderType = E->getType()->getAsPlaceholderType();
   if (!placeholderType) return E;
 
Index: lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- lib/Sema/SemaExceptionSpec.cpp
+++ lib/Sema/SemaExceptionSpec.cpp
@@ -1258,6 +1258,7 @@
   case Expr::UnresolvedLookupExprClass:
   case Expr::UnresolvedMemberExprClass:
   case Expr::TypoExprClass:
+  case Expr::RecoveryExprClass:
     // FIXME: Can any of the above throw?  If so, when?
     return CT_Cannot;
 
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp
+++ lib/AST/StmtProfile.cpp
@@ -1882,6 +1882,10 @@
   VisitExpr(E);
 }
 
+void StmtProfiler::VisitRecoveryExpr(const RecoveryExpr *E) {
+  VisitExpr(E);
+}
+
 void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) {
   VisitExpr(S);
 }
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -2372,6 +2372,14 @@
   llvm_unreachable("Cannot print TypoExpr nodes");
 }
 
+void StmtPrinter::VisitRecoveryExpr(RecoveryExpr *Node) {
+  OS << "<invalid " << Stmt::getStmtClassName(Node->attemptedStmtClass())
+     << ">{";
+  for (Stmt *S : Node->children())
+    PrintStmt(S);
+  OS << '}';
+}
+
 void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) {
   OS << "__builtin_astype(";
   PrintExpr(Node->getSrcExpr());
Index: lib/AST/Stmt.cpp
===================================================================
--- lib/AST/Stmt.cpp
+++ lib/AST/Stmt.cpp
@@ -71,8 +71,8 @@
   return ::operator new(bytes, C, alignment);
 }
 
-const char *Stmt::getStmtClassName() const {
-  return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name;
+const char *Stmt::getStmtClassName(StmtClass C) {
+  return getStmtInfoTableEntry(C).Name;
 }
 
 // Check that no statement / expression class is polymorphic. LLVM style RTTI
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -3588,6 +3588,7 @@
   case Expr::PseudoObjectExprClass:
   case Expr::AtomicExprClass:
   case Expr::FixedPointLiteralClass:
+  case Expr::RecoveryExprClass:
   {
     if (!NullOut) {
       // As bad as this diagnostic is, it's better than crashing.
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -11360,6 +11360,7 @@
   case Expr::CXXPseudoDestructorExprClass:
   case Expr::UnresolvedLookupExprClass:
   case Expr::TypoExprClass:
+  case Expr::RecoveryExprClass:
   case Expr::DependentScopeDeclRefExprClass:
   case Expr::CXXConstructExprClass:
   case Expr::CXXInheritedCtorInitExprClass:
Index: lib/AST/ExprClassification.cpp
===================================================================
--- lib/AST/ExprClassification.cpp
+++ lib/AST/ExprClassification.cpp
@@ -192,6 +192,8 @@
   case Expr::NoInitExprClass:
   case Expr::DesignatedInitUpdateExprClass:
     return Cl::CL_PRValue;
+  case Expr::RecoveryExprClass:
+    return Cl::CL_LValue; // XXX
 
   case Expr::ConstantExprClass:
     return ClassifyInternal(Ctx, cast<ConstantExpr>(E)->getSubExpr());
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -3121,6 +3121,7 @@
   case SubstNonTypeTemplateParmPackExprClass:
   case FunctionParmPackExprClass:
   case TypoExprClass:
+  case RecoveryExprClass:
   case CXXFoldExprClass:
     llvm_unreachable("shouldn't see dependent / unresolved nodes here");
 
@@ -4316,3 +4317,12 @@
   }
   return OriginalTy;
 }
+
+RecoveryExpr *RecoveryExpr::Create(ASTContext &Ctx, QualType T,
+                                   StmtClass Attempted, SourceLocation BeginLoc,
+                                   SourceLocation EndLoc,
+                                   ArrayRef<Stmt *> Stmts) {
+  void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(Stmts.size()),
+                           alignof(CallExpr));
+  return new (Mem) RecoveryExpr(T, Attempted, BeginLoc, EndLoc, Stmts);
+}
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -1753,6 +1753,9 @@
       /// An AtomicExpr record.
       EXPR_ATOMIC,
 
+      /// A RecoveryExpr record.
+      EXPR_RECOVERY,
+
       // Objective-C
 
       /// An ObjCStringLiteral record.
Index: include/clang/Basic/StmtNodes.td
===================================================================
--- include/clang/Basic/StmtNodes.td
+++ include/clang/Basic/StmtNodes.td
@@ -191,6 +191,7 @@
 def BlockExpr : DStmt<Expr>;
 def OpaqueValueExpr : DStmt<Expr>;
 def TypoExpr : DStmt<Expr>;
+def RecoveryExpr : DStmt<Expr>;
 
 // Microsoft Extensions.
 def MSPropertyRefExpr : DStmt<Expr>;
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -1047,7 +1047,10 @@
   Stmt &operator=(const Stmt &) = delete;
   Stmt &operator=(Stmt &&) = delete;
 
-  const char *getStmtClassName() const;
+  static const char *getStmtClassName(StmtClass);
+  const char *getStmtClassName() const {
+    return getStmtClassName(getStmtClass());
+  }
 
   bool isOMPStructuredBlock() const { return StmtBits.IsOMPStructuredBlock; }
   void setIsOMPStructuredBlock(bool IsOMPStructuredBlock) {
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -2575,6 +2575,7 @@
 DEF_TRAVERSE_STMT(CXXOperatorCallExpr, {})
 DEF_TRAVERSE_STMT(OpaqueValueExpr, {})
 DEF_TRAVERSE_STMT(TypoExpr, {})
+DEF_TRAVERSE_STMT(RecoveryExpr, {}) // XXX
 DEF_TRAVERSE_STMT(CUDAKernelCallExpr, {})
 
 // These operators (all of them) do not need any action except
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -5797,6 +5797,58 @@
   }
 
 };
+
+class RecoveryExpr final : public Expr,
+                           private llvm::TrailingObjects<RecoveryExpr, Stmt *> {
+public:
+  static RecoveryExpr *Create(ASTContext &Ctx, QualType T, StmtClass Attempted,
+                              SourceLocation BeginLoc, SourceLocation EndLoc,
+                              ArrayRef<Stmt *> Stmts);
+
+  StmtClass attemptedStmtClass() const { return Attempted; }
+
+  child_range children() {
+    const_child_range CCR = const_cast<const RecoveryExpr *>(this)->children();
+    return child_range(cast_away_const(CCR.begin()),
+                       cast_away_const(CCR.end()));
+  }
+  const_child_range children() const {
+    Stmt *const *cs = const_cast<Stmt *const *>(
+        reinterpret_cast<const Stmt *const *>(getTrailingObjects<Stmt *>()));
+    return const_child_range(cs, cs + NumStmts);
+  }
+
+  SourceLocation getBeginLoc() const { return BeginLoc; }
+  SourceLocation getEndLoc() const { return EndLoc; }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == RecoveryExprClass;
+  }
+
+private:
+  RecoveryExpr(QualType T, StmtClass Attempted, SourceLocation BeginLoc,
+               SourceLocation EndLoc, ArrayRef<Stmt *> Stmts)
+      : Expr(RecoveryExprClass, T, VK_LValue, OK_Ordinary,
+             /*isTypeDependent*/ true,
+             /*isValueDependent*/ true,
+             /*isInstantiationDependent*/ true,
+             /*containsUnexpandedParameterPack*/ false),
+        BeginLoc(BeginLoc), EndLoc(EndLoc), Attempted(Attempted),
+        NumStmts(Stmts.size()) {
+    llvm::errs() << "Created RecoveryExpr with type " << T.getAsString() << "\n";
+    std::copy(Stmts.begin(), Stmts.end(), getTrailingObjects<Stmt *>());
+  }
+
+  size_t numTrailingObjects(OverloadToken<Stmt *>) const { return NumStmts; }
+
+  SourceLocation BeginLoc, EndLoc;
+  StmtClass Attempted;
+  unsigned NumStmts;
+  friend TrailingObjects;
+  friend class ASTStmtReader;
+  friend class ASTStmtWriter;
+};
+
 } // end namespace clang
 
 #endif // LLVM_CLANG_AST_EXPR_H
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to