summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-02-22 02:04:18 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-02-22 02:04:18 +0000
commitfd555f6b1fd950eff620e74da887dc37d919a276 (patch)
tree3c3ce70944db709410b9c1753550d399b57aae6c /clang/lib
parent3715c691b3f4e88d05ae92d7b831cfceb5865285 (diff)
downloadbcm5719-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.cpp10
-rw-r--r--clang/lib/Sema/Sema.cpp3
-rw-r--r--clang/lib/Sema/SemaExpr.cpp13
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp112
-rw-r--r--clang/lib/Sema/SemaOverload.cpp2
-rw-r--r--clang/lib/Sema/TreeTransform.h7
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()) {
OpenPOWER on IntegriCloud