// 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
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
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);
// 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);
//
// 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
//
// 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);
//
// 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 ')'.
/// 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) {
return TypeArg.get();
}
- OwningExprResult ExprArg = ParseAssignmentExpression();
+ OwningExprResult ExprArg = ParseConstantExpression();
if (ExprArg.isInvalid() || !ExprArg.get())
return 0;
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) {
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/OwningPtr.h"
+#include <list>
#include <string>
#include <vector>
/// 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.
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.
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.
///
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()) {
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)));
}
// Instantiate the size expression
+ EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
Sema::OwningExprResult InstantiatedArraySize =
SemaRef.InstantiateExpr(ArraySize, TemplateArgs);
if (InstantiatedArraySize.isInvalid())
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 =
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())
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();
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()) {
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())
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;
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(),
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();
}
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())