From 590e14653252faa97c2a32ba38aeef05ec681f9b Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 7 Dec 2020 18:41:43 -0800 Subject: [PATCH] Fix assertion failure due to incorrect dependence bits on a DeclRefExpr that can only be set correctly after instantiating the initializer for a variable. --- clang/include/clang/AST/Expr.h | 4 ++-- clang/lib/AST/Expr.cpp | 10 ++++++++++ clang/lib/Sema/SemaExpr.cpp | 14 ++++++++++++++ clang/test/SemaCXX/recovery-expr-type.cpp | 7 +++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 3ea2817..c8d87ec 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1284,7 +1284,7 @@ public: ValueDecl *getDecl() { return D; } const ValueDecl *getDecl() const { return D; } - void setDecl(ValueDecl *NewD) { D = NewD; } + void setDecl(ValueDecl *NewD); DeclarationNameInfo getNameInfo() const { return DeclarationNameInfo(getDecl()->getDeclName(), getLocation(), DNLoc); @@ -3167,7 +3167,7 @@ public: /// The returned declaration will be a FieldDecl or (in C++) a VarDecl (for /// static data members), a CXXMethodDecl, or an EnumConstantDecl. ValueDecl *getMemberDecl() const { return MemberDecl; } - void setMemberDecl(ValueDecl *D) { MemberDecl = D; } + void setMemberDecl(ValueDecl *D); /// Retrieves the declaration found by lookup. DeclAccessPair getFoundDecl() const { diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index f55ee20..1bd032a 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -486,6 +486,11 @@ DeclRefExpr *DeclRefExpr::CreateEmpty(const ASTContext &Context, return new (Mem) DeclRefExpr(EmptyShell()); } +void DeclRefExpr::setDecl(ValueDecl *NewD) { + D = NewD; + setDependence(computeDependence(this, NewD->getASTContext())); +} + SourceLocation DeclRefExpr::getBeginLoc() const { if (hasQualifier()) return getQualifierLoc().getBeginLoc(); @@ -1572,6 +1577,11 @@ MemberExpr *MemberExpr::CreateEmpty(const ASTContext &Context, return new (Mem) MemberExpr(EmptyShell()); } +void MemberExpr::setMemberDecl(ValueDecl *D) { + MemberDecl = D; + setDependence(computeDependence(this)); +} + SourceLocation MemberExpr::getBeginLoc() const { if (isImplicitAccess()) { if (hasQualifier()) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 738fe87..859960d1 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -18152,6 +18152,13 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, SemaRef.runWithSufficientStackSpace(PointOfInstantiation, [&] { SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var); }); + + // Re-set the member to trigger a recomputation of the dependence bits + // for the expression. + if (auto *DRE = dyn_cast_or_null(E)) + DRE->setDecl(DRE->getDecl()); + else if (auto *ME = dyn_cast_or_null(E)) + ME->setMemberDecl(ME->getMemberDecl()); } else if (FirstInstantiation || isa(Var)) { // FIXME: For a specialization of a variable template, we don't @@ -18286,6 +18293,9 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, } /// Perform reference-marking and odr-use handling for a DeclRefExpr. +/// +/// Note, this may change the dependence of the DeclRefExpr, and so needs to be +/// handled with care if the DeclRefExpr is not newly-created. void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { // TODO: update this with DR# once a defect report is filed. // C++11 defect. The address of a pure member should not be an ODR use, even @@ -18412,6 +18422,10 @@ public: if (VD->hasLocalStorage()) return; } + + // FIXME: This can trigger the instantiation of the initializer of a + // variable, which can cause the expression to become value-dependent + // or error-dependent. Do we need to propagate the new dependence bits? S.MarkDeclRefReferenced(E); } diff --git a/clang/test/SemaCXX/recovery-expr-type.cpp b/clang/test/SemaCXX/recovery-expr-type.cpp index f4691b4..ed18b7f 100644 --- a/clang/test/SemaCXX/recovery-expr-type.cpp +++ b/clang/test/SemaCXX/recovery-expr-type.cpp @@ -109,3 +109,10 @@ auto f(); // expected-note {{candidate function not viable}} // verify no crash on evaluating the size of undeduced auto type. static_assert(sizeof(f(1)), ""); // expected-error {{no matching function for call to 'f'}} } + +namespace test10 { +// Ensure we don't assert here. +int f(); // expected-note {{candidate}} +template const int k = f(T()); // expected-error {{no matching function}} +static_assert(k == 1, ""); // expected-note {{instantiation of}} +} -- 2.7.4