]> granicus.if.org Git - clang/commitdiff
Rework the way we track which declarations are "used" during
authorDouglas Gregor <dgregor@apple.com>
Mon, 22 Jun 2009 20:57:11 +0000 (20:57 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 22 Jun 2009 20:57:11 +0000 (20:57 +0000)
compilation, and (hopefully) introduce RAII objects for changing the
"potentially evaluated" state at all of the necessary places within
Sema and Parser. Other changes:

  - Set the unevaluated/potentially-evaluated context appropriately
    during template instantiation.
  - We now recognize three different states while parsing or
    instantiating expressions: unevaluated, potentially evaluated, and
    potentially potentially evaluated (for C++'s typeid).
  - When we're in a potentially potentially-evaluated context, queue
    up MarkDeclarationReferenced calls in a stack. For C++ typeid
    expressions that are potentially evaluated, we will play back
    these MarkDeclarationReferenced calls when we exit the
    corresponding potentially potentially-evaluated context.
  - Non-type template arguments are now parsed as constant
    expressions, so they are not potentially-evaluated.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73899 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/clang/Parse/Action.h
include/clang/Parse/Parser.h
lib/Parse/ParseExpr.cpp
lib/Parse/ParseExprCXX.cpp
lib/Parse/ParseTemplate.cpp
lib/Sema/Sema.cpp
lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Sema/SemaTemplateInstantiateExpr.cpp
lib/Sema/SemaTemplateInstantiateStmt.cpp

index 5b57521f67514c686b6728279a1ddba37e1f8836..8c85ba60ac2e50c9d42be48a2447f136bd1e9870 100644 (file)
@@ -637,18 +637,50 @@ public:
   // Expression Parsing Callbacks.
   //===--------------------------------------------------------------------===//
 
-  /// \brief Notifies the action when the parser is processing an unevaluated
-  /// operand.
+  /// \brief Describes how the expressions currently being parsed are
+  /// evaluated at run-time, if at all.
+  enum ExpressionEvaluationContext {
+    /// \brief The current expression and its subexpressions occur within an
+    /// unevaluated operand (C++0x [expr]p8), such as a constant expression
+    /// or the subexpression of \c sizeof, where the type or the value of the
+    /// expression may be significant but no code will be generated to evaluate 
+    /// the value of the expression at run time.
+    Unevaluated,
+    
+    /// \brief The current expression is potentially evaluated at run time, 
+    /// which means that code may be generated to evaluate the value of the 
+    /// expression at run time.
+    PotentiallyEvaluated,
+    
+    /// \brief The current expression may be potentially evaluated or it may
+    /// be unevaluated, but it is impossible to tell from the lexical context.
+    /// This evaluation context is used primary for the operand of the C++
+    /// \c typeid expression, whose argument is potentially evaluated only when
+    /// it is an lvalue of polymorphic class type (C++ [basic.def.odr]p2).
+    PotentiallyPotentiallyEvaluated
+  };
+  
+  /// \brief The parser is entering a new expression evaluation context.
   ///
-  /// \param UnevaluatedOperand true to indicate that the parser is processing
-  /// an unevaluated operand, or false otherwise.
+  /// \param NewContext is the new expression evaluation context.
   ///
-  /// \returns whether the the action module was previously in an unevaluated
-  /// operand.
-  virtual bool setUnevaluatedOperand(bool UnevaluatedOperand) { 
-    return false;
+  /// \returns the previous expression evaluation context.
+  virtual ExpressionEvaluationContext 
+  PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext) {
+    return PotentiallyEvaluated;
   }
   
+  /// \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.
+  virtual void 
+  PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
+                                 ExpressionEvaluationContext NewContext) { }
+  
   // Primary Expressions.
 
   /// \brief Retrieve the source range that corresponds to the given
@@ -1891,6 +1923,29 @@ public:
   virtual void print(llvm::raw_ostream &OS) const;
 };  
   
+/// \brief RAII object that enters a new expression evaluation context.
+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);
+  }
+    
+  ~EnterExpressionEvaluationContext() {
+    Actions.PopExpressionEvaluationContext(CurContext, PrevContext);
+  }
+};
+  
 }  // end namespace clang
 
 #endif
index 75458d821e8ea092ea67865dd78029ddb455fc19..75587936065b66c591fbbeeab8cb79719c16982e 100644 (file)
@@ -104,24 +104,6 @@ class Parser {
       GreaterThanIsOperator = OldGreaterThanIsOperator;
     }
   };
-
-  /// \brief RAII object that enters an unevaluated operand.
-  class EnterUnevaluatedOperand {    
-    /// \brief The action object.
-    Action &Actions;
-    
-    /// \brief Whether we were previously within an unevaluated operand.
-    bool PreviouslyInUnevaluatedOperand;
-    
-  public:
-    explicit EnterUnevaluatedOperand(Action &Actions) : Actions(Actions) { 
-      PreviouslyInUnevaluatedOperand = Actions.setUnevaluatedOperand(true);
-    }
-    
-    ~EnterUnevaluatedOperand() {
-      Actions.setUnevaluatedOperand(PreviouslyInUnevaluatedOperand);
-    }
-  };
   
 public:
   Parser(Preprocessor &PP, Action &Actions);
index 4a07d05650bd1c1ce1ec6893b02aa7b4cbc611e9..13b32acd5b299196c4811cdfbe90965bd34522d8 100644 (file)
@@ -279,7 +279,8 @@ Parser::OwningExprResult Parser::ParseConstantExpression() {
   // C++ [basic.def.odr]p2:
   //   An expression is potentially evaluated unless it appears where an 
   //   integral constant expression is required (see 5.19) [...].
-  EnterUnevaluatedOperand Unevaluated(Actions);
+  EnterExpressionEvaluationContext Unevaluated(Actions,
+                                               Action::Unevaluated);
   
   OwningExprResult LHS(ParseCastExpression(false));
   if (LHS.isInvalid()) return move(LHS);
@@ -983,7 +984,8 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
     //
     // The GNU typeof and alignof extensions also behave as unevaluated
     // operands.
-    EnterUnevaluatedOperand Unevaluated(Actions);
+    EnterExpressionEvaluationContext Unevaluated(Actions,
+                                                 Action::Unevaluated);
     Operand = ParseCastExpression(true/*isUnaryExpression*/);
   } else {
     // If it starts with a '(', we know that it is either a parenthesized
@@ -999,7 +1001,8 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
     //
     // The GNU typeof and alignof extensions also behave as unevaluated
     // operands.
-    EnterUnevaluatedOperand Unevaluated(Actions);
+    EnterExpressionEvaluationContext Unevaluated(Actions,
+                                                 Action::Unevaluated);
     Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/,
                                    CastTy, RParenLoc);
     CastRange = SourceRange(LParenLoc, RParenLoc);
index 87aa5dc671167fea425fd78c1600469ced64c395..2be44a4e77a0f984e471bcf4f2ef542735650147 100644 (file)
@@ -384,10 +384,9 @@ Parser::OwningExprResult Parser::ParseCXXTypeid() {
     //
     // Note that we can't tell whether the expression is an lvalue of a 
     // polymorphic class type until after we've parsed the expression, so
-    // we treat the expression as an unevaluated operand and let semantic
-    // analysis cope with case where the expression is not an unevaluated
-    // operand.
-    EnterUnevaluatedOperand Unevaluated(Actions);
+    // we the expression is potentially potentially evaluated.
+    EnterExpressionEvaluationContext Unevaluated(Actions,
+                                       Action::PotentiallyPotentiallyEvaluated);
     Result = ParseExpression();
 
     // Match the ')'.
index a9f75d8be17da97e328215ad9c52e0b6de07700f..eabe10f1450ee2a16bfafbf81e27407856fd457c 100644 (file)
@@ -750,7 +750,7 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
 /// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]).
 ///
 ///       template-argument: [C++ 14.2]
-///         assignment-expression
+///         constant-expression
 ///         type-id
 ///         id-expression
 void *Parser::ParseTemplateArgument(bool &ArgIsType) {
@@ -768,7 +768,7 @@ void *Parser::ParseTemplateArgument(bool &ArgIsType) {
     return TypeArg.get();
   }
 
-  OwningExprResult ExprArg = ParseAssignmentExpression();
+  OwningExprResult ExprArg = ParseConstantExpression();
   if (ExprArg.isInvalid() || !ExprArg.get())
     return 0;
 
index e756b41b12f5b5a4c34455990cc202cf8fa49360..2fa09b9046461086d81d129a0abb6422d62865bd 100644 (file)
@@ -182,7 +182,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
     Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), 
     ExternalSource(0), CurContext(0), PreDeclaratorDC(0),
     CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()),
-    GlobalNewDeleteDeclared(false), InUnevaluatedOperand(false),
+    GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated),
     CompleteTranslationUnit(CompleteTranslationUnit),
     NumSFINAEErrors(0), CurrentInstantiationScope(0) {
   
index 560f952bffa56458d75aa49be1132f02f6a8896f..28f81e614a33c159a965df7510c92d0105ce732e 100644 (file)
@@ -29,6 +29,7 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/OwningPtr.h"
+#include <list>
 #include <string>
 #include <vector>
 
@@ -247,11 +248,18 @@ public:
   /// have been declared.
   bool GlobalNewDeleteDeclared;
 
-  /// A flag that indicates when we are processing an unevaluated operand
-  /// (C++0x [expr]). C99 has the same notion of declarations being
-  /// "used" and C++03 has the notion of "potentially evaluated", but we
-  /// adopt the C++0x terminology since it is most precise.
-  bool InUnevaluatedOperand;
+  /// The current expression evaluation context.
+  ExpressionEvaluationContext ExprEvalContext;
+  
+  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 Whether the code handled by Sema should be considered a
   /// complete translation unit or not.
@@ -1334,12 +1342,13 @@ public:
   void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
                              Expr **Args, unsigned NumArgs);
 
-  virtual bool setUnevaluatedOperand(bool UnevaluatedOperand) { 
-    bool Result = InUnevaluatedOperand;
-    InUnevaluatedOperand = UnevaluatedOperand;
-    return Result;
-  }
-
+  virtual ExpressionEvaluationContext 
+  PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext);
+  
+  virtual void 
+  PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
+                                 ExpressionEvaluationContext NewContext);
+  
   void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
   
   // Primary Expressions.
index d0cd23e8592af584409658d5e8a53225b4761da3..c005f103a30db5193b31e7717c0560ee82b2a74e 100644 (file)
@@ -5432,6 +5432,35 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){
   return false;
 }
 
+Sema::ExpressionEvaluationContext 
+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;
+}
+
+void 
+Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext,
+                                     ExpressionEvaluationContext NewContext) {
+  ExprEvalContext = NewContext;
+
+  if (OldContext == PotentiallyPotentiallyEvaluated) {
+    // 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();
+         I != IEnd; ++I)
+      MarkDeclarationReferenced(I->first, I->second);
+  }
+}
 
 /// \brief Note that the given declaration was referenced in the source code.
 ///
@@ -5456,10 +5485,24 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
   if (CurContext->isDependentContext())
     return;
   
-  // If we are in an unevaluated operand, don't mark any definitions as used.
-  if (InUnevaluatedOperand)
-    return;
-  
+  switch (ExprEvalContext) {
+    case Unevaluated:
+      // We are in an expression that is not potentially evaluated; do nothing.
+      return;
+      
+    case PotentiallyEvaluated:
+      // We are in a potentially-evaluated expression, so this declaration is
+      // "used"; handle this below.
+      break;
+      
+    case PotentiallyPotentiallyEvaluated:
+      // 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));
+      return;
+  }
+      
   // Note that this declaration has been used.
   if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
     if (Constructor->isImplicit() && Constructor->isDefaultConstructor()) {
index bec595ca9cf989448a618bc3a8ce64f292d722dd..a567218eaa88bcc5cd2d90aa93d1963a20edc576 100644 (file)
@@ -71,6 +71,31 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
 
   QualType TypeInfoType = Context.getTypeDeclType(TypeInfoRecordDecl);
 
+  if (!isType) {
+    // C++0x [expr.typeid]p3:
+    //   When typeid is applied to an expression other than an lvalue of a 
+    //   polymorphic class type [...] [the] expression is an unevaluated 
+    //   operand.
+    
+    // FIXME: if the type of the expression is a class type, the class
+    // shall be completely defined.
+    bool isUnevaluatedOperand = true;
+    Expr *E = static_cast<Expr *>(TyOrExpr);
+    if (E && !E->isTypeDependent() && E->isLvalue(Context) == Expr::LV_Valid) {
+      QualType T = E->getType();
+      if (const RecordType *RecordT = T->getAsRecordType()) {
+        CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getDecl());
+        if (RecordD->isPolymorphic())
+          isUnevaluatedOperand = false;
+      }
+    }
+    
+    // If this is an unevaluated operand, clear out the set of declaration
+    // references we have been computing.
+    if (isUnevaluatedOperand)
+      PotentiallyReferencedDeclStack.back().clear();
+  }
+  
   return Owned(new (Context) CXXTypeidExpr(isType, TyOrExpr,
                                            TypeInfoType.withConst(),
                                            SourceRange(OpLoc, RParenLoc)));
index 3992f8cbe53671d0ce6dd88713cea179a8bcc736..1c4e907d4d6f1c194904e49c2e2c963781b561a2 100644 (file)
@@ -420,6 +420,7 @@ InstantiateDependentSizedArrayType(const DependentSizedArrayType *T,
   }
   
   // Instantiate the size expression
+  EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
   Sema::OwningExprResult InstantiatedArraySize = 
     SemaRef.InstantiateExpr(ArraySize, TemplateArgs);
   if (InstantiatedArraySize.isInvalid())
@@ -443,6 +444,10 @@ InstantiateDependentSizedExtVectorType(const DependentSizedExtVectorType *T,
       return QualType();
   }
 
+  // The expression in a dependent-sized extended vector type is not
+  // potentially evaluated.
+  EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
   // Instantiate the size expression.
   const Expr *SizeExpr = T->getSizeExpr();
   Sema::OwningExprResult InstantiatedArraySize = 
@@ -520,6 +525,9 @@ TemplateTypeInstantiator::InstantiateTypedefType(const TypedefType *T,
 QualType 
 TemplateTypeInstantiator::InstantiateTypeOfExprType(const TypeOfExprType *T,
                                                     unsigned Quals) const {
+  // The expression in a typeof is not potentially evaluated.
+  EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+  
   Sema::OwningExprResult E 
     = SemaRef.InstantiateExpr(T->getUnderlyingExpr(), TemplateArgs);
   if (E.isInvalid())
@@ -1175,6 +1183,9 @@ TemplateArgument Sema::Instantiate(TemplateArgument Arg,
     return Arg;
 
   case TemplateArgument::Expression: {
+    // Template argument expressions are not potentially evaluated.
+    EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated);
+
     Sema::OwningExprResult E = InstantiateExpr(Arg.getAsExpr(), TemplateArgs);
     if (E.isInvalid())
       return TemplateArgument();
index 6d7dc2e6d5311343986de84f03d94ab980f23eb1..461302f81d58003b9010b79b25dd4bcf4a1d1efc 100644 (file)
@@ -163,6 +163,9 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
   if (Invalid)
     BitWidth = 0;
   else if (BitWidth) {
+    // The bit-width expression is not potentially evaluated.
+    EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+    
     OwningExprResult InstantiatedBitWidth
       = SemaRef.InstantiateExpr(BitWidth, TemplateArgs);
     if (InstantiatedBitWidth.isInvalid()) {
@@ -192,6 +195,9 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
 Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
   Expr *AssertExpr = D->getAssertExpr();
       
+  // The expression in a static assertion is not potentially evaluated.
+  EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+  
   OwningExprResult InstantiatedAssertExpr
     = SemaRef.InstantiateExpr(AssertExpr, TemplateArgs);
   if (InstantiatedAssertExpr.isInvalid())
@@ -222,8 +228,13 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
        EC != ECEnd; ++EC) {
     // The specified value for the enumerator.
     OwningExprResult Value = SemaRef.Owned((Expr *)0);
-    if (Expr *UninstValue = EC->getInitExpr())
+    if (Expr *UninstValue = EC->getInitExpr()) {
+      // The enumerator's value expression is not potentially evaluated.
+      EnterExpressionEvaluationContext Unevaluated(SemaRef, 
+                                                   Action::Unevaluated);
+      
       Value = SemaRef.InstantiateExpr(UninstValue, TemplateArgs);
+    }
 
     // Drop the initial value and continue.
     bool isInvalid = false;
index bf19701d6beda9a59796d646c5583b268a299d18..749fb58948786e24712162353ee4d596088bc3af 100644 (file)
@@ -714,9 +714,17 @@ TemplateExprInstantiator::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
                                            E->getSourceRange());
   } 
 
-  Sema::OwningExprResult Arg = Visit(E->getArgumentExpr());
-  if (Arg.isInvalid())
-    return SemaRef.ExprError();
+  Sema::OwningExprResult Arg(SemaRef);
+  {   
+    // C++0x [expr.sizeof]p1:
+    //   The operand is either an expression, which is an unevaluated operand
+    //   [...]
+    EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+    
+    Arg = Visit(E->getArgumentExpr());
+    if (Arg.isInvalid())
+      return SemaRef.ExprError();
+  }
 
   Sema::OwningExprResult Result
     = SemaRef.CreateSizeOfAlignOfExpr((Expr *)Arg.get(), E->getOperatorLoc(),
@@ -949,6 +957,12 @@ TemplateExprInstantiator::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
                                   E->getSourceRange().getEnd());
   }
 
+  // We don't know whether the expression is potentially evaluated until
+  // after we perform semantic analysis, so the expression is potentially
+  // potentially evaluated.
+  EnterExpressionEvaluationContext Unevaluated(SemaRef, 
+                                     Action::PotentiallyPotentiallyEvaluated);
+
   OwningExprResult Operand = Visit(E->getExprOperand());
   if (Operand.isInvalid())
     return SemaRef.ExprError();
index efdcec81afffcaaefa6cfba2b02ea64dec665bd2..565b95b329f73cf0853ec3166488d4254130adb7 100644 (file)
@@ -145,6 +145,9 @@ TemplateStmtInstantiator::VisitSwitchCase(SwitchCase *S) {
 }
 
 Sema::OwningStmtResult TemplateStmtInstantiator::VisitCaseStmt(CaseStmt *S) {
+  // The case value expressions are not potentially evaluated.
+  EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+
   // Instantiate left-hand case value.
   OwningExprResult LHS = SemaRef.InstantiateExpr(S->getLHS(), TemplateArgs);
   if (LHS.isInvalid())