summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaLambda.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaLambda.cpp')
-rw-r--r--lib/Sema/SemaLambda.cpp316
1 files changed, 228 insertions, 88 deletions
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 6ef8d88..6414c6f 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -54,9 +54,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
SourceRange IntroducerRange,
TypeSourceInfo *MethodType,
SourceLocation EndLoc,
- llvm::ArrayRef<ParmVarDecl *> Params,
- llvm::Optional<unsigned> ManglingNumber,
- Decl *ContextDecl) {
+ llvm::ArrayRef<ParmVarDecl *> Params) {
// 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
@@ -98,64 +96,76 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
P != PEnd; ++P)
(*P)->setOwningFunction(Method);
}
-
- // If we don't already have a mangling number for this lambda expression,
- // allocate one now.
- if (!ManglingNumber) {
- ContextDecl = ExprEvalContexts.back().LambdaContextDecl;
-
- enum ContextKind {
- Normal,
- DefaultArgument,
- DataMember,
- StaticDataMember
- } Kind = Normal;
-
- // Default arguments of member function parameters that appear in a class
- // definition, as well as the initializers of data members, receive special
- // treatment. Identify them.
- if (ContextDecl) {
- if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ContextDecl)) {
- if (const DeclContext *LexicalDC
- = Param->getDeclContext()->getLexicalParent())
- if (LexicalDC->isRecord())
- Kind = DefaultArgument;
- } else if (VarDecl *Var = dyn_cast<VarDecl>(ContextDecl)) {
- if (Var->getDeclContext()->isRecord())
- Kind = StaticDataMember;
- } else if (isa<FieldDecl>(ContextDecl)) {
- Kind = DataMember;
- }
- }
-
- switch (Kind) {
- case Normal:
- if (CurContext->isDependentContext() || isInInlineFunction(CurContext))
- ManglingNumber = Context.getLambdaManglingNumber(Method);
- else
- ManglingNumber = 0;
-
- // There is no special context for this lambda.
- ContextDecl = 0;
- break;
-
- case StaticDataMember:
- if (!CurContext->isDependentContext()) {
- ManglingNumber = 0;
- ContextDecl = 0;
- break;
- }
- // Fall through to assign a mangling number.
-
- case DataMember:
- case DefaultArgument:
- ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext()
- .getManglingNumber(Method);
- break;
+
+ // Allocate a mangling number for this lambda expression, if the ABI
+ // requires one.
+ Decl *ContextDecl = ExprEvalContexts.back().LambdaContextDecl;
+
+ enum ContextKind {
+ Normal,
+ DefaultArgument,
+ DataMember,
+ StaticDataMember
+ } Kind = Normal;
+
+ // Default arguments of member function parameters that appear in a class
+ // definition, as well as the initializers of data members, receive special
+ // treatment. Identify them.
+ if (ContextDecl) {
+ if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(ContextDecl)) {
+ if (const DeclContext *LexicalDC
+ = Param->getDeclContext()->getLexicalParent())
+ if (LexicalDC->isRecord())
+ Kind = DefaultArgument;
+ } else if (VarDecl *Var = dyn_cast<VarDecl>(ContextDecl)) {
+ if (Var->getDeclContext()->isRecord())
+ Kind = StaticDataMember;
+ } else if (isa<FieldDecl>(ContextDecl)) {
+ Kind = DataMember;
}
}
- Class->setLambdaMangling(*ManglingNumber, ContextDecl);
+ // Itanium ABI [5.1.7]:
+ // In the following contexts [...] the one-definition rule requires closure
+ // types in different translation units to "correspond":
+ bool IsInNonspecializedTemplate =
+ !ActiveTemplateInstantiations.empty() || CurContext->isDependentContext();
+ unsigned ManglingNumber;
+ switch (Kind) {
+ case Normal:
+ // -- the bodies of non-exported nonspecialized template functions
+ // -- the bodies of inline functions
+ if ((IsInNonspecializedTemplate &&
+ !(ContextDecl && isa<ParmVarDecl>(ContextDecl))) ||
+ isInInlineFunction(CurContext))
+ ManglingNumber = Context.getLambdaManglingNumber(Method);
+ else
+ ManglingNumber = 0;
+
+ // There is no special context for this lambda.
+ ContextDecl = 0;
+ break;
+
+ case StaticDataMember:
+ // -- the initializers of nonspecialized static members of template classes
+ if (!IsInNonspecializedTemplate) {
+ ManglingNumber = 0;
+ ContextDecl = 0;
+ break;
+ }
+ // Fall through to assign a mangling number.
+
+ case DataMember:
+ // -- the in-class initializers of class members
+ case DefaultArgument:
+ // -- default arguments appearing in class definitions
+ ManglingNumber = ExprEvalContexts.back().getLambdaMangleContext()
+ .getManglingNumber(Method);
+ break;
+ }
+
+ Class->setLambdaMangling(ManglingNumber, ContextDecl);
+
return Method;
}
@@ -214,6 +224,141 @@ void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
}
}
+static bool checkReturnValueType(const ASTContext &Ctx, const Expr *E,
+ QualType &DeducedType,
+ QualType &AlternateType) {
+ // Handle ReturnStmts with no expressions.
+ if (!E) {
+ if (AlternateType.isNull())
+ AlternateType = Ctx.VoidTy;
+
+ return Ctx.hasSameType(DeducedType, Ctx.VoidTy);
+ }
+
+ QualType StrictType = E->getType();
+ QualType LooseType = StrictType;
+
+ // In C, enum constants have the type of their underlying integer type,
+ // not the enum. When inferring block return types, we should allow
+ // the enum type if an enum constant is used, unless the enum is
+ // anonymous (in which case there can be no variables of its type).
+ if (!Ctx.getLangOpts().CPlusPlus) {
+ const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
+ if (DRE) {
+ const Decl *D = DRE->getDecl();
+ if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
+ const EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext());
+ if (Enum->getDeclName() || Enum->getTypedefNameForAnonDecl())
+ LooseType = Ctx.getTypeDeclType(Enum);
+ }
+ }
+ }
+
+ // Special case for the first return statement we find.
+ // The return type has already been tentatively set, but we might still
+ // have an alternate type we should prefer.
+ if (AlternateType.isNull())
+ AlternateType = LooseType;
+
+ if (Ctx.hasSameType(DeducedType, StrictType)) {
+ // FIXME: The loose type is different when there are constants from two
+ // different enums. We could consider warning here.
+ if (AlternateType != Ctx.DependentTy)
+ if (!Ctx.hasSameType(AlternateType, LooseType))
+ AlternateType = Ctx.VoidTy;
+ return true;
+ }
+
+ if (Ctx.hasSameType(DeducedType, LooseType)) {
+ // Use DependentTy to signal that we're using an alternate type and may
+ // need to add casts somewhere.
+ AlternateType = Ctx.DependentTy;
+ return true;
+ }
+
+ if (Ctx.hasSameType(AlternateType, StrictType) ||
+ Ctx.hasSameType(AlternateType, LooseType)) {
+ DeducedType = AlternateType;
+ // Use DependentTy to signal that we're using an alternate type and may
+ // need to add casts somewhere.
+ AlternateType = Ctx.DependentTy;
+ return true;
+ }
+
+ return false;
+}
+
+void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
+ assert(CSI.HasImplicitReturnType);
+
+ // First case: no return statements, implicit void return type.
+ ASTContext &Ctx = getASTContext();
+ if (CSI.Returns.empty()) {
+ // It's possible there were simply no /valid/ return statements.
+ // In this case, the first one we found may have at least given us a type.
+ if (CSI.ReturnType.isNull())
+ CSI.ReturnType = Ctx.VoidTy;
+ return;
+ }
+
+ // Second case: at least one return statement has dependent type.
+ // Delay type checking until instantiation.
+ assert(!CSI.ReturnType.isNull() && "We should have a tentative return type.");
+ if (CSI.ReturnType->isDependentType())
+ return;
+
+ // Third case: only one return statement. Don't bother doing extra work!
+ SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(),
+ E = CSI.Returns.end();
+ if (I+1 == E)
+ return;
+
+ // General case: many return statements.
+ // Check that they all have compatible return types.
+ // For now, that means "identical", with an exception for enum constants.
+ // (In C, enum constants have the type of their underlying integer type,
+ // not the type of the enum. C++ uses the type of the enum.)
+ QualType AlternateType;
+
+ // We require the return types to strictly match here.
+ for (; I != E; ++I) {
+ const ReturnStmt *RS = *I;
+ const Expr *RetE = RS->getRetValue();
+ if (!checkReturnValueType(Ctx, RetE, CSI.ReturnType, AlternateType)) {
+ // FIXME: This is a poor diagnostic for ReturnStmts without expressions.
+ Diag(RS->getLocStart(),
+ diag::err_typecheck_missing_return_type_incompatible)
+ << (RetE ? RetE->getType() : Ctx.VoidTy) << CSI.ReturnType
+ << isa<LambdaScopeInfo>(CSI);
+ // Don't bother fixing up the return statements in the block if some of
+ // them are unfixable anyway.
+ AlternateType = Ctx.VoidTy;
+ // Continue iterating so that we keep emitting diagnostics.
+ }
+ }
+
+ // If our return statements turned out to be compatible, but we needed to
+ // pick a different return type, go through and fix the ones that need it.
+ if (AlternateType == Ctx.DependentTy) {
+ for (SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(),
+ E = CSI.Returns.end();
+ I != E; ++I) {
+ ReturnStmt *RS = *I;
+ Expr *RetE = RS->getRetValue();
+ if (RetE->getType() == CSI.ReturnType)
+ continue;
+
+ // Right now we only support integral fixup casts.
+ assert(CSI.ReturnType->isIntegralOrUnscopedEnumerationType());
+ assert(RetE->getType()->isIntegralOrUnscopedEnumerationType());
+ ExprResult Casted = ImpCastExprToType(RetE, CSI.ReturnType,
+ CK_IntegralCast);
+ assert(Casted.isUsable());
+ RS->setRetValue(Casted.take());
+ }
+ }
+}
+
void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
Declarator &ParamInfo,
Scope *CurScope) {
@@ -230,6 +375,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
TypeSourceInfo *MethodTyInfo;
bool ExplicitParams = true;
bool ExplicitResultType = true;
+ bool ContainsUnexpandedParameterPack = false;
SourceLocation EndLoc;
llvm::ArrayRef<ParmVarDecl *> Params;
if (ParamInfo.getNumTypeObjects() == 0) {
@@ -269,9 +415,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
Params = llvm::ArrayRef<ParmVarDecl *>(Proto.getParmArray(),
Proto.getNumArgs());
+
+ // Check for unexpanded parameter packs in the method type.
+ if (MethodTyInfo->getType()->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
}
- CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
+ CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
MethodTyInfo, EndLoc, Params);
if (ExplicitParams)
@@ -287,7 +437,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
LambdaScopeInfo *LSI
= enterLambdaScope(Method, Intro.Range, Intro.Default, ExplicitParams,
ExplicitResultType,
- (Method->getTypeQualifiers() & Qualifiers::Const) == 0);
+ !Method->isConst());
// Handle explicit captures.
SourceLocation PrevCaptureLoc
@@ -409,8 +559,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// Just ignore the ellipsis.
}
} else if (Var->isParameterPack()) {
- Diag(C->Loc, diag::err_lambda_unexpanded_pack);
- continue;
+ ContainsUnexpandedParameterPack = true;
}
TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
@@ -419,6 +568,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
}
finishLambdaExplicitCaptures(LSI);
+ LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
+
// Add lambda parameters into scope.
addLambdaParameters(Method, CurScope);
@@ -441,7 +592,10 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope,
LambdaScopeInfo *LSI = getCurLambda();
CXXRecordDecl *Class = LSI->Lambda;
Class->setInvalidDecl();
- SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end());
+ SmallVector<Decl*, 4> Fields;
+ for (RecordDecl::field_iterator i = Class->field_begin(),
+ e = Class->field_end(); i != e; ++i)
+ Fields.push_back(*i);
ActOnFields(0, Class->getLocation(), Class, Fields,
SourceLocation(), SourceLocation(), 0);
CheckCompletedCXXClass(Class);
@@ -578,6 +732,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
bool ExplicitParams;
bool ExplicitResultType;
bool LambdaExprNeedsCleanups;
+ bool ContainsUnexpandedParameterPack;
llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
{
@@ -588,6 +743,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
ExplicitParams = LSI->ExplicitParams;
ExplicitResultType = !LSI->HasImplicitReturnType;
LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups;
+ ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack;
ArrayIndexVars.swap(LSI->ArrayIndexVars);
ArrayIndexStarts.swap(LSI->ArrayIndexStarts);
@@ -639,32 +795,14 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
// denotes the following type:
// FIXME: Assumes current resolution to core issue 975.
if (LSI->HasImplicitReturnType) {
+ deduceClosureReturnType(*LSI);
+
// - if there are no return statements in the
// compound-statement, or all return statements return
// either an expression of type void or no expression or
// braced-init-list, the type void;
if (LSI->ReturnType.isNull()) {
LSI->ReturnType = Context.VoidTy;
- } else {
- // C++11 [expr.prim.lambda]p4:
- // - if the compound-statement is of the form
- //
- // { attribute-specifier-seq[opt] return expression ; }
- //
- // the type of the returned expression after
- // lvalue-to-rvalue conversion (4.1), array-to-pointer
- // conver- sion (4.2), and function-to-pointer conversion
- // (4.3);
- //
- // Since we're accepting the resolution to a post-C++11 core
- // issue with a non-trivial extension, provide a warning (by
- // default).
- CompoundStmt *CompoundBody = cast<CompoundStmt>(Body);
- if (!(CompoundBody->size() == 1 &&
- isa<ReturnStmt>(*CompoundBody->body_begin())) &&
- !Context.hasSameType(LSI->ReturnType, Context.VoidTy))
- Diag(IntroducerRange.getBegin(),
- diag::ext_lambda_implies_void_return);
}
// Create a function type with the inferred return type.
@@ -704,7 +842,10 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
addBlockPointerConversion(*this, IntroducerRange, Class, CallOperator);
// Finalize the lambda class.
- SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end());
+ SmallVector<Decl*, 4> Fields;
+ for (RecordDecl::field_iterator i = Class->field_begin(),
+ e = Class->field_end(); i != e; ++i)
+ Fields.push_back(*i);
ActOnFields(0, Class->getLocation(), Class, Fields,
SourceLocation(), SourceLocation(), 0);
CheckCompletedCXXClass(Class);
@@ -717,7 +858,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
CaptureDefault, Captures,
ExplicitParams, ExplicitResultType,
CaptureInits, ArrayIndexVars,
- ArrayIndexStarts, Body->getLocEnd());
+ ArrayIndexStarts, Body->getLocEnd(),
+ ContainsUnexpandedParameterPack);
// C++11 [expr.prim.lambda]p2:
// A lambda-expression shall not appear in an unevaluated operand
@@ -807,9 +949,7 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
// Add a fake function body to the block. IR generation is responsible
// for filling in the actual body, which cannot be expressed as an AST.
- Block->setBody(new (Context) CompoundStmt(Context, 0, 0,
- ConvLocation,
- ConvLocation));
+ Block->setBody(new (Context) CompoundStmt(ConvLocation));
// Create the block literal expression.
Expr *BuildBlock = new (Context) BlockExpr(Block, Conv->getConversionType());
OpenPOWER on IntegriCloud