From 2afce7248b7a362f1e322ad18e43484d575b9c9d Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 26 Nov 2009 00:44:06 +0000 Subject: [PATCH] Refactor our handling of expression evaluation contexts, so that Sema maintains a stack of evaluation contexts rather than having the parser do it. This change made it simpler to track in which contexts temporaries were created, so that we could... "Forget" about temporaries created within unevaluated contexts, so that we don't build a CXXExprWithTemporaries and, therefore, destroy the integral-constness of our expressions. Fixes PR5609. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89908 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Action.h | 31 +++-------- lib/Sema/Sema.cpp | 7 ++- lib/Sema/Sema.h | 57 +++++++++++++++----- lib/Sema/SemaExpr.cpp | 49 +++++++++-------- lib/Sema/SemaExprCXX.cpp | 7 +-- test/SemaTemplate/instantiate-static-var.cpp | 36 ++++++++++++- 6 files changed, 122 insertions(+), 65 deletions(-) diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index c201b78df9..fc56cc6847 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -917,23 +917,12 @@ public: /// \brief The parser is entering a new expression evaluation context. /// /// \param NewContext is the new expression evaluation context. - /// - /// \returns the previous expression evaluation context. - virtual ExpressionEvaluationContext - PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) { - return PotentiallyEvaluated; - } + virtual void + PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) { } - /// \brief The parser is existing an expression evaluation context. - /// - /// \param OldContext the expression evaluation context that the parser is - /// leaving. - /// - /// \param NewContext the expression evaluation context that the parser is - /// returning to. + /// \brief The parser is exiting an expression evaluation context. virtual void - PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext, - ExpressionEvaluationContext NewContext) { } + PopExpressionEvaluationContext() { } // Primary Expressions. @@ -2661,21 +2650,15 @@ class EnterExpressionEvaluationContext { /// \brief The action object. Action &Actions; - /// \brief The previous expression evaluation context. - Action::ExpressionEvaluationContext PrevContext; - - /// \brief The current expression evaluation context. - Action::ExpressionEvaluationContext CurContext; - public: EnterExpressionEvaluationContext(Action &Actions, Action::ExpressionEvaluationContext NewContext) - : Actions(Actions), CurContext(NewContext) { - PrevContext = Actions.PushExpressionEvaluationContext(NewContext); + : Actions(Actions) { + Actions.PushExpressionEvaluationContext(NewContext); } ~EnterExpressionEvaluationContext() { - Actions.PopExpressionEvaluationContext(CurContext, PrevContext); + Actions.PopExpressionEvaluationContext(); } }; diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 838fb6cbb0..f0812bfe7f 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -352,7 +352,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), PreDeclaratorDC(0), CurBlock(0), PackContext(0), ParsingDeclDepth(0), IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0), - GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated), + GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), NumSFINAEErrors(0), NonInstantiationEntries(0), CurrentInstantiationScope(0) @@ -363,6 +363,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, // Tell diagnostics how to render things from the AST library. PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context); + + ExprEvalContexts.push_back( + ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0)); } /// Retrieves the width and signedness of the given integer type, @@ -592,7 +595,7 @@ static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, unsigned diag) { /// Implements -Wconversion. static void CheckImplicitConversion(Sema &S, Expr *E, QualType T) { // Don't diagnose in unevaluated contexts. - if (S.ExprEvalContext == Sema::Unevaluated) + if (S.ExprEvalContexts.back().Context == Sema::Unevaluated) return; // Don't diagnose for value-dependent expressions. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 084f720d4d..5577cbd7d7 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -330,18 +330,49 @@ public: /// have been declared. bool GlobalNewDeleteDeclared; - /// The current expression evaluation context. - ExpressionEvaluationContext ExprEvalContext; - - typedef std::vector > + /// \brief The set of declarations that have been referenced within + /// a potentially evaluated expression. + typedef std::vector > PotentiallyReferencedDecls; - /// A stack of declarations, each element of which is a set of declarations - /// that will be marked as referenced if the corresponding potentially - /// potentially evaluated expression is potentially evaluated. Each element - /// in the stack corresponds to a PotentiallyPotentiallyEvaluated expression - /// evaluation context. - std::list PotentiallyReferencedDeclStack; + /// \brief Data structure used to record current or nested + /// expression evaluation contexts. + struct ExpressionEvaluationContextRecord { + /// \brief The expression evaluation context. + ExpressionEvaluationContext Context; + + /// \brief The number of temporaries that were active when we + /// entered this expression evaluation context. + unsigned NumTemporaries; + + /// \brief The set of declarations referenced within a + /// potentially potentially-evaluated context. + /// + /// When leaving a potentially potentially-evaluated context, each + /// of these elements will be as referenced if the corresponding + /// potentially potentially evaluated expression is potentially + /// evaluated. + PotentiallyReferencedDecls *PotentiallyReferenced; + + ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, + unsigned NumTemporaries) + : Context(Context), NumTemporaries(NumTemporaries), + PotentiallyReferenced(0) { } + + void addReferencedDecl(SourceLocation Loc, Decl *Decl) { + if (!PotentiallyReferenced) + PotentiallyReferenced = new PotentiallyReferencedDecls; + PotentiallyReferenced->push_back(std::make_pair(Loc, Decl)); + } + + void Destroy() { + delete PotentiallyReferenced; + PotentiallyReferenced = 0; + } + }; + + /// A stack of expression evaluation contexts. + llvm::SmallVector ExprEvalContexts; /// \brief Whether the code handled by Sema should be considered a /// complete translation unit or not. @@ -1377,12 +1408,10 @@ public: const PartialDiagnostic &PD, bool Equality = false); - virtual ExpressionEvaluationContext + virtual void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext); - virtual void - PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext, - ExpressionEvaluationContext NewContext); + virtual void PopExpressionEvaluationContext(); void MarkDeclarationReferenced(SourceLocation Loc, Decl *D); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 5479ce65fa..f3a6765a6a 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4490,7 +4490,7 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, const PartialDiagnostic &PD, bool Equality) { // Don't warn if we're in an unevaluated context. - if (ExprEvalContext == Unevaluated) + if (ExprEvalContexts.back().Context == Unevaluated) return; QualType lt = lex->getType(), rt = rex->getType(); @@ -6378,34 +6378,41 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){ return false; } -Sema::ExpressionEvaluationContext +void Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) { - // Introduce a new set of potentially referenced declarations to the stack. - if (NewContext == PotentiallyPotentiallyEvaluated) - PotentiallyReferencedDeclStack.push_back(PotentiallyReferencedDecls()); - - std::swap(ExprEvalContext, NewContext); - return NewContext; + ExprEvalContexts.push_back( + ExpressionEvaluationContextRecord(NewContext, ExprTemporaries.size())); } void -Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext, - ExpressionEvaluationContext NewContext) { - ExprEvalContext = NewContext; +Sema::PopExpressionEvaluationContext() { + // Pop the current expression evaluation context off the stack. + ExpressionEvaluationContextRecord Rec = ExprEvalContexts.back(); + ExprEvalContexts.pop_back(); - if (OldContext == PotentiallyPotentiallyEvaluated) { + if (Rec.Context == PotentiallyPotentiallyEvaluated && + Rec.PotentiallyReferenced) { // Mark any remaining declarations in the current position of the stack // as "referenced". If they were not meant to be referenced, semantic // analysis would have eliminated them (e.g., in ActOnCXXTypeId). - PotentiallyReferencedDecls RemainingDecls; - RemainingDecls.swap(PotentiallyReferencedDeclStack.back()); - PotentiallyReferencedDeclStack.pop_back(); - - for (PotentiallyReferencedDecls::iterator I = RemainingDecls.begin(), - IEnd = RemainingDecls.end(); + for (PotentiallyReferencedDecls::iterator + I = Rec.PotentiallyReferenced->begin(), + IEnd = Rec.PotentiallyReferenced->end(); I != IEnd; ++I) MarkDeclarationReferenced(I->first, I->second); - } + } + + // When are coming out of an unevaluated context, clear out any + // temporaries that we may have created as part of the evaluation of + // the expression in that context: they aren't relevant because they + // will never be constructed. + if (Rec.Context == Unevaluated && + ExprTemporaries.size() > Rec.NumTemporaries) + ExprTemporaries.erase(ExprTemporaries.begin() + Rec.NumTemporaries, + ExprTemporaries.end()); + + // Destroy the popped expression evaluation record. + Rec.Destroy(); } /// \brief Note that the given declaration was referenced in the source code. @@ -6437,7 +6444,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (CurContext->isDependentContext()) return; - switch (ExprEvalContext) { + switch (ExprEvalContexts.back().Context) { case Unevaluated: // We are in an expression that is not potentially evaluated; do nothing. return; @@ -6451,7 +6458,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // We are in an expression that may be potentially evaluated; queue this // declaration reference until we know whether the expression is // potentially evaluated. - PotentiallyReferencedDeclStack.back().push_back(std::make_pair(Loc, D)); + ExprEvalContexts.back().addReferencedDecl(Loc, D); return; } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 3b18b3a1ba..af7a56fb7b 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -63,10 +63,11 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, } } - // If this is an unevaluated operand, clear out the set of declaration - // references we have been computing. + // If this is an unevaluated operand, clear out the set of + // declaration references we have been computing and eliminate any + // temporaries introduced in its computation. if (isUnevaluatedOperand) - PotentiallyReferencedDeclStack.back().clear(); + ExprEvalContexts.back().Context = Unevaluated; } return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr, diff --git a/test/SemaTemplate/instantiate-static-var.cpp b/test/SemaTemplate/instantiate-static-var.cpp index 96fa34cc2a..452fccf224 100644 --- a/test/SemaTemplate/instantiate-static-var.cpp +++ b/test/SemaTemplate/instantiate-static-var.cpp @@ -1,5 +1,4 @@ // RUN: clang-cc -fsyntax-only -verify %s - template class X { public: @@ -38,3 +37,38 @@ void test() { DefCon &DC = Z::value; NoDefCon &NDC = Z::value; // expected-note{{instantiation}} } + +// PR5609 +struct X1 { + ~X1(); // The errors won't be triggered without this dtor. +}; + +template +struct Y1 { + static char Helper(T); + static const int value = sizeof(Helper(T())); +}; + +struct X2 { + virtual ~X2(); +}; + +namespace std { + class type_info { }; +} + +template +struct Y2 { + static T &Helper(); + static const int value = sizeof(typeid(Helper())); +}; + +template +struct Z1 {}; + +void Test() { + Z1::value> x; + int y[Y1::value]; + Z1::value> x2; + int y2[Y2::value]; +} -- 2.40.0