]> granicus.if.org Git - clang/commitdiff
Implement C++ core issue 974, which permits default arguments for
authorDouglas Gregor <dgregor@apple.com>
Tue, 14 Feb 2012 22:28:59 +0000 (22:28 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 14 Feb 2012 22:28:59 +0000 (22:28 +0000)
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

include/clang/Basic/DiagnosticGroups.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaLambda.cpp
lib/Sema/TreeTransform.h
test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp [new file with mode: 0644]
test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp

index d295683ab70f36d0bdba5e7c248a6a5e6b1508b3..5e33a8ad049206c1376996f66d94141798db1bf7 100644 (file)
@@ -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">;
index b042e2f6928d0d7db767162ad74fdd36490dcf83..0b6d7748662fbde8d0b427a5db9e2dc4c6db3dbc 100644 (file)
@@ -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<
index 45540100628e0b92761e50edb5a64eb9e2824c7c..13631213412b3225eba88b2a5b45ab1870ddd301 100644 (file)
@@ -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 
index 84063e5fd0ff9e0c54032cf9e6800a63fdd404d3..624dc5d1e6ff087111dbbf8530101245dab3ee5d 100644 (file)
@@ -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:
index 8b8a083a0667895cce8e7ed8e2dd7dbfe04803c3..34ccb2d3dd6ab68fe7228eef3227cd4d82c48a39 100644 (file)
@@ -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.
index 4c69dd51f70a151c3bca58a9ef557637d51e119c..3293f7468d8253bc1f045457e6398083bb0fac54 100644 (file)
@@ -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 (file)
index 0000000..5dac886
--- /dev/null
@@ -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}}
+
index 581dbca309f8fc922bbd9da516017b8520e52814..a67b5c01fd582d91fd39e043a810574f23bb4587 100644 (file)
@@ -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