]> granicus.if.org Git - clang/commitdiff
Refactor our handling of expression evaluation contexts, so that Sema
authorDouglas Gregor <dgregor@apple.com>
Thu, 26 Nov 2009 00:44:06 +0000 (00:44 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 26 Nov 2009 00:44:06 +0000 (00:44 +0000)
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
lib/Sema/Sema.cpp
lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
test/SemaTemplate/instantiate-static-var.cpp

index c201b78df90b2225821b0f94503174d933abe480..fc56cc68476eabb64491b2bcd28b009e311d3115 100644 (file)
@@ -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();
   }
 };
 
index 838fb6cbb00ce13fd7e5d6829afaa3a03e00e749..f0812bfe7fdb49fd28ae14ae46c2726a43ca98b3 100644 (file)
@@ -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.
index 084f720d4ddc202fe464dec130aece0a20a945c7..5577cbd7d744a31c88ca180273bd66b4ead5bcba 100644 (file)
@@ -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);
 
index 5479ce65fa8a19ebadb10009512c0f85d33ff21d..f3a6765a6a22e6510d4a07e9a83fa2f0d4dc4bf1 100644 (file)
@@ -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;
   }
 
index 3b18b3a1ba9b63e1866b6a1ea3bc34bd5ca0647b..af7a56fb7b03b99510c543b5f23f4624d6f4ff5d 100644 (file)
@@ -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,
index 96fa34cc2aff1982a0f9df40ea54e8b1ab078864..452fccf2244d7c9ddb71ef058c7ecac7e124ab00 100644 (file)
@@ -1,5 +1,4 @@
 // RUN: clang-cc -fsyntax-only -verify %s
-
 template<typename T, T Divisor>
 class X {
 public:
@@ -38,3 +37,38 @@ void test() {
   DefCon &DC = Z<DefCon>::value;
   NoDefCon &NDC = Z<NoDefCon>::value; // expected-note{{instantiation}}
 }
+
+// PR5609
+struct X1 {
+  ~X1();  // The errors won't be triggered without this dtor.
+};
+
+template <typename T>
+struct Y1 {
+  static char Helper(T);
+  static const int value = sizeof(Helper(T()));
+};
+
+struct X2 {
+  virtual ~X2();
+};
+
+namespace std {
+  class type_info { };
+}
+
+template <typename T>
+struct Y2 {
+  static T &Helper();
+  static const int value = sizeof(typeid(Helper()));
+};
+
+template <int>
+struct Z1 {};
+
+void Test() {
+  Z1<Y1<X1>::value> x;
+  int y[Y1<X1>::value];
+  Z1<Y2<X2>::value> x2;
+  int y2[Y2<X2>::value];
+}