diff options
-rw-r--r-- | clang/include/clang/Parse/Action.h | 71 | ||||
-rw-r--r-- | clang/include/clang/Parse/Parser.h | 18 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 9 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Parse/ParseTemplate.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 31 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 51 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 25 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 11 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateExpr.cpp | 20 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateStmt.cpp | 3 |
13 files changed, 210 insertions, 55 deletions
diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 5b57521f675..8c85ba60ac2 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -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 diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 75458d821e8..75587936065 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -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); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 4a07d05650b..13b32acd5b2 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -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); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 87aa5dc6711..2be44a4e77a 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -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 ')'. diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index a9f75d8be17..eabe10f1450 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -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; diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index e756b41b12f..2fa09b90464 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -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) { diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 560f952bffa..28f81e614a3 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -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. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d0cd23e8592..c005f103a30 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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()) { diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index bec595ca9cf..a567218eaa8 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -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))); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 3992f8cbe53..1c4e907d4d6 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -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(); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 6d7dc2e6d53..461302f81d5 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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; diff --git a/clang/lib/Sema/SemaTemplateInstantiateExpr.cpp b/clang/lib/Sema/SemaTemplateInstantiateExpr.cpp index bf19701d6be..749fb589487 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -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(); diff --git a/clang/lib/Sema/SemaTemplateInstantiateStmt.cpp b/clang/lib/Sema/SemaTemplateInstantiateStmt.cpp index efdcec81aff..565b95b329f 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateStmt.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateStmt.cpp @@ -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()) |