diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-02-22 02:04:18 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-02-22 02:04:18 +0000 |
commit | fd555f6b1fd950eff620e74da887dc37d919a276 (patch) | |
tree | 3c3ce70944db709410b9c1753550d399b57aae6c /clang/lib | |
parent | 3715c691b3f4e88d05ae92d7b831cfceb5865285 (diff) | |
download | bcm5719-llvm-fd555f6b1fd950eff620e74da887dc37d919a276.tar.gz bcm5719-llvm-fd555f6b1fd950eff620e74da887dc37d919a276.zip |
Implement C++11 [expr.call]p11: If the operand to a decltype-specifier is a
function call (or a comma expression with a function call on its right-hand
side), possibly parenthesized, then the return type is not required to be
complete and a temporary is not bound. Other subexpressions inside a decltype
expression do not get this treatment.
This is implemented by deferring the relevant checks for all calls immediately
within a decltype expression, then, when the expression is fully-parsed,
checking the relevant constraints and stripping off any top-level temporary
binding.
Deferring the completion of the return type exposed a bug in overload
resolution where completion of the argument types was not attempted, which
is also fixed by this change.
llvm-svn: 151117
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 112 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 7 |
6 files changed, 133 insertions, 14 deletions
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 5edc30be92b..61ca84136e3 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -667,8 +667,8 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { // C++0x [dcl.type.simple]p4: // The operand of the decltype specifier is an unevaluated operand. - EnterExpressionEvaluationContext Unevaluated(Actions, - Sema::Unevaluated); + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, + 0, /*IsDecltype=*/true); Result = ParseExpression(); if (Result.isInvalid()) { SkipUntil(tok::r_paren, true, true); @@ -685,6 +685,12 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { return T.getCloseLocation(); } + Result = Actions.ActOnDecltypeExpression(Result.take()); + if (Result.isInvalid()) { + DS.SetTypeSpecError(); + return T.getCloseLocation(); + } + EndLoc = T.getCloseLocation(); } diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 6a83518bc02..cfb4e4c91b9 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -111,7 +111,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, &Context); ExprEvalContexts.push_back( - ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0, false, 0)); + ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0, + false, 0, false)); FunctionScopes.push_back(new FunctionScopeInfo(Diags)); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index be3fa6c0dc6..c7738a5626a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -9277,12 +9277,14 @@ ExprResult Sema::TranformToPotentiallyEvaluated(Expr *E) { void Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, - Decl *LambdaContextDecl) { + Decl *LambdaContextDecl, + bool IsDecltype) { ExprEvalContexts.push_back( ExpressionEvaluationContextRecord(NewContext, ExprCleanupObjects.size(), ExprNeedsCleanups, - LambdaContextDecl)); + LambdaContextDecl, + IsDecltype)); ExprNeedsCleanups = false; if (!MaybeODRUseExprs.empty()) std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs); @@ -10280,6 +10282,13 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc, if (ReturnType->isVoidType() || !ReturnType->isIncompleteType()) return false; + // If we're inside a decltype's expression, don't check for a valid return + // type or construct temporaries until we know whether this is the last call. + if (ExprEvalContexts.back().IsDecltype) { + ExprEvalContexts.back().DelayedDecltypeCalls.push_back(CE); + return false; + } + PartialDiagnostic Note = FD ? PDiag(diag::note_function_with_incomplete_return_type_declared_here) << FD->getDeclName() : PDiag(); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index c33ba7558b8..c8e640f1917 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -4315,11 +4315,14 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { } } - // That should be enough to guarantee that this type is complete. + // That should be enough to guarantee that this type is complete, if we're + // not processing a decltype expression. CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); if (RD->isInvalidDecl() || RD->isDependentContext()) return Owned(E); - CXXDestructorDecl *Destructor = LookupDestructor(RD); + + bool IsDecltype = ExprEvalContexts.back().IsDecltype; + CXXDestructorDecl *Destructor = IsDecltype ? 0 : LookupDestructor(RD); if (Destructor) { MarkFunctionReferenced(E->getExprLoc(), Destructor); @@ -4327,18 +4330,22 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { PDiag(diag::err_access_dtor_temp) << E->getType()); DiagnoseUseOfDecl(Destructor, E->getExprLoc()); - } - // If destructor is trivial, we can avoid the extra copy. - if (Destructor->isTrivial()) - return Owned(E); + // If destructor is trivial, we can avoid the extra copy. + if (Destructor->isTrivial()) + return Owned(E); - if (Destructor) // We need a cleanup, but we don't need to remember the temporary. ExprNeedsCleanups = true; + } CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor); - return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E)); + CXXBindTemporaryExpr *Bind = CXXBindTemporaryExpr::Create(Context, Temp, E); + + if (IsDecltype) + ExprEvalContexts.back().DelayedDecltypeBinds.push_back(Bind); + + return Owned(Bind); } ExprResult @@ -4390,6 +4397,95 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) { return MaybeCreateExprWithCleanups(E); } +/// Process the expression contained within a decltype. For such expressions, +/// certain semantic checks on temporaries are delayed until this point, and +/// are omitted for the 'topmost' call in the decltype expression. If the +/// topmost call bound a temporary, strip that temporary off the expression. +ExprResult Sema::ActOnDecltypeExpression(Expr *E) { + ExpressionEvaluationContextRecord &Rec = ExprEvalContexts.back(); + assert(Rec.IsDecltype && "not in a decltype expression"); + + // C++11 [expr.call]p11: + // If a function call is a prvalue of object type, + // -- if the function call is either + // -- the operand of a decltype-specifier, or + // -- the right operand of a comma operator that is the operand of a + // decltype-specifier, + // a temporary object is not introduced for the prvalue. + + // Recursively rebuild ParenExprs and comma expressions to strip out the + // outermost CXXBindTemporaryExpr, if any. + if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) { + ExprResult SubExpr = ActOnDecltypeExpression(PE->getSubExpr()); + if (SubExpr.isInvalid()) + return ExprError(); + if (SubExpr.get() == PE->getSubExpr()) + return Owned(E); + return ActOnParenExpr(PE->getLParen(), PE->getRParen(), SubExpr.take()); + } + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + if (BO->getOpcode() == BO_Comma) { + ExprResult RHS = ActOnDecltypeExpression(BO->getRHS()); + if (RHS.isInvalid()) + return ExprError(); + if (RHS.get() == BO->getRHS()) + return Owned(E); + return Owned(new (Context) BinaryOperator(BO->getLHS(), RHS.take(), + BO_Comma, BO->getType(), + BO->getValueKind(), + BO->getObjectKind(), + BO->getOperatorLoc())); + } + } + + CXXBindTemporaryExpr *TopBind = dyn_cast<CXXBindTemporaryExpr>(E); + if (TopBind) + E = TopBind->getSubExpr(); + + // Disable the special decltype handling now. + Rec.IsDecltype = false; + + // Perform the semantic checks we delayed until this point. + CallExpr *TopCall = dyn_cast<CallExpr>(E); + for (unsigned I = 0, N = Rec.DelayedDecltypeCalls.size(); I != N; ++I) { + CallExpr *Call = Rec.DelayedDecltypeCalls[I]; + if (Call == TopCall) + continue; + + if (CheckCallReturnType(Call->getCallReturnType(), + Call->getSourceRange().getBegin(), + Call, Call->getDirectCallee())) + return ExprError(); + } + + // Now all relevant types are complete, check the destructors are accessible + // and non-deleted, and annotate them on the temporaries. + for (unsigned I = 0, N = Rec.DelayedDecltypeBinds.size(); I != N; ++I) { + CXXBindTemporaryExpr *Bind = Rec.DelayedDecltypeBinds[I]; + if (Bind == TopBind) + continue; + + CXXTemporary *Temp = Bind->getTemporary(); + + CXXRecordDecl *RD = + Bind->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + CXXDestructorDecl *Destructor = LookupDestructor(RD); + Temp->setDestructor(Destructor); + + MarkFunctionReferenced(E->getExprLoc(), Destructor); + CheckDestructorAccess(E->getExprLoc(), Destructor, + PDiag(diag::err_access_dtor_temp) + << E->getType()); + DiagnoseUseOfDecl(Destructor, E->getExprLoc()); + + // We need a cleanup, but we don't need to remember the temporary. + ExprNeedsCleanups = true; + } + + // Possibly strip off the top CXXBindTemporaryExpr. + return Owned(E); +} + ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, ParsedType &ObjectType, diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index bc48f08a340..e5db60b2002 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -740,6 +740,8 @@ namespace { /// Return true on unrecoverable error. static bool checkPlaceholderForOverload(Sema &S, Expr *&E, UnbridgedCastsSet *unbridgedCasts = 0) { + S.RequireCompleteType(E->getExprLoc(), E->getType(), 0); + if (const BuiltinType *placeholder = E->getType()->getAsPlaceholderType()) { // We can't handle overloaded expressions here because overload // resolution might reasonably tweak them. diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 7e775f55e0a..58d6a22a288 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -4305,12 +4305,17 @@ QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB, const DecltypeType *T = TL.getTypePtr(); // decltype expressions are not potentially evaluated contexts - EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); + EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated, 0, + /*IsDecltype=*/ true); ExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr()); if (E.isInvalid()) return QualType(); + E = getSema().ActOnDecltypeExpression(E.take()); + if (E.isInvalid()) + return QualType(); + QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || E.get() != T->getUnderlyingExpr()) { |