[cfe-commits] r61406 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/AST/ExprCXX.h include/clang/Basic/DiagnosticKinds.def include/clang/Parse/Action.h lib/AST/StmtDumper.cpp lib/AST/Type.cpp lib/Parse/ParseDecl.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp test/SemaCXX/condition.cpp test/SemaCXX/constructor.cpp test/SemaCXX/copy-initialization.cpp test/SemaCXX/default1.cpp test/SemaCXX/default2.cpp

Douglas Gregor dgregor at apple.com
Tue Dec 23 16:01:04 PST 2008


Author: dgregor
Date: Tue Dec 23 18:01:03 2008
New Revision: 61406

URL: http://llvm.org/viewvc/llvm-project?rev=61406&view=rev
Log:
Correct the order in which we cope with end-of-class-definition
semantics and improve our handling of default arguments. Specifically,
we follow this order:

  - As soon as the see the '}' in the class definition, the class is
  complete and we add any implicit declarations (default constructor,
  copy constructor, etc.) to the class.
  - If there are any default function arguments, parse them
  - If there were any inline member function definitions, parse them

As part of this change, we now keep track of the the fact that we've
seen unparsed default function arguments within the AST. See the new
ParmVarDecl::hasUnparsedDefaultArg member. This allows us to properly
cope with calls inside default function arguments to other functions
where we're making use of the default arguments.

Made some C++ error messages regarding failed initializations more
specific. 


Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/lib/AST/StmtDumper.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/SemaCXX/condition.cpp
    cfe/trunk/test/SemaCXX/constructor.cpp
    cfe/trunk/test/SemaCXX/copy-initialization.cpp
    cfe/trunk/test/SemaCXX/default1.cpp
    cfe/trunk/test/SemaCXX/default2.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Tue Dec 23 18:01:03 2008
@@ -504,6 +504,27 @@
   Expr *getDefaultArg() { return DefaultArg; }
   void setDefaultArg(Expr *defarg) { DefaultArg = defarg; }
 
+  /// hasUnparsedDefaultArg - Determines whether this parameter has a
+  /// default argument that has not yet been parsed. This will occur
+  /// during the processing of a C++ class whose member functions have
+  /// default arguments, e.g.,
+  /// @code
+  ///   class X {
+  ///   public:
+  ///     void f(int x = 17); // x has an unparsed default argument now
+  ///   }; // x has a regular default argument now
+  /// @endcode
+  bool hasUnparsedDefaultArg() const {
+    return DefaultArg == reinterpret_cast<Expr *>(-1);
+  }
+
+  /// setUnparsedDefaultArg - Specify that this parameter has an
+  /// unparsed default argument. The argument will be replaced with a
+  /// real default argument via setDefaultArg when the class
+  /// definition enclosing the function declaration that owns this
+  /// default argument is completed.
+  void setUnparsedDefaultArg() { DefaultArg = reinterpret_cast<Expr *>(-1); }
+
   QualType getOriginalType() const;
   
   // Implement isa/cast/dyncast/etc.

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Tue Dec 23 18:01:03 2008
@@ -335,7 +335,9 @@
   // Param is the parameter whose default argument is used by this
   // expression.
   explicit CXXDefaultArgExpr(ParmVarDecl *param) 
-    : Expr(CXXDefaultArgExprClass, param->getDefaultArg()->getType()),
+    : Expr(CXXDefaultArgExprClass, 
+           param->hasUnparsedDefaultArg()? param->getType().getNonReferenceType()
+                                         : param->getDefaultArg()->getType()),
       Param(param) { }
 
   // Retrieve the parameter that the argument was created from.

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Tue Dec 23 18:01:03 2008
@@ -1352,6 +1352,10 @@
 // FIXME: %2 is an english string here.
 DIAG(err_typecheck_convert_incompatible, ERROR,
      "incompatible type %2 %1, expected %0")
+DIAG(err_cannot_initialize_decl_noname, ERROR,
+     "cannot initialize a value of type %0 with an %select{rvalue|lvalue}1 of type %2")
+DIAG(err_cannot_initialize_decl, ERROR,
+     "cannot initialize %0 with an %select{rvalue|lvalue}1 of type %2")
 DIAG(warn_incompatible_qualified_id, WARNING,
      "incompatible type %2 %1, expected %0")
 DIAG(warn_incompatible_qualified_id_operands, WARNING,

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Tue Dec 23 18:01:03 2008
@@ -734,6 +734,13 @@
                                          ExprTy *defarg) {
   }
 
+  /// ActOnParamUnparsedDefaultArgument - We've seen a default
+  /// argument for a function parameter, but we can't parse it yet
+  /// because we're inside a class definition. Note that this default
+  /// argument will be parsed later.
+  virtual void ActOnParamUnparsedDefaultArgument(DeclTy *param, 
+                                                 SourceLocation EqualLoc) { }
+
   /// ActOnParamDefaultArgumentError - Parsing or semantic analysis of
   /// the default argument for the parameter param failed.
   virtual void ActOnParamDefaultArgumentError(DeclTy *param) { }

Modified: cfe/trunk/lib/AST/StmtDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtDumper.cpp?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/lib/AST/StmtDumper.cpp (original)
+++ cfe/trunk/lib/AST/StmtDumper.cpp Tue Dec 23 18:01:03 2008
@@ -83,12 +83,14 @@
     void DumpType(QualType T) {
       fprintf(F, "'%s'", T.getAsString().c_str());
 
-      // If the type is directly a typedef, strip off typedefness to give at
-      // least one level of concreteness.
-      if (TypedefType *TDT = dyn_cast<TypedefType>(T)) {
-        QualType Simplified = 
-          TDT->LookThroughTypedefs().getQualifiedType(T.getCVRQualifiers());
-        fprintf(F, ":'%s'", Simplified.getAsString().c_str());
+      if (!T.isNull()) {
+        // If the type is directly a typedef, strip off typedefness to give at
+        // least one level of concreteness.
+        if (TypedefType *TDT = dyn_cast<TypedefType>(T)) {
+          QualType Simplified = 
+            TDT->LookThroughTypedefs().getQualifiedType(T.getCVRQualifiers());
+          fprintf(F, ":'%s'", Simplified.getAsString().c_str());
+        }
       }
     }
     void DumpStmt(const Stmt *Node) {

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Tue Dec 23 18:01:03 2008
@@ -841,7 +841,7 @@
 
 void QualType::getAsStringInternal(std::string &S) const {
   if (isNull()) {
-    S += "NULL TYPE\n";
+    S += "NULL TYPE";
     return;
   }
   

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Tue Dec 23 18:01:03 2008
@@ -1811,6 +1811,8 @@
       // ActOnParamDefaultArgument will reject the default argument in
       // C.
       if (Tok.is(tok::equal)) {
+        SourceLocation EqualLoc = Tok.getLocation();
+
         // Parse the default argument
         if (D.getContext() == Declarator::MemberContext) {
           // If we're inside a class definition, cache the tokens
@@ -1824,10 +1826,12 @@
                                     tok::semi, false)) {
             delete DefArgToks;
             DefArgToks = 0;
-          } 
+            Actions.ActOnParamDefaultArgumentError(Param);
+          } else
+            Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc);
         } else {
           // Consume the '='.
-          SourceLocation EqualLoc = ConsumeToken();
+          ConsumeToken();
         
           OwningExprResult DefArgResult(ParseAssignmentExpression());
           if (DefArgResult.isInvalid()) {

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Dec 23 18:01:03 2008
@@ -276,6 +276,8 @@
   virtual void ActOnParamDefaultArgument(DeclTy *param, 
                                          SourceLocation EqualLoc,
                                          ExprTy *defarg);
+  virtual void ActOnParamUnparsedDefaultArgument(DeclTy *param, 
+                                                 SourceLocation EqualLoc);
   virtual void ActOnParamDefaultArgumentError(DeclTy *param);
   void AddInitializerToDecl(DeclTy *dcl, ExprArg init);
   void ActOnUninitializedDecl(DeclTy *dcl);

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Dec 23 18:01:03 2008
@@ -888,9 +888,14 @@
       if (!PerformImplicitConversion(Init, DeclType, "initializing"))
         return false;
       
-      return Diag(InitLoc, diag::err_typecheck_convert_incompatible)
-        << DeclType << InitEntity << "initializing"
-        << Init->getSourceRange();
+      if (InitEntity)
+        return Diag(InitLoc, diag::err_cannot_initialize_decl)
+          << InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
+          << Init->getType() << Init->getSourceRange();
+      else
+        return Diag(InitLoc, diag::err_cannot_initialize_decl_noname)
+          << DeclType << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
+          << Init->getType() << Init->getSourceRange();
     }
 
     // C99 6.7.8p16.

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Dec 23 18:01:03 2008
@@ -126,8 +126,9 @@
   //   a declaration of a variable of the parameter type, using the
   //   copy-initialization semantics (8.5).
   Expr *DefaultArgPtr = DefaultArg.get();
-  bool DefaultInitFailed = PerformCopyInitialization(DefaultArgPtr, ParamType,
-                                                     "in default argument");
+  bool DefaultInitFailed = CheckInitializerTypes(DefaultArgPtr, ParamType,
+                                                 EqualLoc,
+                                                 Param->getDeclName());
   if (DefaultArgPtr != DefaultArg.get()) {
     DefaultArg.take();
     DefaultArg.reset(DefaultArgPtr);
@@ -147,6 +148,17 @@
   Param->setDefaultArg(DefaultArg.take());
 }
 
+/// ActOnParamUnparsedDefaultArgument - We've seen a default
+/// argument for a function parameter, but we can't parse it yet
+/// because we're inside a class definition. Note that this default
+/// argument will be parsed later.
+void Sema::ActOnParamUnparsedDefaultArgument(DeclTy *param, 
+                                             SourceLocation EqualLoc) {
+  ParmVarDecl *Param = (ParmVarDecl*)param;
+  if (Param)
+    Param->setUnparsedDefaultArg();
+}
+
 /// ActOnParamDefaultArgumentError - Parsing or semantic analysis of
 /// the default argument for the parameter param failed.
 void Sema::ActOnParamDefaultArgumentError(DeclTy *param) {
@@ -171,16 +183,16 @@
     if (chunk.Kind == DeclaratorChunk::Function) {
       for (unsigned argIdx = 0; argIdx < chunk.Fun.NumArgs; ++argIdx) {
         ParmVarDecl *Param = (ParmVarDecl *)chunk.Fun.ArgInfo[argIdx].Param;
-        if (Param->getDefaultArg()) {
-          Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
-            << Param->getDefaultArg()->getSourceRange();
-          Param->setDefaultArg(0);
-        } else if (CachedTokens *Toks 
-                     = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens) {
+        if (Param->hasUnparsedDefaultArg()) {
+          CachedTokens *Toks = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens;
           Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
             << SourceRange((*Toks)[1].getLocation(), Toks->back().getLocation());
           delete Toks;
           chunk.Fun.ArgInfo[argIdx].DefaultArgTokens = 0;
+        } else if (Param->getDefaultArg()) {
+          Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
+            << Param->getDefaultArg()->getSourceRange();
+          Param->setDefaultArg(0);
         }
       }
     }
@@ -269,7 +281,8 @@
     for (p = 0; p <= LastMissingDefaultArg; ++p) {
       ParmVarDecl *Param = FD->getParamDecl(p);
       if (Param->getDefaultArg()) {
-        delete Param->getDefaultArg();
+        if (!Param->hasUnparsedDefaultArg())
+          Param->getDefaultArg()->Destroy(Context);
         Param->setDefaultArg(0);
       }
     }
@@ -736,6 +749,7 @@
   ActOnFields(S, RLoc, TagDecl,
               (DeclTy**)FieldCollector->getCurFields(),
               FieldCollector->getCurNumFields(), LBrac, RBrac, 0);
+  AddImplicitlyDeclaredMembersToClass(cast<CXXRecordDecl>((Decl*)TagDecl));
 }
 
 /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
@@ -872,7 +886,6 @@
 void Sema::ActOnFinishCXXClassDef(DeclTy *D) {
   CXXRecordDecl *Rec = cast<CXXRecordDecl>(static_cast<Decl *>(D));
   FieldCollector->FinishClass();
-  AddImplicitlyDeclaredMembersToClass(Rec);
   PopDeclContext();
 
   // Everything, including inline method definitions, have been parsed.
@@ -901,6 +914,12 @@
 /// ActOnParamDefaultArgument event for this parameter.
 void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclTy *ParamD) {
   ParmVarDecl *Param = (ParmVarDecl*)ParamD;
+
+  // If this parameter has an unparsed default argument, clear it out
+  // to make way for the parsed default argument.
+  if (Param->hasUnparsedDefaultArg())
+    Param->setDefaultArg(0);
+
   S->AddDecl(Param);
   if (Param->getDeclName())
     IdResolver.AddDecl(Param);
@@ -1871,7 +1890,11 @@
   if (Op != OO_Call) {
     for (FunctionDecl::param_iterator Param = FnDecl->param_begin();
          Param != FnDecl->param_end(); ++Param) {
-      if (Expr *DefArg = (*Param)->getDefaultArg())
+      if ((*Param)->hasUnparsedDefaultArg())
+        return Diag((*Param)->getLocation(), 
+                    diag::err_operator_overload_default_arg)
+          << FnDecl->getDeclName();
+      else if (Expr *DefArg = (*Param)->getDefaultArg())
         return Diag((*Param)->getLocation(),
                     diag::err_operator_overload_default_arg)
           << FnDecl->getDeclName() << DefArg->getSourceRange();

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Dec 23 18:01:03 2008
@@ -1507,16 +1507,17 @@
     QualType ProtoArgType = Proto->getArgType(i);
     
     Expr *Arg;
-    if (i < NumArgs) 
+    if (i < NumArgs) {
       Arg = Args[i];
-    else 
+
+      // Pass the argument.
+      if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
+        return true;
+    } else 
+      // We already type-checked the argument, so we know it works.
       Arg = new CXXDefaultArgExpr(FDecl->getParamDecl(i));
     QualType ArgType = Arg->getType();
-    
-    // Pass the argument.
-    if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
-      return true;
-    
+        
     Call->setArg(i, Arg);
   }
   

Modified: cfe/trunk/test/SemaCXX/condition.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/condition.cpp?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/condition.cpp (original)
+++ cfe/trunk/test/SemaCXX/condition.cpp Tue Dec 23 18:01:03 2008
@@ -16,8 +16,8 @@
   for (;s;) ; // expected-error {{expression must have bool type (or be convertible to bool) ('struct S' invalid)}}
   switch (s) {} // expected-error {{statement requires expression of integer type ('struct S' invalid)}}
 
-  while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{incompatible type}} expected-error {{expression must have bool type}}
-  while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{incompatible type}} expected-error {{expression must have bool type}}
+  while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{expression must have bool type}}
+  while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{expression must have bool type}}
   switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{incompatible type}}
 
   if (int x=0) { // expected-note {{previous definition is here}}

Modified: cfe/trunk/test/SemaCXX/constructor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constructor.cpp?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/constructor.cpp (original)
+++ cfe/trunk/test/SemaCXX/constructor.cpp Tue Dec 23 18:01:03 2008
@@ -1,5 +1,4 @@
 // RUN: clang -fsyntax-only -verify %s 
-
 typedef int INT;
 
 class Foo {
@@ -37,3 +36,7 @@
   y(int);
 };
 extern y b;
+
+struct Length {
+  Length l() const { return *this; }
+};

Modified: cfe/trunk/test/SemaCXX/copy-initialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/copy-initialization.cpp?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/copy-initialization.cpp (original)
+++ cfe/trunk/test/SemaCXX/copy-initialization.cpp Tue Dec 23 18:01:03 2008
@@ -13,5 +13,5 @@
   X x1 = y; // expected-error{{no matching constructor for initialization of 'x1'; candidate is:}}
   X x2 = 0;
   X x3 = ip;
-  X x4 = fp; // expected-error{{incompatible type initializing 'x4', expected 'class X'}}
+  X x4 = fp; // expected-error{{cannot initialize 'x4' with an lvalue of type 'float *'}}
 }

Modified: cfe/trunk/test/SemaCXX/default1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/default1.cpp?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/default1.cpp (original)
+++ cfe/trunk/test/SemaCXX/default1.cpp Tue Dec 23 18:01:03 2008
@@ -26,4 +26,6 @@
   explicit Y(int);
 };
 
-void k(Y y = 17); // expected-error{{incompatible type in default argument}}
+void k(Y y = 17); // expected-error{{cannot initialize 'y' with an rvalue of type 'int'}}
+
+void kk(Y = 17); // expected-error{{cannot initialize a value of type 'struct Y' with an rvalue of type 'int'}}

Modified: cfe/trunk/test/SemaCXX/default2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/default2.cpp?rev=61406&r1=61405&r2=61406&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/default2.cpp (original)
+++ cfe/trunk/test/SemaCXX/default2.cpp Tue Dec 23 18:01:03 2008
@@ -103,8 +103,20 @@
     Z z2;    // expected-error{{no matching constructor for initialization}}
     Z z3(z);
   }
+
+  void test_Z(const Z& z) {
+    Z z2(z); // expected-error{{no matching constructor for initialization of 'z2'}}
+  }
 };
 
 void test_Z(const Z& z) {
   Z z2(z); // expected-error{{no matching constructor for initialization of 'z2'}}
 }
+
+struct ZZ {
+  void f(ZZ z = g()); // expected-error{{no matching constructor for initialization}}
+
+  static ZZ g(int = 17);
+
+  ZZ(ZZ&, int = 17); // expected-note{{candidate function}}
+};





More information about the cfe-commits mailing list