diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-11-26 00:44:06 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-11-26 00:44:06 +0000 |
commit | 2afce7248b7a362f1e322ad18e43484d575b9c9d (patch) | |
tree | ec6248bcb8c77c0371d28db1f51f44d21b1da68d /lib | |
parent | bf0fe6c5b7bd7bc67b6b3ef0acb22bf4811f2a1b (diff) |
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
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Sema/Sema.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 57 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 49 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 7 |
4 files changed, 80 insertions, 40 deletions
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<std::pair<SourceLocation, Decl *> > + /// \brief The set of declarations that have been referenced within + /// a potentially evaluated expression. + typedef std::vector<std::pair<SourceLocation, Decl *> > 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<PotentiallyReferencedDecls> 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<ExpressionEvaluationContextRecord, 8> 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, |