hokein created this revision. Herald added subscribers: cfe-commits, arphaman. Herald added a project: clang.
RecoveryExprs was modeled as dependent type to prevent bogus diagnostics and crashes in clang. This patch allows to preseve the type for broken calls when the RecoveryEprs have a known type, e.g. a broken non-overloaded call, a overloaded call when the all candidates have the same return type, so that more features (code completion still work on "take2args(x).^") will still work. However, adding the type is ricky, which may result in more clang code being affected leading to new crashes and hurt diagnostic, and it requires large effort to minimize the affect (update all sites in clang to handle errorDepend case), so we add a new flag (off by default) to allow us to develop/test them incrementally. Tested: - all existing tests are passed (when both "-frecovery-ast", "-frecovery-ast-type" flags are flipped on); Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D79160 Files: clang/include/clang/AST/Expr.h clang/include/clang/Basic/LangOptions.def clang/include/clang/Driver/CC1Options.td clang/include/clang/Sema/Sema.h clang/lib/AST/ComputeDependence.cpp clang/lib/AST/Expr.cpp clang/lib/Frontend/CompilerInvocation.cpp clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaOverload.cpp clang/test/AST/ast-dump-recovery.cpp clang/test/CodeCompletion/member-access.cpp clang/test/Index/getcursor-recovery.cpp clang/test/SemaCXX/enable_if.cpp clang/test/SemaCXX/recovery-expr-type.cpp clang/test/SemaTemplate/instantiate-function-params.cpp
Index: clang/test/SemaTemplate/instantiate-function-params.cpp =================================================================== --- clang/test/SemaTemplate/instantiate-function-params.cpp +++ clang/test/SemaTemplate/instantiate-function-params.cpp @@ -3,32 +3,32 @@ // 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)> almost_type_; // expected-note 7{{in instantiation}} }; template <class Model, void (Model::*)()> struct wrap_constraints { }; template <class Model> inline char has_constraints_(Model* , // expected-note 3{{candidate template ignored}} - wrap_constraints<Model,&Model::constraints>* = 0); // expected-note 2{{in instantiation}} + wrap_constraints<Model,&Model::constraints>* = 0); // expected-note 4{{in instantiation}} template <class Model> struct not_satisfied { static const bool value = sizeof( has_constraints_((Model*)0) == 1); // expected-error 3{{no matching function}} \ - // expected-note 2{{while substituting deduced template arguments into function template 'has_constraints_' [with }} + // expected-note 4{{while substituting deduced template arguments into function template 'has_constraints_' [with }} }; 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-error 3{{no type named 'type' in}} expected-note 7{{in instantiation}} }; template <class Model> struct usage_requirements { }; template < typename TT > struct InputIterator { - typedef instantiate< & requirement_<void(*)(usage_requirements<InputIterator> x)>::failed> boost_concept_check1; // expected-note {{in instantiation}} + typedef instantiate< & requirement_<void(*)(usage_requirements<InputIterator> x)>::failed> boost_concept_check1; // expected-note 2{{in instantiation}} }; -template < typename TT > struct ForwardIterator : InputIterator<TT> { // expected-note {{in instantiation}} - typedef instantiate< & requirement_<void(*)(usage_requirements<ForwardIterator> x)>::failed> boost_concept_check2; // expected-note {{in instantiation}} +template < typename TT > struct ForwardIterator : InputIterator<TT> { // expected-note 2{{in instantiation}} + typedef instantiate< & requirement_<void(*)(usage_requirements<ForwardIterator> x)>::failed> boost_concept_check2; // expected-note 2{{in instantiation}} }; -typedef instantiate< &requirement_<void(*)(ForwardIterator<char*> x)>::failed> boost_concept_checkX;// expected-note 3{{in instantiation}} +typedef instantiate< &requirement_<void(*)(ForwardIterator<char*> x)>::failed> boost_concept_checkX;// expected-note 6{{in instantiation}} template<typename T> struct X0 { }; template<typename R, typename A1> struct X0<R(A1 param)> { }; Index: clang/test/SemaCXX/recovery-expr-type.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/recovery-expr-type.cpp @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -frecovery-ast -frecovery-ast-type -o - %s -fsyntax-only -verify + +namespace test0 { +struct Indestructible { + // Indestructible(); + ~Indestructible() = delete; // expected-note {{deleted}} +}; +Indestructible make_indestructible(); + +void test() { + // no crash. + int s = sizeof(make_indestructible()); // expected-error {{deleted}} +} +} + +namespace test1 { +constexpr int foo() { return 1;} // expected-note {{candidate function not viable}} +// verify the "not an integral constant expression" diagnostic is suppressed. +static_assert(1 == foo(1), ""); // expected-error {{no matching function}} +} + +namespace test2 { +void foo(); // expected-note 3{{requires 0 arguments}} +void func() { + // verify that "field has incomplete type" diagnostic is suppressed. + typeof(foo(42)) var; // expected-error {{no matching function}} + + // FIXME: suppress the "cannot initialize a variable" diagnostic. + int a = foo(1); // expected-error {{no matching function}} \ + // expected-error {{cannot initialize a variable of type}} + + // FIXME: suppress the "invalid application" diagnostic. + int s = sizeof(foo(42)); // expected-error {{no matching function}} expected-error {{invalid application of 'sizeof'}} +}; +} + +namespace test3 { +template <int N> constexpr int templated() __attribute__((enable_if(N, ""))) { // expected-note {{candidate disabled}} + return 1; +} +// verify that "constexpr variable must be initialized" diagnostic is suppressed. +constexpr int A = templated<0>(); // expected-error{{no matching function}} + +template <typename T> +struct AA { + template <typename U> + static constexpr int getB() { // expected-note{{candidate template ignored}} + return 2; + } + static constexpr int foo2() { + return AA<T>::getB(); // expected-error{{no matching function for call to 'getB'}} expected-note {{subexpression not valid in a constant expression}} + } +}; +// FIXME: should we suppress the "be initialized by a constant expression" diagnostic? +constexpr auto x2 = AA<int>::foo2(); // expected-error {{be initialized by a constant expression}} expected-note{{in instantiation of member function}} expected-note {{in call to}} +} Index: clang/test/SemaCXX/enable_if.cpp =================================================================== --- clang/test/SemaCXX/enable_if.cpp +++ clang/test/SemaCXX/enable_if.cpp @@ -414,8 +414,8 @@ 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}} +constexpr int B = 10 + // expected-error {{initialized by a constant expression}} + callTemplated<0>(); // expected-error@-3{{no matching function for call to 'templated'}} expected-note{{in instantiation of function template}} expected-note@-10{{candidate disabled}} expected-note {{in call to 'callTemplated()'}} expected-note@-3 {{subexpression not valid in a constant expression}} static_assert(callTemplated<1>() == 1, ""); } Index: clang/test/Index/getcursor-recovery.cpp =================================================================== --- clang/test/Index/getcursor-recovery.cpp +++ clang/test/Index/getcursor-recovery.cpp @@ -2,15 +2,24 @@ int foo(int, double); int x; -void testTypedRecoveryExpr() { - // Inner foo() is a RecoveryExpr, outer foo() is an overloaded call. - foo(x, foo(x)); +void testTypedRecoveryExpr1() { + // Inner bar() is a RecoveryExpr, outer foo() is an overloaded call. + foo(x, bar(x)); } -// RUN: c-index-test -cursor-at=%s:7:3 %s -Xclang -frecovery-ast | FileCheck -check-prefix=OUTER-FOO %s +// RUN: c-index-test -cursor-at=%s:7:3 %s -Xclang -frecovery-ast -Xclang -frecovery-ast-type | FileCheck -check-prefix=OUTER-FOO %s // OUTER-FOO: OverloadedDeclRef=foo[2:5, 1:5] -// RUN: c-index-test -cursor-at=%s:7:7 %s -Xclang -frecovery-ast | FileCheck -check-prefix=OUTER-X %s +// RUN: c-index-test -cursor-at=%s:7:7 %s -Xclang -frecovery-ast -Xclang -frecovery-ast-type | FileCheck -check-prefix=OUTER-X %s // OUTER-X: DeclRefExpr=x:3:5 -// RUN: c-index-test -cursor-at=%s:7:10 %s -Xclang -frecovery-ast | FileCheck -check-prefix=INNER-FOO %s -// INNER-FOO: OverloadedDeclRef=foo[2:5, 1:5] -// RUN: c-index-test -cursor-at=%s:7:14 %s -Xclang -frecovery-ast | FileCheck -check-prefix=INNER-X %s +// RUN: c-index-test -cursor-at=%s:7:10 %s -Xclang -frecovery-ast -Xclang -frecovery-ast-type | FileCheck -check-prefix=INNER-FOO %s +// INNER-FOO: OverloadedDeclRef=bar +// RUN: c-index-test -cursor-at=%s:7:14 %s -Xclang -frecovery-ast -Xclang -frecovery-ast-type | FileCheck -check-prefix=INNER-X %s // INNER-X: DeclRefExpr=x:3:5 + +void testTypedRecoveryExpr2() { + // Inner foo() is a RecoveryExpr (with int type), outer foo() is a "foo(int, int)" call. + foo(x, foo(x)); +} +// RUN: c-index-test -cursor-at=%s:20:3 %s -Xclang -frecovery-ast -Xclang -frecovery-ast-type | FileCheck -check-prefix=TEST2-OUTER %s +// TEST2-OUTER: DeclRefExpr=foo:1:5 +// RUN: c-index-test -cursor-at=%s:20:10 %s -Xclang -frecovery-ast -Xclang -frecovery-ast-type | FileCheck -check-prefix=TEST2-INNER %s +// TEST2-INNER: OverloadedDeclRef=foo[2:5, 1:5] Index: clang/test/CodeCompletion/member-access.cpp =================================================================== --- clang/test/CodeCompletion/member-access.cpp +++ clang/test/CodeCompletion/member-access.cpp @@ -273,3 +273,12 @@ // RUN: --implicit-check-not="[#char#]operator=(" // CHECK-OPER: [#int#]operator=( +struct S { int member; }; +S overloaded(int); +S overloaded(double); +void foo() { + // No overload matches, but we have recovery-expr with the correct type. + overloaded(). +} +// RUN: not %clang_cc1 -fsyntax-only -frecovery-ast -frecovery-ast-type -code-completion-at=%s:281:16 %s -o - | FileCheck -check-prefix=CHECK-CC10 %s +// CHECK-CC10: [#int#]member \ No newline at end of file Index: clang/test/AST/ast-dump-recovery.cpp =================================================================== --- clang/test/AST/ast-dump-recovery.cpp +++ clang/test/AST/ast-dump-recovery.cpp @@ -1,12 +1,13 @@ -// RUN: not %clang_cc1 -triple x86_64-unknown-unknown -Wno-unused-value -fcxx-exceptions -std=gnu++17 -frecovery-ast -ast-dump %s | FileCheck -strict-whitespace %s +// RUN: not %clang_cc1 -triple x86_64-unknown-unknown -Wno-unused-value -fcxx-exceptions -std=gnu++17 -frecovery-ast -frecovery-ast-type -ast-dump %s | FileCheck -strict-whitespace %s // RUN: not %clang_cc1 -triple x86_64-unknown-unknown -Wno-unused-value -fcxx-exceptions -std=gnu++17 -fno-recovery-ast -ast-dump %s | FileCheck --check-prefix=DISABLED -strict-whitespace %s int some_func(int *); // CHECK: VarDecl {{.*}} invalid_call -// CHECK-NEXT:`-RecoveryExpr {{.*}} contains-errors -// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func' -// CHECK-NEXT: `-IntegerLiteral {{.*}} 123 +// CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'int' contains-errors +// CHECK-NEXT: `-RecoveryExpr {{.*}} 'int' contains-errors +// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'some_func' +// CHECK-NEXT: `-IntegerLiteral {{.*}} 123 // DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors int invalid_call = some_func(123); @@ -14,14 +15,15 @@ int ambig_func(float); // CHECK: VarDecl {{.*}} ambig_call -// CHECK-NEXT:`-RecoveryExpr {{.*}} contains-errors -// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'ambig_func' -// CHECK-NEXT: `-IntegerLiteral {{.*}} 123 +// CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'int' contains-errors +// CHECK-NEXT: `-RecoveryExpr {{.*}} 'int' contains-errors +// CHECK-NEXT: |-UnresolvedLookupExpr {{.*}} 'ambig_func' +// CHECK-NEXT: `-IntegerLiteral {{.*}} 123 // DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors int ambig_call = ambig_func(123); // CHECK: VarDecl {{.*}} unresolved_call1 -// CHECK-NEXT:`-RecoveryExpr {{.*}} contains-errors +// CHECK-NEXT:`-RecoveryExpr {{.*}} '<dependent type>' contains-errors // CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'bar' // DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors int unresolved_call1 = bar(); Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -12776,6 +12776,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() @@ -12865,8 +12901,11 @@ } } - // Overload resolution failed. - return ExprError(); + // Overload resolution failed, try to recovery. + SmallVector<Expr *, 8> SubExprs = {Fn}; + SubExprs.append(Args.begin(), Args.end()); + return SemaRef.CreateRecoveryExpr(Fn->getBeginLoc(), RParenLoc, SubExprs, + chooseRecoveryType(*CandidateSet, Best)); } static void markUnaddressableCandidatesUnviable(Sema &S, Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -18945,7 +18945,7 @@ } ExprResult Sema::CreateRecoveryExpr(SourceLocation Begin, SourceLocation End, - ArrayRef<Expr *> SubExprs) { + ArrayRef<Expr *> SubExprs, QualType T) { // FIXME: enable it for C++, RecoveryExpr is type-dependent to suppress // bogus diagnostics and this trick does not work in C. // FIXME: use containsErrors() to suppress unwanted diags in C. @@ -18955,5 +18955,8 @@ if (isSFINAEContext()) return ExprError(); - return RecoveryExpr::Create(Context, Begin, End, SubExprs); + if (T.isNull() || !Context.getLangOpts().RecoveryASTType) + // We don't know the concrete type, fallback to dependent type. + T = Context.DependentTy; + return RecoveryExpr::Create(Context, T, Begin, End, SubExprs); } Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -15884,7 +15884,7 @@ bool Failed) { assert(AssertExpr != nullptr && "Expected non-null condition"); if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent() && - !Failed) { + !AssertExpr->containsErrors() && !Failed) { // In a static_assert-declaration, the constant-expression shall be a // constant expression that can be contextually converted to bool. ExprResult Converted = PerformContextuallyConvertToBool(AssertExpr); Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -12804,7 +12804,7 @@ bool IsGlobal = GlobalStorage && !var->isStaticLocal(); QualType baseType = Context.getBaseElementType(type); - if (Init && !Init->isValueDependent()) { + if (Init && !Init->isValueDependent() && !Init->containsErrors()) { if (var->isConstexpr()) { SmallVector<PartialDiagnosticAt, 8> Notes; if (!var->evaluateValue(Notes) || !var->isInitICE()) { @@ -16424,7 +16424,7 @@ } QualType EltTy = Context.getBaseElementType(T); - if (!EltTy->isDependentType()) { + if (!EltTy->isDependentType() && !EltTy->containsErrors()) { if (RequireCompleteSizedType(Loc, EltTy, diag::err_field_incomplete_or_sizeless)) { // Fields of incomplete type force their record to be invalid. Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -2891,6 +2891,8 @@ Diags.Report(diag::warn_fe_concepts_ts_flag); Opts.RecoveryAST = Args.hasFlag(OPT_frecovery_ast, OPT_fno_recovery_ast, Opts.CPlusPlus); + Opts.RecoveryASTType = + Args.hasFlag(OPT_frecovery_ast_type, OPT_fno_recovery_ast_type, false); Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions); Opts.AccessControl = !Args.hasArg(OPT_fno_access_control); Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); Index: clang/lib/AST/Expr.cpp =================================================================== --- clang/lib/AST/Expr.cpp +++ clang/lib/AST/Expr.cpp @@ -3306,7 +3306,7 @@ if (!IncludePossibleEffects && getExprLoc().isMacroID()) return false; - if (isInstantiationDependent()) + if (isInstantiationDependent() || containsErrors()) return IncludePossibleEffects; switch (getStmtClass()) { @@ -4648,11 +4648,12 @@ return OriginalTy; } -RecoveryExpr::RecoveryExpr(ASTContext &Ctx, SourceLocation BeginLoc, +RecoveryExpr::RecoveryExpr(ASTContext &Ctx, QualType T, SourceLocation BeginLoc, SourceLocation EndLoc, ArrayRef<Expr *> SubExprs) - : Expr(RecoveryExprClass, Ctx.DependentTy, VK_LValue, OK_Ordinary), - BeginLoc(BeginLoc), EndLoc(EndLoc), NumExprs(SubExprs.size()) { + : Expr(RecoveryExprClass, T, VK_LValue, OK_Ordinary), BeginLoc(BeginLoc), + EndLoc(EndLoc), NumExprs(SubExprs.size()) { #ifndef NDEBUG + assert(!T.isNull()); for (auto *E : SubExprs) assert(E != nullptr); #endif @@ -4661,12 +4662,13 @@ setDependence(computeDependence(this)); } -RecoveryExpr *RecoveryExpr::Create(ASTContext &Ctx, SourceLocation BeginLoc, +RecoveryExpr *RecoveryExpr::Create(ASTContext &Ctx, QualType T, + SourceLocation BeginLoc, SourceLocation EndLoc, ArrayRef<Expr *> SubExprs) { void *Mem = Ctx.Allocate(totalSizeToAlloc<Expr *>(SubExprs.size()), alignof(RecoveryExpr)); - return new (Mem) RecoveryExpr(Ctx, BeginLoc, EndLoc, SubExprs); + return new (Mem) RecoveryExpr(Ctx, T, BeginLoc, EndLoc, SubExprs); } RecoveryExpr *RecoveryExpr::CreateEmpty(ASTContext &Ctx, unsigned NumSubExprs) { Index: clang/lib/AST/ComputeDependence.cpp =================================================================== --- clang/lib/AST/ComputeDependence.cpp +++ clang/lib/AST/ComputeDependence.cpp @@ -487,7 +487,8 @@ ExprDependence clang::computeDependence(RecoveryExpr *E) { // FIXME: drop type+value+instantiation once Error is sufficient to suppress // bogus dianostics. - auto D = ExprDependence::TypeValueInstantiation | ExprDependence::Error; + auto D = + toExprDependence(E->getType()->getDependence()) | ExprDependence::Error; for (auto *S : E->subExpressions()) D |= S->getDependence(); return D; Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -3887,7 +3887,8 @@ /// Attempts to produce a RecoveryExpr after some AST node cannot be created. ExprResult CreateRecoveryExpr(SourceLocation Begin, SourceLocation End, - ArrayRef<Expr *> SubExprs); + ArrayRef<Expr *> SubExprs, + QualType T = QualType()); ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, SourceLocation IdLoc, Index: clang/include/clang/Driver/CC1Options.td =================================================================== --- clang/include/clang/Driver/CC1Options.td +++ clang/include/clang/Driver/CC1Options.td @@ -569,6 +569,10 @@ HelpText<"Preserve expressions in AST rather than dropping them when " "encountering semantic errors">; def fno_recovery_ast : Flag<["-"], "fno-recovery-ast">; +def frecovery_ast_type : Flag<["-"], "frecovery-ast-type">, + HelpText<"Preserve the type for recovery expressions when possible " + "(experimental) ">; +def fno_recovery_ast_type : Flag<["-"], "fno-recovery-ast-type">; let Group = Action_Group in { Index: clang/include/clang/Basic/LangOptions.def =================================================================== --- clang/include/clang/Basic/LangOptions.def +++ clang/include/clang/Basic/LangOptions.def @@ -149,6 +149,7 @@ LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes") COMPATIBLE_LANGOPT(RecoveryAST, 1, CPlusPlus, "Preserve expressions in AST when encountering errors") +COMPATIBLE_LANGOPT(RecoveryASTType, 1, 0, "Preserve the type in recovery expressions") BENIGN_LANGOPT(ThreadsafeStatics , 1, 1, "thread-safe static initializers") LANGOPT(POSIXThreads , 1, 0, "POSIX thread support") Index: clang/include/clang/AST/Expr.h =================================================================== --- clang/include/clang/AST/Expr.h +++ clang/include/clang/AST/Expr.h @@ -6052,8 +6052,9 @@ class RecoveryExpr final : public Expr, private llvm::TrailingObjects<RecoveryExpr, Expr *> { public: - static RecoveryExpr *Create(ASTContext &Ctx, SourceLocation BeginLoc, - SourceLocation EndLoc, ArrayRef<Expr *> SubExprs); + static RecoveryExpr *Create(ASTContext &Ctx, QualType T, + SourceLocation BeginLoc, SourceLocation EndLoc, + ArrayRef<Expr *> SubExprs); static RecoveryExpr *CreateEmpty(ASTContext &Ctx, unsigned NumSubExprs); ArrayRef<Expr *> subExpressions() { @@ -6078,8 +6079,8 @@ } private: - RecoveryExpr(ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc, - ArrayRef<Expr *> SubExprs); + RecoveryExpr(ASTContext &Ctx, QualType T, SourceLocation BeginLoc, + SourceLocation EndLoc, ArrayRef<Expr *> SubExprs); RecoveryExpr(EmptyShell Empty, unsigned NumSubExprs) : Expr(RecoveryExprClass, Empty), NumExprs(NumSubExprs) {}
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits