diff options
-rw-r--r-- | include/clang/AST/EvaluatedExprVisitor.h | 74 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 13 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 5 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 138 | ||||
-rw-r--r-- | test/SemaTemplate/default-expr-arguments.cpp | 28 |
6 files changed, 222 insertions, 41 deletions
diff --git a/include/clang/AST/EvaluatedExprVisitor.h b/include/clang/AST/EvaluatedExprVisitor.h new file mode 100644 index 0000000000..dcb125497b --- /dev/null +++ b/include/clang/AST/EvaluatedExprVisitor.h @@ -0,0 +1,74 @@ +//===--- EvaluatedExprVisitor.h - Evaluated expression visitor --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the EvaluatedExprVisitor class template, which visits +// the potentially-evaluated subexpressions of a potentially-evaluated +// expression. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H +#define LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H + +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" + +namespace clang { + +class ASTContext; + +/// \begin Given a potentially-evaluated expression, this visitor visits all +/// of its potentially-evaluated subexpressions, recursively. +template<typename ImplClass> +class EvaluatedExprVisitor : public StmtVisitor<ImplClass> { + ASTContext &Context; + +public: + explicit EvaluatedExprVisitor(ASTContext &Context) : Context(Context) { } + + // Expressions that have no potentially-evaluated subexpressions (but may have + // other sub-expressions). + void VisitDeclRefExpr(DeclRefExpr *E) { } + void VisitOffsetOfExpr(OffsetOfExpr *E) { } + void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { } + void VisitBlockExpr(BlockExpr *E) { } + void VisitCXXUuidofExpr(CXXUuidofExpr *E) { } + void VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { } + + void VisitMemberExpr(MemberExpr *E) { + // Only the base matters. + return this->Visit(E->getBase()); + } + + void VisitChooseExpr(ChooseExpr *E) { + // Only the selected subexpression matters; the other one is not evaluated. + return this->Visit(E->getChosenSubExpr(Context)); + } + + void VisitDesignatedInitExpr(DesignatedInitExpr *E) { + // Only the actual initializer matters; the designators are all constant + // expressions. + return this->Visit(E->getInit()); + } + + void VisitCXXTypeidExpr(CXXTypeidExpr *E) { + // typeid(expression) is potentially evaluated when the argument is + // a glvalue of polymorphic type. (C++ 5.2.8p2-3) + if (!E->isTypeOperand() && E->Classify(Context).isGLValue()) + if (const RecordType *Record + = E->getExprOperand()->getType()->getAs<RecordType>()) + if (cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic()) + return this->Visit(E->getExprOperand()); + } +}; + +} + +#endif // LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index c98b140e23..e0397075d7 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -404,7 +404,17 @@ public: /// 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 + PotentiallyPotentiallyEvaluated, + + /// \brief The current expression is potentially evaluated, but any + /// declarations referenced inside that expression are only used if + /// in fact the current expression is used. + /// + /// This value is used when parsing default function arguments, for which + /// we would like to provide diagnostics (e.g., passing non-POD arguments + /// through varargs) but do not want to mark declarations as "referenced" + /// until the default argument is used. + PotentiallyEvaluatedIfUsed }; /// \brief Data structure used to record current or nested @@ -1656,6 +1666,7 @@ public: void MarkDeclarationReferenced(SourceLocation Loc, Decl *D); void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); + void MarkDeclarationsReferencedInExpr(Expr *E); bool DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD); // Primary Expressions. diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index d327db485c..8b2fb55d9d 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -138,6 +138,11 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { assert(Tok.is(tok::equal) && "Default argument not starting with '='"); SourceLocation EqualLoc = ConsumeToken(); + // The argument isn't actually potentially evaluated unless it is + // used. + EnterExpressionEvaluationContext Eval(Actions, + Sema::PotentiallyEvaluatedIfUsed); + ExprResult DefArgResult(ParseAssignmentExpression()); if (DefArgResult.isInvalid()) Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index fedfba82ef..45487e0fd1 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3192,6 +3192,11 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // Consume the '='. ConsumeToken(); + // The argument isn't actually potentially evaluated unless it is + // used. + EnterExpressionEvaluationContext Eval(Actions, + Sema::PotentiallyEvaluatedIfUsed); + ExprResult DefArgResult(ParseAssignmentExpression()); if (DefArgResult.isInvalid()) { Actions.ActOnParamDefaultArgumentError(Param); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 1836482fd8..b951b98cce 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -19,6 +19,7 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" @@ -3401,57 +3402,59 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param) { if (Param->hasUnparsedDefaultArg()) { - Diag (CallLoc, + Diag(CallLoc, diag::err_use_of_default_argument_to_function_declared_later) << FD << cast<CXXRecordDecl>(FD->getDeclContext())->getDeclName(); Diag(UnparsedDefaultArgLocs[Param], diag::note_default_argument_declared_here); - } else { - if (Param->hasUninstantiatedDefaultArg()) { - Expr *UninstExpr = Param->getUninstantiatedDefaultArg(); + return ExprError(); + } + + if (Param->hasUninstantiatedDefaultArg()) { + Expr *UninstExpr = Param->getUninstantiatedDefaultArg(); - // Instantiate the expression. - MultiLevelTemplateArgumentList ArgList - = getTemplateInstantiationArgs(FD, 0, /*RelativeToPrimary=*/true); + // Instantiate the expression. + MultiLevelTemplateArgumentList ArgList + = getTemplateInstantiationArgs(FD, 0, /*RelativeToPrimary=*/true); - std::pair<const TemplateArgument *, unsigned> Innermost - = ArgList.getInnermost(); - InstantiatingTemplate Inst(*this, CallLoc, Param, Innermost.first, - Innermost.second); + std::pair<const TemplateArgument *, unsigned> Innermost + = ArgList.getInnermost(); + InstantiatingTemplate Inst(*this, CallLoc, Param, Innermost.first, + Innermost.second); - ExprResult Result = SubstExpr(UninstExpr, ArgList); - if (Result.isInvalid()) - return ExprError(); - - // Check the expression as an initializer for the parameter. - InitializedEntity Entity - = InitializedEntity::InitializeParameter(Param); - InitializationKind Kind - = InitializationKind::CreateCopy(Param->getLocation(), - /*FIXME:EqualLoc*/UninstExpr->getSourceRange().getBegin()); - Expr *ResultE = Result.takeAs<Expr>(); - - InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1); - Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, &ResultE, 1)); - if (Result.isInvalid()) - return ExprError(); + ExprResult Result = SubstExpr(UninstExpr, ArgList); + if (Result.isInvalid()) + return ExprError(); - // Build the default argument expression. - return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param, - Result.takeAs<Expr>())); - } + // Check the expression as an initializer for the parameter. + InitializedEntity Entity + = InitializedEntity::InitializeParameter(Param); + InitializationKind Kind + = InitializationKind::CreateCopy(Param->getLocation(), + /*FIXME:EqualLoc*/UninstExpr->getSourceRange().getBegin()); + Expr *ResultE = Result.takeAs<Expr>(); + + InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1); + Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, &ResultE, 1)); + if (Result.isInvalid()) + return ExprError(); - // If the default expression creates temporaries, we need to - // push them to the current stack of expression temporaries so they'll - // be properly destroyed. - // FIXME: We should really be rebuilding the default argument with new - // bound temporaries; see the comment in PR5810. - for (unsigned i = 0, e = Param->getNumDefaultArgTemporaries(); i != e; ++i) - ExprTemporaries.push_back(Param->getDefaultArgTemporary(i)); + // Build the default argument expression. + return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param, + Result.takeAs<Expr>())); } - // We already type-checked the argument, so we know it works. + // If the default expression creates temporaries, we need to + // push them to the current stack of expression temporaries so they'll + // be properly destroyed. + // FIXME: We should really be rebuilding the default argument with new + // bound temporaries; see the comment in PR5810. + for (unsigned i = 0, e = Param->getNumDefaultArgTemporaries(); i != e; ++i) + ExprTemporaries.push_back(Param->getDefaultArgTemporary(i)); + + // We already type-checked the argument, so we know it works. + MarkDeclarationsReferencedInExpr(Param->getDefaultArg()); return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param)); } @@ -7653,6 +7656,11 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // potentially evaluated. ExprEvalContexts.back().addReferencedDecl(Loc, D); return; + + case PotentiallyEvaluatedIfUsed: + // Referenced declarations will only be used if the construct in the + // containing expression is used. + return; } // Note that this declaration has been used. @@ -7791,6 +7799,55 @@ void Sema::MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T) { Marker.TraverseType(Context.getCanonicalType(T)); } +namespace { + /// \brief Helper class that marks all of the declarations referenced by + /// potentially-evaluated subexpressions as "referenced". + class EvaluatedExprMarker : public EvaluatedExprVisitor<EvaluatedExprMarker> { + Sema &S; + + public: + typedef EvaluatedExprVisitor<EvaluatedExprMarker> Inherited; + + explicit EvaluatedExprMarker(Sema &S) : Inherited(S.Context), S(S) { } + + void VisitDeclRefExpr(DeclRefExpr *E) { + S.MarkDeclarationReferenced(E->getLocation(), E->getDecl()); + } + + void VisitMemberExpr(MemberExpr *E) { + S.MarkDeclarationReferenced(E->getMemberLoc(), E->getMemberDecl()); + } + + void VisitCXXNewExpr(CXXNewExpr *E) { + if (E->getConstructor()) + S.MarkDeclarationReferenced(E->getLocStart(), E->getConstructor()); + if (E->getOperatorNew()) + S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorNew()); + if (E->getOperatorDelete()) + S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorDelete()); + } + + void VisitCXXDeleteExpr(CXXDeleteExpr *E) { + if (E->getOperatorDelete()) + S.MarkDeclarationReferenced(E->getLocStart(), E->getOperatorDelete()); + } + + void VisitCXXConstructExpr(CXXConstructExpr *E) { + S.MarkDeclarationReferenced(E->getLocStart(), E->getConstructor()); + } + + void VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { + S.MarkDeclarationReferenced(E->getLocation(), E->getDecl()); + } + }; +} + +/// \brief Mark any declarations that appear within this expression or any +/// potentially-evaluated subexpressions as "referenced". +void Sema::MarkDeclarationsReferencedInExpr(Expr *E) { + EvaluatedExprMarker(*this).Visit(E); +} + /// \brief Emit a diagnostic that describes an effect on the run-time behavior /// of the program being compiled. /// @@ -7815,6 +7872,7 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, break; case PotentiallyEvaluated: + case PotentiallyEvaluatedIfUsed: Diag(Loc, PD); return true; diff --git a/test/SemaTemplate/default-expr-arguments.cpp b/test/SemaTemplate/default-expr-arguments.cpp index 7c3525a1fb..c898e102bc 100644 --- a/test/SemaTemplate/default-expr-arguments.cpp +++ b/test/SemaTemplate/default-expr-arguments.cpp @@ -206,3 +206,31 @@ namespace InstForInit { Holder<int> h(i); } }; + +namespace PR5810b { + template<typename T> + T broken() { + T t; + double**** not_it = t; + } + + void f(int = broken<int>()); + void g() { f(17); } +} + +namespace PR8127 { + template< typename T > class PointerClass { + public: + PointerClass( T * object_p ) : p_( object_p ) { + p_->acquire(); + } + private: + T * p_; + }; + + class ExternallyImplementedClass; + + class MyClass { + void foo( PointerClass<ExternallyImplementedClass> = 0 ); + }; +} |