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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits