sammccall updated this revision to Diff 199678.
sammccall added a comment.
Herald added a subscriber: arphaman.
This should work for real now: handle types properly, make tests pass, add some
tests.
Repository:
rC Clang
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D61722/new/
https://reviews.llvm.org/D61722
Files:
include/clang/AST/ASTContext.h
include/clang/AST/BuiltinTypes.def
include/clang/AST/Expr.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/AST/Stmt.h
include/clang/AST/TextNodeDumper.h
include/clang/AST/Type.h
include/clang/Basic/StmtNodes.td
include/clang/Serialization/ASTBitCodes.h
lib/AST/ASTContext.cpp
lib/AST/Expr.cpp
lib/AST/ExprClassification.cpp
lib/AST/ExprConstant.cpp
lib/AST/ItaniumMangle.cpp
lib/AST/MicrosoftMangle.cpp
lib/AST/NSAPI.cpp
lib/AST/Stmt.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/AST/TextNodeDumper.cpp
lib/AST/Type.cpp
lib/AST/TypeLoc.cpp
lib/CodeGen/CGDebugInfo.cpp
lib/CodeGen/CodeGenTypes.cpp
lib/CodeGen/ItaniumCXXABI.cpp
lib/Index/USRGeneration.cpp
lib/Sema/SemaCast.cpp
lib/Sema/SemaCoroutine.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExceptionSpec.cpp
lib/Sema/SemaExprMember.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaPseudoObject.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTCommon.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
test/CodeCompletion/member-access.cpp
test/Index/getcursor-recovery.cpp
test/SemaCXX/constructor-initializer.cpp
test/SemaCXX/enable_if.cpp
test/SemaTemplate/dependent-names.cpp
test/SemaTemplate/instantiate-function-params.cpp
test/SemaTemplate/instantiate-init.cpp
tools/libclang/CIndex.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: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -1516,6 +1516,7 @@
case BuiltinType::Void:
case BuiltinType::NullPtr:
case BuiltinType::Dependent:
+ case BuiltinType::Recovery:
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
case BuiltinType::Id:
#include "clang/Basic/OpenCLImageTypes.def"
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/SemaTemplate/instantiate-function-params.cpp
===================================================================
--- test/SemaTemplate/instantiate-function-params.cpp
+++ test/SemaTemplate/instantiate-function-params.cpp
@@ -3,7 +3,7 @@
// PR6619
template<bool C> struct if_c { };
template<typename T1> struct if_ {
- typedef if_c< static_cast<bool>(T1::value)> almost_type_; // expected-note 5{{in instantiation}}
+ typedef if_c< static_cast<bool>(T1::value)> type; // expected-note 5{{in instantiation}}
};
template <class Model, void (Model::*)()> struct wrap_constraints { };
template <class Model>
@@ -17,7 +17,9 @@
template <class ModelFn> struct requirement_;
template <void(*)()> struct instantiate {
};
-template <class Model> struct requirement_<void(*)(Model)> : if_< not_satisfied<Model> >::type { // expected-note 5{{in instantiation}}
+template <class Model>
+struct requirement_<void (*)(Model)> : if_<not_satisfied<Model>>::type { // expected-note 5{{in instantiation}}
+ static void failed();
};
template <class Model> struct usage_requirements {
};
Index: test/SemaTemplate/dependent-names.cpp
===================================================================
--- test/SemaTemplate/dependent-names.cpp
+++ test/SemaTemplate/dependent-names.cpp
@@ -176,7 +176,7 @@
void f(char&); // expected-note {{candidate function not viable}}
template<typename T> struct C {
- static const int n = f(T()); // expected-error {{no matching function}}
+ static const int n = f(T()); // expected-error {{no matching function}} expected-error {{variable of type 'const int' with an lvalue of type 'void'}}
};
}
Index: test/SemaCXX/enable_if.cpp
===================================================================
--- test/SemaCXX/enable_if.cpp
+++ test/SemaCXX/enable_if.cpp
@@ -406,16 +406,16 @@
static_assert(callNoError<1>() == 0, "");
template <int N> constexpr int templated() __attribute__((enable_if(N, ""))) {
- return 1;
+ return 1; //expected-note@-1 2 {{candidate disabled}}
}
-constexpr int A = templated<0>(); // expected-error{{no matching function for call to 'templated'}} expected-note@-4{{candidate disabled}}
+constexpr int A = templated<0>(); // expected-error{{no matching function for call to 'templated'}}
static_assert(templated<1>() == 1, "");
-template <int N> constexpr int callTemplated() { return templated<N>(); }
+template <int N> constexpr int callTemplated() { return templated<N>(); } // expected-error{{no matching function for call to 'templated'}} expected-note{{subexpression not valid}}
-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}}
+constexpr int B = 10 + // expected-error{{initialized by a constant expression}}
+ callTemplated<0>(); // expected-note{{in instantiation of function template}} expected-note{{in call to 'callTemplated()'}}
static_assert(callTemplated<1>() == 1, "");
}
Index: test/SemaCXX/constructor-initializer.cpp
===================================================================
--- test/SemaCXX/constructor-initializer.cpp
+++ test/SemaCXX/constructor-initializer.cpp
@@ -250,7 +250,7 @@
B(const String& s, int e=0) // expected-error {{unknown type name}}
: A(e), m_String(s) , m_ErrorStr(__null) {} // expected-error {{no matching constructor}} expected-error {{does not name}}
B(const B& e)
- : A(e), m_String(e.m_String), m_ErrorStr(__null) { // expected-error {{does not name}} \
+ : A(e), m_String(e.m_String), m_ErrorStr(__null) { // expected-error 2 {{does not name}} \
// expected-error {{no member named 'm_String' in 'test3::B'}}
}
};
Index: test/Index/getcursor-recovery.cpp
===================================================================
--- /dev/null
+++ test/Index/getcursor-recovery.cpp
@@ -0,0 +1,50 @@
+int foo(int, int);
+int foo(int, double);
+int x;
+
+void testTypedRecoveryExpr() {
+ // Inner foo() is a recoveryexpr of type int. Outer foo() is a regular call.
+ foo(x, foo(x));
+}
+// RUN: c-index-test -cursor-at=%s:7:3 %s | FileCheck -check-prefix=OUTER-FOO %s
+// OUTER-FOO: DeclRefExpr=foo:1:5
+// RUN: c-index-test -cursor-at=%s:7:7 %s | FileCheck -check-prefix=OUTER-X %s
+// OUTER-X: DeclRefExpr=x:3:5
+// RUN: c-index-test -cursor-at=%s:7:10 %s | FileCheck -check-prefix=INNER-FOO %s
+// INNER-FOO: OverloadedDeclRef=foo[2:5, 1:5]
+// RUN: c-index-test -cursor-at=%s:7:14 %s | FileCheck -check-prefix=INNER-X %s
+// INNER-X: DeclRefExpr=x:3:5
+
+
+
+
+int bar(int, int);
+int bar(int, double);
+int y;
+
+void testUntypedRecoveryExpr() {
+ // Inner bar() is a recoveryexpr of RecoveryTy. Outer is a dependent CallExpr.
+ bar(y, bar(y));
+}
+// RUN: c-index-test -cursor-at=%s:27:3 %s | FileCheck -check-prefix=OUTER-BAR %s
+// OUTER-BAR: DeclRefExpr=bar:21:5
+// RUN: c-index-test -cursor-at=%s:27:7 %s | FileCheck -check-prefix=OUTER-Y %s
+// OUTER-Y: DeclRefExpr=y:23:5
+// RUN: c-index-test -cursor-at=%s:27:10 %s | FileCheck -check-prefix=INNER-BAR %s
+// INNER-BAR: OverloadedDeclRef=bar[22:5, 21:5]
+// RUN: c-index-test -cursor-at=%s:27:14 %s | FileCheck -check-prefix=INNER-Y %s
+// INNER-Y: DeclRefExpr=y:23:5
+
+
+
+
+struct S{} s;
+int z;
+
+void testInvalidMember() {
+ s.mem(z);
+}
+// RUN: c-index-test -cursor-at=%s:45:3 %s | FileCheck -check-prefix=S %s
+// S: DeclRefExpr=s:41:12
+// RUN: c-index-test -cursor-at=%s:45:9 %s | FileCheck -check-prefix=Z %s
+// Z: DeclRefExpr=z:42:5
Index: test/CodeCompletion/member-access.cpp
===================================================================
--- test/CodeCompletion/member-access.cpp
+++ test/CodeCompletion/member-access.cpp
@@ -210,3 +210,14 @@
// CHECK-CC9: memfun2 (InBase) : [#void#][#Base3::#]memfun2(<#int#>) (requires fix-it: {181:4-181:5} to "->")
// CHECK-CC9: memfun3 : [#int#]memfun3(<#int#>) (requires fix-it: {181:4-181:5} to "->")
// CHECK-CC9: operator-> : [#Derived *#]operator->()[# const#]
+
+struct S { int MysteryMember; };
+S overloaded(int);
+S overloaded(double);
+void foo() {
+ // No overload matches, but we recover with the correct type.
+ overloaded().
+}
+// RUN: not %clang_cc1 -fsyntax-only -code-completion-at=%s:219:16 %s -o - | FileCheck -check-prefix=CHECK-CC10 %s
+// CHECK-CC10: [#int#]MysteryMember
+
Index: test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
===================================================================
--- test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
+++ test/CXX/temp/temp.decls/temp.variadic/fixed-expansion.cpp
@@ -124,6 +124,7 @@
template<typename T, typename U> using U = S<T, int, U>; // expected-note 2{{template parameter is declared here}}
template<typename...Ts> U<Ts...> &f(U<Ts...>, Ts...); // expected-error 2{{pack expansion used as argument for non-pack parameter of alias template}}
S<int, int, double> &s1 = f({}, 0, 0.0); // expected-error {{no matching function}}
+ // f() is invalid, so: expected-error@-1 {{cannot bind to a value of unrelated type 'int'}}
}
namespace PR18401 {
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
@@ -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/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -1827,6 +1827,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
//===----------------------------------------------------------------------===//
@@ -2533,6 +2547,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/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp
+++ lib/Serialization/ASTReader.cpp
@@ -6959,6 +6959,9 @@
case PREDEF_TYPE_OVERLOAD_ID:
T = Context.OverloadTy;
break;
+ case PREDEF_TYPE_RECOVERY_ID:
+ T = Context.RecoveryTy;
+ break;
case PREDEF_TYPE_BOUND_MEMBER:
T = Context.BoundMemberTy;
break;
Index: lib/Serialization/ASTCommon.cpp
===================================================================
--- lib/Serialization/ASTCommon.cpp
+++ lib/Serialization/ASTCommon.cpp
@@ -183,6 +183,9 @@
case BuiltinType::Overload:
ID = PREDEF_TYPE_OVERLOAD_ID;
break;
+ case BuiltinType::Recovery:
+ ID = PREDEF_TYPE_RECOVERY_ID;
+ break;
case BuiltinType::BoundMember:
ID = PREDEF_TYPE_BOUND_MEMBER;
break;
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -9378,6 +9378,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/SemaPseudoObject.cpp
===================================================================
--- lib/Sema/SemaPseudoObject.cpp
+++ lib/Sema/SemaPseudoObject.cpp
@@ -1484,7 +1484,7 @@
S.ActOnMemberAccessExpr(S.getCurScope(), InstanceBase, SourceLocation(),
RefExpr->isArrow() ? tok::arrow : tok::period, SS,
SourceLocation(), GetterName, nullptr);
- if (GetterExpr.isInvalid()) {
+ if (GetterExpr.isInvalid() || isa<RecoveryExpr>(GetterExpr.get())) {
S.Diag(RefExpr->getMemberLoc(),
diag::err_cannot_find_suitable_accessor) << 0 /* getter */
<< RefExpr->getPropertyDecl();
@@ -1513,7 +1513,7 @@
S.ActOnMemberAccessExpr(S.getCurScope(), InstanceBase, SourceLocation(),
RefExpr->isArrow() ? tok::arrow : tok::period, SS,
SourceLocation(), SetterName, nullptr);
- if (SetterExpr.isInvalid()) {
+ if (SetterExpr.isInvalid() || isa<RecoveryExpr>(SetterExpr.get())) {
S.Diag(RefExpr->getMemberLoc(),
diag::err_cannot_find_suitable_accessor) << 1 /* setter */
<< RefExpr->getPropertyDecl();
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"
@@ -12111,6 +12112,42 @@
return false;
}
+// Guess at what the return type for an unresolvable overload should be.
+static QualType chooseRecoveryType(OverloadCandidateSet &CS,
+ OverloadCandidateSet::iterator *Best) {
+ llvm::Optional<QualType> Result;
+ // Adjust Type after seeing a candidate.
+ auto ConsiderCandidate = [&](const OverloadCandidate &Candidate) {
+ if (!Candidate.Function)
+ return;
+ QualType T = Candidate.Function->getCallResultType();
+ if (T.isNull())
+ return;
+ if (!Result)
+ Result = T;
+ else if (Result != T)
+ Result = QualType();
+ };
+
+ // Look for an unambiguous type from a progressively larger subset.
+ // e.g. if types disagree, but all *viable* overloads return int, choose int.
+ //
+ // First, consider only the best candidate.
+ if (Best && *Best != CS.end())
+ ConsiderCandidate(**Best);
+ // Next, consider only viable candidates.
+ if (!Result)
+ for (const auto& C : CS)
+ if (C.Viable)
+ ConsiderCandidate(C);
+ // Finally, consider all candidates.
+ if (!Result)
+ for (const auto& C : CS)
+ ConsiderCandidate(C);
+
+ return Result.getValueOr(QualType());
+}
+
/// FinishOverloadedCallExpr - given an OverloadCandidateSet, builds and returns
/// the completed call expression. If overload resolution fails, emits
/// diagnostics and returns ExprError()
@@ -12201,6 +12238,17 @@
}
// Overload resolution failed.
+ if (!AllowTypoCorrection)
+ return ExprError();
+
+ // Build a RecoveryExpr so that arguments aren't orphaned in the AST.
+ // Also record the unresolved OverloadExpr, and the type (if unambiguous).
+ SmallVector<Stmt*, 8> SubExprs = {Fn};
+ SubExprs.append(Args.begin(), Args.end());
+ if (auto RE = RecoveryExpr::Create(
+ SemaRef.Context, chooseRecoveryType(*CandidateSet, Best),
+ Stmt::CallExprClass, Fn->getBeginLoc(), RParenLoc, SubExprs))
+ return *RE;
return ExprError();
}
Index: lib/Sema/SemaExprMember.cpp
===================================================================
--- lib/Sema/SemaExprMember.cpp
+++ lib/Sema/SemaExprMember.cpp
@@ -1022,6 +1022,23 @@
Diag(R.getNameLoc(), diag::err_no_member)
<< MemberName << DC
<< (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
+
+ SourceLocation BeginLoc;
+ if (BaseExpr)
+ BeginLoc = BaseExpr->getBeginLoc();
+ if (BeginLoc.isInvalid())
+ BeginLoc = TemplateKWLoc;
+ if (BeginLoc.isInvalid())
+ BeginLoc = SS.getBeginLoc();
+ if (BeginLoc.isInvalid())
+ BeginLoc = MemberNameInfo.getBeginLoc();
+ llvm::SmallVector<Stmt*, 1> SubExprs;
+ if (BaseExpr)
+ SubExprs.push_back(BaseExpr);
+ if (auto RE = RecoveryExpr::Create(Context, QualType(),
+ Stmt::MemberExprClass, BeginLoc,
+ MemberNameInfo.getEndLoc(), SubExprs))
+ return *RE;
return ExprError();
}
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/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp
+++ lib/Sema/SemaDeclCXX.cpp
@@ -1169,7 +1169,8 @@
Expr *Arg = E.get();
E = S.BuildCallExpr(nullptr, Get, Loc, Arg, Loc);
}
- if (E.isInvalid())
+ // Don't allow recovery of get() calls for now, this is a can of worms.
+ if (E.isInvalid() || isa<RecoveryExpr>(E.get()))
return true;
Expr *Init = E.get();
Index: lib/Sema/SemaCoroutine.cpp
===================================================================
--- lib/Sema/SemaCoroutine.cpp
+++ lib/Sema/SemaCoroutine.cpp
@@ -373,6 +373,8 @@
<< Base->getSourceRange();
return ExprError();
}
+ if (isa<RecoveryExpr>(Result.get()))
+ return ExprError();
return S.BuildCallExpr(nullptr, Result.get(), Loc, Args, Loc, nullptr);
}
Index: lib/Sema/SemaCast.cpp
===================================================================
--- lib/Sema/SemaCast.cpp
+++ lib/Sema/SemaCast.cpp
@@ -13,6 +13,8 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/OperationKinds.h"
+#include "clang/Sema/Ownership.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
Index: lib/Index/USRGeneration.cpp
===================================================================
--- lib/Index/USRGeneration.cpp
+++ lib/Index/USRGeneration.cpp
@@ -713,6 +713,7 @@
#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Dependent:
+ case BuiltinType::Recovery:
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
case BuiltinType::Id:
#include "clang/Basic/OpenCLImageTypes.def"
Index: lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -2869,6 +2869,7 @@
return false;
case BuiltinType::Dependent:
+ case BuiltinType::Recovery:
#define BUILTIN_TYPE(Id, SingletonId)
#define PLACEHOLDER_TYPE(Id, SingletonId) \
case BuiltinType::Id:
Index: lib/CodeGen/CodeGenTypes.cpp
===================================================================
--- lib/CodeGen/CodeGenTypes.cpp
+++ lib/CodeGen/CodeGenTypes.cpp
@@ -513,6 +513,7 @@
break;
case BuiltinType::Dependent:
+ case BuiltinType::Recovery:
#define BUILTIN_TYPE(Id, SingletonId)
#define PLACEHOLDER_TYPE(Id, SingletonId) \
case BuiltinType::Id:
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp
+++ lib/CodeGen/CGDebugInfo.cpp
@@ -630,6 +630,7 @@
#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Dependent:
+ case BuiltinType::Recovery:
llvm_unreachable("Unexpected builtin type");
case BuiltinType::NullPtr:
return DBuilder.createNullPtrType();
Index: lib/AST/TypeLoc.cpp
===================================================================
--- lib/AST/TypeLoc.cpp
+++ lib/AST/TypeLoc.cpp
@@ -372,6 +372,7 @@
case BuiltinType::NullPtr:
case BuiltinType::Overload:
+ case BuiltinType::Recovery:
case BuiltinType::Dependent:
case BuiltinType::BoundMember:
case BuiltinType::UnknownAny:
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -2843,6 +2843,8 @@
return "nullptr_t";
case Overload:
return "<overloaded function type>";
+ case Recovery:
+ return "<recovery type>";
case BoundMember:
return "<bound member function type>";
case PseudoObject:
@@ -3860,6 +3862,7 @@
// Dependent types that could instantiate to a pointer type.
case BuiltinType::Dependent:
case BuiltinType::Overload:
+ case BuiltinType::Recovery:
case BuiltinType::BoundMember:
case BuiltinType::PseudoObject:
case BuiltinType::UnknownAny:
Index: lib/AST/TextNodeDumper.cpp
===================================================================
--- lib/AST/TextNodeDumper.cpp
+++ lib/AST/TextNodeDumper.cpp
@@ -717,6 +717,10 @@
}
}
+void TextNodeDumper::VisitRecoveryExpr(const RecoveryExpr *Node) {
+ OS << " " << Stmt::getStmtClassName(Node->attemptedStmtClass());
+}
+
void TextNodeDumper::VisitUnresolvedLookupExpr(
const UnresolvedLookupExpr *Node) {
OS << " (";
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,20 @@
llvm_unreachable("Cannot print TypoExpr nodes");
}
+void StmtPrinter::VisitRecoveryExpr(RecoveryExpr *Node) {
+ OS << "<bad " << Stmt::getStmtClassName(Node->attemptedStmtClass()) << ">(";
+ const char *Sep = "";
+ for (Stmt *S : Node->children()) {
+ OS << Sep;
+ if (Expr *E = dyn_cast<Expr>(S))
+ PrintExpr(E);
+ else
+ PrintStmt(S);
+ Sep = ", ";
+ }
+ 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/NSAPI.cpp
===================================================================
--- lib/AST/NSAPI.cpp
+++ lib/AST/NSAPI.cpp
@@ -485,6 +485,7 @@
case BuiltinType::BoundMember:
case BuiltinType::Dependent:
case BuiltinType::Overload:
+ case BuiltinType::Recovery:
case BuiltinType::UnknownAny:
case BuiltinType::ARCUnbridgedCast:
case BuiltinType::Half:
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -2013,6 +2013,7 @@
case BuiltinType::Id:
#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Dependent:
+ case BuiltinType::Recovery:
llvm_unreachable("placeholder types shouldn't get to name mangling");
case BuiltinType::ObjCId:
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -2626,6 +2626,7 @@
case BuiltinType::Id:
#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Dependent:
+ case BuiltinType::Recovery:
if (!NullOut)
llvm_unreachable("mangling a placeholder type");
break;
@@ -3590,6 +3591,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
@@ -8081,6 +8081,7 @@
return GCCTypeClass::None;
case BuiltinType::Dependent:
+ case BuiltinType::Recovery:
llvm_unreachable("unexpected dependent type");
};
llvm_unreachable("unexpected placeholder type");
@@ -11698,6 +11699,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
@@ -132,6 +132,7 @@
case Expr::DependentCoawaitExprClass:
case Expr::CXXDependentScopeMemberExprClass:
case Expr::DependentScopeDeclRefExprClass:
+ case Expr::RecoveryExprClass:
// ObjC instance variables are lvalues
// FIXME: ObjC++0x might have different rules
case Expr::ObjCIvarRefExprClass:
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -2339,6 +2339,7 @@
// If we don't know precisely what we're looking at, let's not warn.
case UnresolvedLookupExprClass:
case CXXUnresolvedConstructExprClass:
+ case RecoveryExprClass:
return false;
case CXXTemporaryObjectExprClass:
@@ -3124,6 +3125,8 @@
case TypoExprClass:
case CXXFoldExprClass:
llvm_unreachable("shouldn't see dependent / unresolved nodes here");
+ case RecoveryExprClass:
+ return IncludePossibleEffects;
case DeclRefExprClass:
case ObjCIvarRefExprClass:
@@ -4317,3 +4320,41 @@
}
return OriginalTy;
}
+
+RecoveryExpr::RecoveryExpr(QualType T, StmtClass Attempted,
+ SourceLocation BeginLoc, SourceLocation EndLoc,
+ ArrayRef<Stmt *> Stmts)
+ : Expr(RecoveryExprClass, T, VK_LValue, OK_Ordinary, T->isDependentType(),
+ /*isValueDependent=*/true,
+ /*isInstantiationDependent=*/true,
+ /*containsUnexpandedParameterPack*/ false),
+ BeginLoc(BeginLoc), EndLoc(EndLoc), Attempted(Attempted),
+ NumStmts(Stmts.size()) {
+ std::copy(Stmts.begin(), Stmts.end(), getTrailingObjects<Stmt *>());
+}
+
+Optional<RecoveryExpr *> RecoveryExpr::Create(ASTContext &Ctx, QualType T,
+ StmtClass Attempted,
+ SourceLocation BeginLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Stmt *> Stmts) {
+ // FIXME: In some contexts recovery is not desired (e.g. synthesized member
+ // accesses for coroutines). Currently the caller checks for RecoveryExpr and
+ // discards it, it would be cleaner/safer to have a flag on Sema and never
+ // call Create(). The current cases where we return None could be moved there.
+
+ if (T.isNull()) {
+ if (!Ctx.getLangOpts().CPlusPlus)
+ return None; // We have no type, and can't use a dependent type.
+ T = Ctx.RecoveryTy;
+ }
+ void *Mem = Ctx.Allocate(totalSizeToAlloc<Stmt *>(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<Stmt *>(NumStmts), alignof(CallExpr));
+ return new (Mem) RecoveryExpr(EmptyShell());
+}
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -1247,6 +1247,9 @@
// expressions.
InitBuiltinType(DependentTy, BuiltinType::Dependent);
+ // Placeholder type for broken/invalid expressions of unknown type.
+ InitBuiltinType(RecoveryTy, BuiltinType::Recovery);
+
// Placeholder type for functions.
InitBuiltinType(OverloadTy, BuiltinType::Overload);
@@ -6610,6 +6613,7 @@
case BuiltinType::OCLReserveID:
case BuiltinType::OCLSampler:
case BuiltinType::Dependent:
+ case BuiltinType::Recovery:
#define BUILTIN_TYPE(KIND, ID)
#define PLACEHOLDER_TYPE(KIND, ID) \
case BuiltinType::KIND:
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -1010,6 +1010,9 @@
/// \brief The '_Sat unsigned long _Fract' type
PREDEF_TYPE_SAT_ULONG_FRACT_ID = 69,
+ /// The type for broken/invalid expressions of unknown type.
+ PREDEF_TYPE_RECOVERY_ID = 70,
+
/// OpenCL image types with auto numeration
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
PREDEF_TYPE_##Id##_ID,
@@ -1750,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/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -2419,8 +2419,9 @@
friend class ASTContext; // ASTContext creates these.
BuiltinType(Kind K)
- : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent),
- /*InstantiationDependent=*/(K == Dependent),
+ : Type(Builtin, QualType(),
+ /*Dependent=*/(K == Dependent || K == Recovery),
+ /*InstantiationDependent=*/(K == Dependent || K == Recovery),
/*VariablyModified=*/false,
/*Unexpanded parameter pack=*/false) {
BuiltinTypeBits.Kind = K;
Index: include/clang/AST/TextNodeDumper.h
===================================================================
--- include/clang/AST/TextNodeDumper.h
+++ include/clang/AST/TextNodeDumper.h
@@ -259,6 +259,7 @@
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node);
void VisitExprWithCleanups(const ExprWithCleanups *Node);
void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
+ void VisitRecoveryExpr(const RecoveryExpr *Node);
void VisitSizeOfPackExpr(const SizeOfPackExpr *Node);
void
VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *Node);
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, {})
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,64 @@
}
};
+
+/// RecoveryExpr - a broken expression that we couldn't construct an AST for,
+/// e.g. because overload resolution failed.
+/// We capture:
+/// - the kind of expression that would have been produced
+/// - the valid subexpressions
+/// - the type, if known. If unknown, it is the built-in RecoveryTy, which
+/// is dependent (and so generally suppresses further diagnostics etc).
+class RecoveryExpr final : public Expr,
+ private llvm::TrailingObjects<RecoveryExpr, Stmt *> {
+public:
+ // T may be null, in which case RecoveryTy is used.
+ // Returns None if recovery is not valid here, e.g. because dependent types
+ // are required but not supported.
+ static Optional<RecoveryExpr *> Create(ASTContext &Ctx, QualType T,
+ StmtClass Attempted,
+ SourceLocation BeginLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Stmt *> Stmts);
+ static RecoveryExpr *CreateEmpty(ASTContext &Ctx, unsigned NumStmts);
+
+ /// The expression type that would have been produced, if not for errors
+ /// in the code.
+ 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);
+ RecoveryExpr(EmptyShell Empty) : Expr(RecoveryExprClass, Empty) {}
+
+ 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
Index: include/clang/AST/BuiltinTypes.def
===================================================================
--- include/clang/AST/BuiltinTypes.def
+++ include/clang/AST/BuiltinTypes.def
@@ -257,6 +257,13 @@
// theoretically deducible.
BUILTIN_TYPE(Dependent, DependentTy)
+// The type of a broken expression whose type isn't clear. e.g. 'foo()', where
+// foo's overloads require arguments and have different return types.
+// This type is considered dependent, even though it will never be deduced: the
+// concrete type is determined by correcting the source code, not instantiating
+// a template.
+BUILTIN_TYPE(Recovery, RecoveryTy)
+
// The type of an unresolved overload set. A placeholder type.
// Expressions with this type have one of the following basic
// forms, with parentheses generally permitted:
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -1031,7 +1031,7 @@
CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
CanQualType Float128ComplexTy;
CanQualType VoidPtrTy, NullPtrTy;
- CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
+ CanQualType DependentTy, RecoveryTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
CanQualType BuiltinFnTy;
CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits