aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2012-02-14 22:28:59 +0000
committerDouglas Gregor <dgregor@apple.com>2012-02-14 22:28:59 +0000
commitc6889e7ed16604c51994e1f11becf213fdc64eb3 (patch)
treecd67da6857b1e624c3c190e4a9e3648c606381fb
parent57b9c4e9d85971e20ab0dac3eadabae672c43c62 (diff)
Implement C++ core issue 974, which permits default arguments for
lambda expressions. Because these issue was pulled back from Ready status at the Kona meeting, we still emit an ExtWarn when using default arguments for lambda expressions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150519 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticGroups.td1
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--include/clang/Sema/Sema.h6
-rw-r--r--lib/Sema/SemaDeclCXX.cpp16
-rw-r--r--lib/Sema/SemaLambda.cpp49
-rw-r--r--lib/Sema/TreeTransform.h25
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp50
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp5
8 files changed, 116 insertions, 41 deletions
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index d295683ab7..5e33a8ad04 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -183,6 +183,7 @@ def : DiagGroup<"strict-overflow=5">;
def : DiagGroup<"strict-overflow">;
def InvalidOffsetof : DiagGroup<"invalid-offsetof">;
+def LambdaExtensions : DiagGroup<"lambda-extensions">;
def : DiagGroup<"strict-prototypes">;
def StrictSelector : DiagGroup<"strict-selector-match">;
def MethodDuplicate : DiagGroup<"duplicate-method-match">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index b042e2f692..0b6d774866 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4031,7 +4031,7 @@ let CategoryName = "Lambda Issue" in {
def ext_lambda_implies_void_return : ExtWarn<
"C++11 requires lambda with omitted result type to consist of a single "
"return statement">,
- InGroup<DiagGroup<"lambda-return">>;
+ InGroup<LambdaExtensions>;
def err_lambda_return_init_list : Error<
"cannot deduce lambda return type from initializer list">;
def err_lambda_capture_default_arg : Error<
@@ -4042,6 +4042,9 @@ let CategoryName = "Lambda Issue" in {
"incomplete result type %0 in lambda expression">;
def err_lambda_objc_object_result : Error<
"non-pointer Objective-C class type %0 in lambda expression result">;
+ def ext_lambda_default_arguments : ExtWarn<
+ "C++11 forbids default arguments for lambda expressions">,
+ InGroup<LambdaExtensions>;
}
def err_operator_arrow_circular : Error<
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 4554010062..1363121341 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -3515,7 +3515,8 @@ public:
CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class,
SourceRange IntroducerRange,
TypeSourceInfo *MethodType,
- SourceLocation EndLoc);
+ SourceLocation EndLoc,
+ llvm::ArrayRef<ParmVarDecl *> Params);
/// \brief Introduce the scope for a lambda expression.
sema::LambdaScopeInfo *enterLambdaScope(CXXMethodDecl *CallOperator,
@@ -3530,8 +3531,7 @@ public:
void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI);
/// \brief Introduce the lambda parameters into scope.
- void addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope,
- llvm::ArrayRef<ParmVarDecl *> Params);
+ void addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope);
/// ActOnStartOfLambdaDefinition - This is called just before we start
/// parsing the body of a lambda; it analyzes the explicit captures and
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 84063e5fd0..624dc5d1e6 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -585,11 +585,25 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
unsigned NumParams = FD->getNumParams();
unsigned p;
+ bool IsLambda = FD->getOverloadedOperator() == OO_Call &&
+ isa<CXXMethodDecl>(FD) &&
+ cast<CXXMethodDecl>(FD)->getParent()->isLambda();
+
// Find first parameter with a default argument
for (p = 0; p < NumParams; ++p) {
ParmVarDecl *Param = FD->getParamDecl(p);
- if (Param->hasDefaultArg())
+ if (Param->hasDefaultArg()) {
+ // C++11 [expr.prim.lambda]p5:
+ // [...] Default arguments (8.3.6) shall not be specified in the
+ // parameter-declaration-clause of a lambda-declarator.
+ //
+ // FIXME: Core issue 974 strikes this sentence, we only provide an
+ // extension warning.
+ if (IsLambda)
+ Diag(Param->getLocation(), diag::ext_lambda_default_arguments)
+ << Param->getDefaultArgRange();
break;
+ }
}
// C++ [dcl.fct.default]p4:
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 8b8a083a06..34ccb2d3dd 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -36,7 +36,8 @@ CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange) {
CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
SourceRange IntroducerRange,
TypeSourceInfo *MethodType,
- SourceLocation EndLoc) {
+ SourceLocation EndLoc,
+ 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
@@ -66,6 +67,19 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
// context, so that the Scope stack matches the lexical nesting.
Method->setLexicalDeclContext(Class->getDeclContext());
+ // Add parameters.
+ if (!Params.empty()) {
+ Method->setParams(Params);
+ CheckParmsForFunctionDef(const_cast<ParmVarDecl **>(Params.begin()),
+ const_cast<ParmVarDecl **>(Params.end()),
+ /*CheckParameterNames=*/false);
+
+ for (CXXMethodDecl::param_iterator P = Method->param_begin(),
+ PEnd = Method->param_end();
+ P != PEnd; ++P)
+ (*P)->setOwningFunction(Method);
+ }
+
return Method;
}
@@ -109,18 +123,11 @@ void Sema::finishLambdaExplicitCaptures(LambdaScopeInfo *LSI) {
LSI->finishedExplicitCaptures();
}
-void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope,
- llvm::ArrayRef<ParmVarDecl *> Params) {
- CallOperator->setParams(Params);
- CheckParmsForFunctionDef(const_cast<ParmVarDecl **>(Params.begin()),
- const_cast<ParmVarDecl **>(Params.end()),
- /*CheckParameterNames=*/false);
-
+void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
// Introduce our parameters into the function scope
for (unsigned p = 0, NumParams = CallOperator->getNumParams();
p < NumParams; ++p) {
ParmVarDecl *Param = CallOperator->getParamDecl(p);
- Param->setOwningFunction(CallOperator);
// If this has an identifier, add it to the scope stack.
if (CurScope && Param->getIdentifier()) {
@@ -141,6 +148,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
bool ExplicitParams = true;
bool ExplicitResultType = true;
SourceLocation EndLoc;
+ llvm::ArrayRef<ParmVarDecl *> Params;
if (ParamInfo.getNumTypeObjects() == 0) {
// C++11 [expr.prim.lambda]p4:
// If a lambda-expression does not include a lambda-declarator, it is as
@@ -166,11 +174,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (!FTI.hasMutableQualifier())
FTI.TypeQuals |= DeclSpec::TQ_const;
- // C++11 [expr.prim.lambda]p5:
- // [...] Default arguments (8.3.6) shall not be specified in the
- // parameter-declaration-clause of a lambda-declarator.
- CheckExtraCXXDefaultArguments(ParamInfo);
-
MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope);
assert(MethodTyInfo && "no type from lambda-declarator");
EndLoc = ParamInfo.getSourceRange().getEnd();
@@ -178,10 +181,18 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
ExplicitResultType
= MethodTyInfo->getType()->getAs<FunctionType>()->getResultType()
!= Context.DependentTy;
+
+ TypeLoc TL = MethodTyInfo->getTypeLoc();
+ FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
+ Params = llvm::ArrayRef<ParmVarDecl *>(Proto.getParmArray(),
+ Proto.getNumArgs());
}
CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
- MethodTyInfo, EndLoc);
+ MethodTyInfo, EndLoc, Params);
+
+ if (ExplicitParams)
+ CheckCXXDefaultArguments(Method);
// Attributes on the lambda apply to the method.
ProcessDeclAttributes(CurScope, Method, ParamInfo);
@@ -325,12 +336,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
}
finishLambdaExplicitCaptures(LSI);
- // Set the parameters on the decl, if specified.
- if (isa<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc())) {
- FunctionProtoTypeLoc Proto
- = cast<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc());
- addLambdaParameters(Method, CurScope, Proto.getParams());
- }
+ // Add lambda parameters into scope.
+ addLambdaParameters(Method, CurScope);
// Enter a new evaluation context to insulate the lambda from any
// cleanups from the enclosing full-expression.
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 4c69dd51f7..3293f7468d 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -7667,11 +7667,22 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
if (!MethodTy)
return ExprError();
+ // Transform lambda parameters.
+ bool Invalid = false;
+ llvm::SmallVector<QualType, 4> ParamTypes;
+ llvm::SmallVector<ParmVarDecl *, 4> Params;
+ if (getDerived().TransformFunctionTypeParams(E->getLocStart(),
+ E->getCallOperator()->param_begin(),
+ E->getCallOperator()->param_size(),
+ 0, ParamTypes, &Params))
+ Invalid = true;
+
// Build the call operator.
CXXMethodDecl *CallOperator
= getSema().startLambdaDefinition(Class, E->getIntroducerRange(),
MethodTy,
- E->getCallOperator()->getLocEnd());
+ E->getCallOperator()->getLocEnd(),
+ Params);
getDerived().transformAttrs(E->getCallOperator(), CallOperator);
// FIXME: Instantiation-specific.
@@ -7690,7 +7701,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
E->isMutable());
// Transform captures.
- bool Invalid = false;
bool FinishedExplicitCaptures = false;
for (LambdaExpr::capture_iterator C = E->capture_begin(),
CEnd = E->capture_end();
@@ -7766,17 +7776,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
if (!FinishedExplicitCaptures)
getSema().finishLambdaExplicitCaptures(LSI);
- // Transform lambda parameters.
- llvm::SmallVector<QualType, 4> ParamTypes;
- llvm::SmallVector<ParmVarDecl *, 4> Params;
- if (!getDerived().TransformFunctionTypeParams(E->getLocStart(),
- E->getCallOperator()->param_begin(),
- E->getCallOperator()->param_size(),
- 0, ParamTypes, &Params))
- getSema().addLambdaParameters(CallOperator, /*CurScope=*/0, Params);
- else
- Invalid = true;
-
// Enter a new evaluation context to insulate the lambda from any
// cleanups from the enclosing full-expression.
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
new file mode 100644
index 0000000000..5dac886d4d
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -Wno-lambda-extensions -verify
+
+void defargs() {
+ auto l1 = [](int i, int j = 17, int k = 18) { return i + j + k; };
+ int i1 = l1(1);
+ int i2 = l1(1, 2);
+ int i3 = l1(1, 2, 3);
+}
+
+
+void defargs_errors() {
+ auto l1 = [](int i,
+ int j = 17,
+ int k) { }; // expected-error{{missing default argument on parameter 'k'}}
+
+ auto l2 = [](int i, int j = i) {}; // expected-error{{default argument references parameter 'i'}}
+
+ int foo;
+ auto l3 = [](int i = foo) {}; // expected-error{{default argument references local variable 'foo' of enclosing function}}
+}
+
+struct NonPOD {
+ NonPOD();
+ NonPOD(const NonPOD&);
+ ~NonPOD();
+};
+
+struct NoDefaultCtor {
+ NoDefaultCtor(const NoDefaultCtor&); // expected-note{{candidate constructor}}
+ ~NoDefaultCtor();
+};
+
+template<typename T>
+void defargs_in_template_unused(T t) {
+ auto l1 = [](const T& value = T()) { };
+ l1(t);
+}
+
+template void defargs_in_template_unused(NonPOD);
+template void defargs_in_template_unused(NoDefaultCtor);
+
+template<typename T>
+void defargs_in_template_used() {
+ auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}}
+ l1(); // expected-note{{in instantiation of default function argument expression for 'operator()<NoDefaultCtor>' required here}}
+}
+
+template void defargs_in_template_used<NonPOD>();
+template void defargs_in_template_used<NoDefaultCtor>(); // expected-note{{in instantiation of function template specialization}}
+
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp
index 581dbca309..a67b5c01fd 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp
@@ -38,9 +38,10 @@ void test_quals() {
// Default arguments (8.3.6) shall not be specified in the
// parameter-declaration-clause of a lambda- declarator.
+// Note: Removed by core issue 974.
int test_default_args() {
- return [](int i = 5, // expected-error{{default arguments can only be specified for parameters in a function declaration}}
- int j = 17) { return i+j;}(5, 6); // expected-error{{default arguments can only be specified for parameters in a function declaration}}
+ return [](int i = 5, // expected-warning{{C++11 forbids default arguments for lambda expressions}}
+ int j = 17) { return i+j;}(5, 6);
}
// Any exception-specification specified on a lambda-expression