Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -5797,6 +5797,61 @@ } }; + +class RecoveryExpr final : public Expr, + private llvm::TrailingObjects { +public: + static RecoveryExpr *Create(ASTContext &Ctx, QualType T, StmtClass Attempted, + SourceLocation BeginLoc, SourceLocation EndLoc, + ArrayRef Stmts); + static RecoveryExpr *CreateEmpty(ASTContext &Ctx, unsigned NumStmts); + + StmtClass attemptedStmtClass() const { return Attempted; } + + child_range children() { + const_child_range CCR = const_cast(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( + reinterpret_cast(getTrailingObjects())); + 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 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()); + } + + RecoveryExpr(EmptyShell Empty) : Expr(RecoveryExprClass, Empty) {} + + size_t numTrailingObjects(OverloadToken) 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 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/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/Basic/StmtNodes.td =================================================================== --- include/clang/Basic/StmtNodes.td +++ include/clang/Basic/StmtNodes.td @@ -191,6 +191,7 @@ def BlockExpr : DStmt; def OpaqueValueExpr : DStmt; def TypoExpr : DStmt; +def RecoveryExpr : DStmt; // Microsoft Extensions. def MSPropertyRefExpr : DStmt; 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: 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,18 @@ } return OriginalTy; } + +RecoveryExpr *RecoveryExpr::Create(ASTContext &Ctx, QualType T, + StmtClass Attempted, SourceLocation BeginLoc, + SourceLocation EndLoc, + ArrayRef Stmts) { + void *Mem = Ctx.Allocate(totalSizeToAlloc(Stmts.size()), + alignof(CallExpr)); + return new (Mem) RecoveryExpr(T, Attempted, BeginLoc, EndLoc, Stmts); +} + +RecoveryExpr *RecoveryExpr::CreateEmpty(ASTContext &Ctx, unsigned NumStmts) { + void *Mem = + Ctx.Allocate(totalSizeToAlloc(NumStmts), alignof(CallExpr)); + return new (Mem) RecoveryExpr(EmptyShell()); +} 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(E)->getSubExpr()); 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/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/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/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 << "attemptedStmtClass()) + << ">{"; + for (Stmt *S : Node->children()) + PrintStmt(S); + OS << '}'; +} + void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) { OS << "__builtin_astype("; PrintExpr(Node->getSrcExpr()); 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/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/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -16864,6 +16864,9 @@ E = Result.get(); } + if (isa(E)) + return E; + const BuiltinType *placeholderType = E->getType()->getAsPlaceholderType(); if (!placeholderType) return 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 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/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -9377,6 +9377,12 @@ return E; } +template +ExprResult +TreeTransform::TransformRecoveryExpr(RecoveryExpr *E) { + return E; +} + template ExprResult TreeTransform::TransformPseudoObjectExpr(PseudoObjectExpr *E) { Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -1826,6 +1826,20 @@ llvm_unreachable("Cannot read TypoExpr nodes"); } +void ASTStmtReader::VisitRecoveryExpr(RecoveryExpr *E) { + VisitExpr(E); + unsigned NumArgs = Record.readInt(); + E->BeginLoc = ReadSourceLocation(); + E->EndLoc = ReadSourceLocation(); + E->Attempted = (Stmt::StmtClass)Record.readInt(); + assert( + (NumArgs == std::distance(E->children().begin(), E->children().end())) && + "Wrong NumArgs!"); + (void)NumArgs; + for (Stmt*& Child : E->children()) + Child = Record.readSubStmt(); +} + //===----------------------------------------------------------------------===// // Microsoft Expressions and Statements //===----------------------------------------------------------------------===// @@ -2532,6 +2546,11 @@ Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], Empty); break; + case EXPR_RECOVERY: + S = RecoveryExpr::CreateEmpty( + Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields]); + break; + case EXPR_MEMBER: { // We load everything here and fully initialize it at creation. // That way we can use MemberExpr::Create and don't have to duplicate its Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -11,6 +11,7 @@ /// //===----------------------------------------------------------------------===// +#include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ASTWriter.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" @@ -655,6 +656,17 @@ Code = serialization::EXPR_CALL; } +void ASTStmtWriter::VisitRecoveryExpr(RecoveryExpr *E) { + VisitExpr(E); + Record.push_back(std::distance(E->children().begin(), E->children().end())); + Record.AddSourceLocation(E->getBeginLoc()); + Record.AddSourceLocation(E->getEndLoc()); + Record.push_back(E->attemptedStmtClass()); + for (Stmt* Child : E->children()) + Record.AddStmt(Child); + Code = serialization::EXPR_RECOVERY; +} + void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) { // Don't call VisitExpr, we'll write everything here. 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: 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 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 void valuedep() __attribute__((enable_if(N == 1, ""))); - -// FIXME: we skip potential constant expression evaluation on value dependent -// enable-if expressions -int not_constexpr(); -template void valuedep() __attribute__((enable_if(N == not_constexpr(), ""))); - -template 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' requested here}} -} - -template 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 void test3() { - fn3(sizeof(T) == 1); // expected-error{{no matching function for call to 'fn3'}} expected-note@-2{{candidate disabled}} -} - -template -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 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 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 void test1() { - int &expr = T::expr(); - fn1(expr); - } - - int fn2(const Integer &) __attribute__((enable_if(false, ""))); // expected-note{{candidate disabled}} - template 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 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 ''}} expected-note@191{{candidate function}} expected-note@192{{candidate function}} - a = &ovlConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@191{{candidate function}} expected-note@192{{candidate function}} - } - - template - T templated(T m) __attribute__((enable_if(true, ""))) { return T(); } - template - T templated(T m) __attribute__((enable_if(false, ""))) { return T(); } - void test4() { - int (*p)(int) = templated; - int (*p2)(int) = &templated; - int (*a)(int); - a = templated; - a = &templated; - } - - template - T templatedBar(T m) __attribute__((enable_if(m > 0, ""))) { return T(); } - void test5() { - int (*p)(int) = templatedBar; // 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; // 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; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@214{{candidate function made ineligible by enable_if}} - a = &templatedBar; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@214{{candidate function made ineligible by enable_if}} - } - - template - T templatedConflict(T m) __attribute__((enable_if(false, ""))) { return T(); } - template - T templatedConflict(T m) __attribute__((enable_if(true, ""))) { return T(); } - template - T templatedConflict(T m) __attribute__((enable_if(1, ""))) { return T(); } - void test6() { - int (*p)(int) = templatedConflict; // 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; // 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; // expected-error{{assigning to 'int (*)(int)' from incompatible type ''}} expected-note@226{{candidate function}} expected-note@228{{candidate function}} - a = &templatedConflict; // expected-error{{assigning to 'int (*)(int)' from incompatible 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 ''}} 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 ''}} 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(foo); - auto AAmp = reinterpret_cast(&foo); - - using VoidFooTy = void (*)(void *); - auto B = reinterpret_cast(foo); - auto BAmp = reinterpret_cast(&foo); - - using IntFooTy = void (*)(int *); - auto C = reinterpret_cast(foo); - auto CAmp = reinterpret_cast(&foo); - - using CharFooTy = void (*)(void *); - auto D = reinterpret_cast(foo); - auto DAmp = reinterpret_cast(&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 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(foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}} - auto ARef = reinterpret_cast(&foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}} - auto AExplicit = reinterpret_cast(foo); - - using CharFooTy = void (*)(char *); - auto B = reinterpret_cast(foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}} - auto BRef = reinterpret_cast(&foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}} - auto BExplicit = reinterpret_cast(foo); -} - -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; - - using CharFooTy = void (*)(char *); - constexpr auto B = (CharFooTy)foo; - constexpr auto BRef = (CharFooTy)&foo; - constexpr auto BExplicit = (CharFooTy)foo; - - 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(foo); // expected-error{{reinterpret_cast cannot resolve overloaded function 'foo' to type}} - auto ARef = reinterpret_cast(&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 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 -constexpr int callNoError() { return noError(N); } -static_assert(callNoError<0>() == 0, ""); -static_assert(callNoError<1>() == 0, ""); - template 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 constexpr int callTemplated() { return templated(); } - 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 -struct Foo { - void bar(int a) __attribute__((enable_if(a, ""))); // expected-note{{disabled}} -}; - -void runFoo() { - Foo().bar(0); // expected-error{{no matching}} - Foo().bar(1); -} -} - -namespace instantiate_constexpr_in_enable_if { - template struct X { - static constexpr bool ok() { return true; } - void f() __attribute__((enable_if(ok(), ""))); - }; - void g() { X().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(foo); // expected-error{{cannot take address of function 'foo'}} - int baz = runFn(static_cast(foo)); // expected-error{{cannot take address of function 'foo'}} - } - - { - int (&bar)(int) = static_cast((foo)); // expected-error{{cannot take address of function 'foo'}} - int baz = runFn(static_cast((foo))); // expected-error{{cannot take address of function 'foo'}} - } -} -} - -namespace TypeOfFn { - template - struct is_same; - - template struct is_same { - 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: 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::data); (void)sizeof(array_lengthof(Description::data)); - sizeof(array_lengthof( // expected-error{{no matching function for call to 'array_lengthof'}} - Description::data // expected-note{{in instantiation of static data member 'PR7985::Description::data' requested here}} - )); + (void)sizeof(array_lengthof( // expected-error{{no matching function for call to 'array_lengthof'}} + Description::data // expected-note{{in instantiation of static data member 'PR7985::Description::data' requested here}} + )); array_lengthof(Description::data); // expected-error{{no matching function for call to 'array_lengthof'}} } 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;