r191354 - Refactor to use C++1y 'auto' semantics directly in lambdas with no specified
Richard Smith
richard-llvm at metafoo.co.uk
Tue Sep 24 22:02:55 PDT 2013
Author: rsmith
Date: Wed Sep 25 00:02:54 2013
New Revision: 191354
URL: http://llvm.org/viewvc/llvm-project?rev=191354&view=rev
Log:
Refactor to use C++1y 'auto' semantics directly in lambdas with no specified
return type in C++1y mode. No functionality change intended. Extracted and
tweaked from a patch by Faisal Vali!
Modified:
cfe/trunk/lib/Sema/SemaLambda.cpp
cfe/trunk/lib/Sema/SemaStmt.cpp
cfe/trunk/lib/Sema/SemaType.cpp
Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=191354&r1=191353&r2=191354&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Wed Sep 25 00:02:54 2013
@@ -131,10 +131,25 @@ Sema::ExpressionEvaluationContextRecord:
}
CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
- SourceRange IntroducerRange,
- TypeSourceInfo *MethodType,
- SourceLocation EndLoc,
- ArrayRef<ParmVarDecl *> Params) {
+ SourceRange IntroducerRange,
+ TypeSourceInfo *MethodTypeInfo,
+ SourceLocation EndLoc,
+ ArrayRef<ParmVarDecl *> Params) {
+ QualType MethodType = MethodTypeInfo->getType();
+
+ // If a lambda appears in a dependent context and has an 'auto' return type,
+ // deduce it to a dependent type.
+ // FIXME: Generic lambda call operators should also get this treatment.
+ if (Class->isDependentContext()) {
+ const FunctionProtoType *FPT = MethodType->castAs<FunctionProtoType>();
+ QualType Result = FPT->getResultType();
+ if (Result->isUndeducedType()) {
+ Result = SubstAutoType(Result, Context.DependentTy);
+ MethodType = Context.getFunctionType(Result, FPT->getArgTypes(),
+ FPT->getExtProtoInfo());
+ }
+ }
+
// C++11 [expr.prim.lambda]p5:
// The closure type for a lambda-expression has a public inline function
// call operator (13.5.4) whose parameters and return type are described by
@@ -152,7 +167,7 @@ CXXMethodDecl *Sema::startLambdaDefiniti
DeclarationNameInfo(MethodName,
IntroducerRange.getBegin(),
MethodNameLoc),
- MethodType->getType(), MethodType,
+ MethodType, MethodTypeInfo,
SC_None,
/*isInline=*/true,
/*isConstExpr=*/false,
@@ -553,8 +568,17 @@ void Sema::ActOnStartOfLambdaDefinition(
/*IsVariadic=*/false, /*IsCXXMethod=*/true));
EPI.HasTrailingReturn = true;
EPI.TypeQuals |= DeclSpec::TQ_const;
- QualType MethodTy = Context.getFunctionType(Context.DependentTy, None,
- EPI);
+ // C++1y [expr.prim.lambda]:
+ // The lambda return type is 'auto', which is replaced by the
+ // trailing-return type if provided and/or deduced from 'return'
+ // statements
+ // We don't do this before C++1y, because we don't support deduced return
+ // types there.
+ QualType DefaultTypeForNoTrailingReturn =
+ getLangOpts().CPlusPlus1y ? Context.getAutoDeductType()
+ : Context.DependentTy;
+ QualType MethodTy =
+ Context.getFunctionType(DefaultTypeForNoTrailingReturn, None, EPI);
MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
ExplicitParams = false;
ExplicitResultType = false;
@@ -563,21 +587,19 @@ void Sema::ActOnStartOfLambdaDefinition(
assert(ParamInfo.isFunctionDeclarator() &&
"lambda-declarator is a function");
DeclaratorChunk::FunctionTypeInfo &FTI = ParamInfo.getFunctionTypeInfo();
-
+
// C++11 [expr.prim.lambda]p5:
// This function call operator is declared const (9.3.1) if and only if
// the lambda-expression's parameter-declaration-clause is not followed
// by mutable. It is neither virtual nor declared volatile. [...]
if (!FTI.hasMutableQualifier())
FTI.TypeQuals |= DeclSpec::TQ_const;
-
+
MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
assert(MethodTyInfo && "no type from lambda-declarator");
EndLoc = ParamInfo.getSourceRange().getEnd();
-
- ExplicitResultType
- = MethodTyInfo->getType()->getAs<FunctionType>()->getResultType()
- != Context.DependentTy;
+
+ ExplicitResultType = FTI.hasTrailingReturnType();
if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
cast<ParmVarDecl>(FTI.ArgInfo[0].Param)->getType()->isVoidType()) {
@@ -1015,8 +1037,12 @@ ExprResult Sema::ActOnLambdaExpr(SourceL
// If a lambda-expression does not include a
// trailing-return-type, it is as if the trailing-return-type
// denotes the following type:
+ //
+ // Skip for C++1y return type deduction semantics which uses
+ // different machinery.
+ // FIXME: Refactor and Merge the return type deduction machinery.
// FIXME: Assumes current resolution to core issue 975.
- if (LSI->HasImplicitReturnType) {
+ if (LSI->HasImplicitReturnType && !getLangOpts().CPlusPlus1y) {
deduceClosureReturnType(*LSI);
// - if there are no return statements in the
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=191354&r1=191353&r2=191354&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Wed Sep 25 00:02:54 2013
@@ -2478,6 +2478,14 @@ Sema::PerformMoveOrCopyInitialization(co
return Res;
}
+/// \brief Determine whether the declared return type of the specified function
+/// contains 'auto'.
+static bool hasDeducedReturnType(FunctionDecl *FD) {
+ const FunctionProtoType *FPT =
+ FD->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>();
+ return FPT->getResultType()->isUndeducedType();
+}
+
/// ActOnCapScopeReturnStmt - Utility routine to type-check return statements
/// for capturing scopes.
///
@@ -2487,27 +2495,36 @@ Sema::ActOnCapScopeReturnStmt(SourceLoca
// [expr.prim.lambda]p4 in C++11; block literals follow the same rules.
CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction());
QualType FnRetType = CurCap->ReturnType;
+ LambdaScopeInfo *CurLambda = dyn_cast<LambdaScopeInfo>(CurCap);
+
+ if (CurLambda && hasDeducedReturnType(CurLambda->CallOperator)) {
+ // In C++1y, the return type may involve 'auto'.
+ // FIXME: Blocks might have a return type of 'auto' explicitly specified.
+ FunctionDecl *FD = CurLambda->CallOperator;
+ if (CurCap->ReturnType.isNull())
+ CurCap->ReturnType = FD->getResultType();
- // For blocks/lambdas with implicit return types, we check each return
- // statement individually, and deduce the common return type when the block
- // or lambda is completed.
- if (CurCap->HasImplicitReturnType) {
- // FIXME: Fold this into the 'auto' codepath below.
+ AutoType *AT = CurCap->ReturnType->getContainedAutoType();
+ assert(AT && "lost auto type from lambda return type");
+ if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) {
+ FD->setInvalidDecl();
+ return StmtError();
+ }
+ CurCap->ReturnType = FnRetType = FD->getResultType();
+ } else if (CurCap->HasImplicitReturnType) {
+ // For blocks/lambdas with implicit return types, we check each return
+ // statement individually, and deduce the common return type when the block
+ // or lambda is completed.
+ // FIXME: Fold this into the 'auto' codepath above.
if (RetValExp && !isa<InitListExpr>(RetValExp)) {
ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp);
if (Result.isInvalid())
return StmtError();
RetValExp = Result.take();
- if (!CurContext->isDependentContext()) {
+ if (!CurContext->isDependentContext())
FnRetType = RetValExp->getType();
- // In C++11, we take the type of the expression after decay and
- // lvalue-to-rvalue conversion, so a class type can be cv-qualified.
- // In C++1y, we perform template argument deduction as if the return
- // type were 'auto', so an implicit return type is never cv-qualified.
- if (getLangOpts().CPlusPlus1y && FnRetType.hasQualifiers())
- FnRetType = FnRetType.getUnqualifiedType();
- } else
+ else
FnRetType = CurCap->ReturnType = Context.DependentTy;
} else {
if (RetValExp) {
@@ -2525,21 +2542,6 @@ Sema::ActOnCapScopeReturnStmt(SourceLoca
// make sure we provide a return type now for better error recovery.
if (CurCap->ReturnType.isNull())
CurCap->ReturnType = FnRetType;
- } else if (AutoType *AT =
- FnRetType.isNull() ? 0 : FnRetType->getContainedAutoType()) {
- // In C++1y, the return type may involve 'auto'.
- FunctionDecl *FD = cast<LambdaScopeInfo>(CurCap)->CallOperator;
- if (CurContext->isDependentContext()) {
- // C++1y [dcl.spec.auto]p12:
- // Return type deduction [...] occurs when the definition is
- // instantiated even if the function body contains a return
- // statement with a non-type-dependent operand.
- CurCap->ReturnType = FnRetType = Context.DependentTy;
- } else if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) {
- FD->setInvalidDecl();
- return StmtError();
- } else
- CurCap->ReturnType = FnRetType = FD->getResultType();
}
assert(!FnRetType.isNull());
@@ -2553,8 +2555,9 @@ Sema::ActOnCapScopeReturnStmt(SourceLoca
Diag(ReturnLoc, diag::err_return_in_captured_stmt) << CurRegion->getRegionName();
return StmtError();
} else {
- LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CurCap);
- if (LSI->CallOperator->getType()->getAs<FunctionType>()->getNoReturnAttr()){
+ assert(CurLambda && "unknown kind of captured scope");
+ if (CurLambda->CallOperator->getType()->getAs<FunctionType>()
+ ->getNoReturnAttr()) {
Diag(ReturnLoc, diag::err_noreturn_lambda_has_return_expr);
return StmtError();
}
@@ -2638,7 +2641,10 @@ bool Sema::DeduceFunctionTypeFromReturnE
if (RetExpr && isa<InitListExpr>(RetExpr)) {
// If the deduction is for a return statement and the initializer is
// a braced-init-list, the program is ill-formed.
- Diag(RetExpr->getExprLoc(), diag::err_auto_fn_return_init_list);
+ Diag(RetExpr->getExprLoc(),
+ getCurLambda() ? diag::err_lambda_return_init_list
+ : diag::err_auto_fn_return_init_list)
+ << RetExpr->getSourceRange();
return true;
}
@@ -2692,9 +2698,16 @@ bool Sema::DeduceFunctionTypeFromReturnE
AutoType *NewAT = Deduced->getContainedAutoType();
if (!FD->isDependentContext() &&
!Context.hasSameType(AT->getDeducedType(), NewAT->getDeducedType())) {
- Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
- << (AT->isDecltypeAuto() ? 1 : 0)
- << NewAT->getDeducedType() << AT->getDeducedType();
+ const LambdaScopeInfo *LambdaSI = getCurLambda();
+ if (LambdaSI && LambdaSI->HasImplicitReturnType) {
+ Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
+ << NewAT->getDeducedType() << AT->getDeducedType()
+ << true /*IsLambda*/;
+ } else {
+ Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
+ << (AT->isDecltypeAuto() ? 1 : 0)
+ << NewAT->getDeducedType() << AT->getDeducedType();
+ }
return true;
}
} else if (!FD->isInvalidDecl()) {
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=191354&r1=191353&r2=191354&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Wed Sep 25 00:02:54 2013
@@ -762,8 +762,13 @@ static QualType ConvertDeclSpecToType(Ty
// is inferred from the return statements inside the block.
// The declspec is always missing in a lambda expr context; it is either
// specified with a trailing return type or inferred.
- if (declarator.getContext() == Declarator::LambdaExprContext ||
- isOmittedBlockReturnType(declarator)) {
+ if (S.getLangOpts().CPlusPlus1y &&
+ declarator.getContext() == Declarator::LambdaExprContext) {
+ // In C++1y, a lambda's implicit return type is 'auto'.
+ Result = Context.getAutoDeductType();
+ break;
+ } else if (declarator.getContext() == Declarator::LambdaExprContext ||
+ isOmittedBlockReturnType(declarator)) {
Result = Context.DependentTy;
break;
}
More information about the cfe-commits
mailing list