[cfe-commits] r62290 - in /cfe/trunk/lib/Sema: Sema.h SemaDecl.cpp

Zhongxing Xu xuzhongxing at gmail.com
Thu Jan 15 17:13:29 PST 2009


Author: zhongxingxu
Date: Thu Jan 15 19:13:29 2009
New Revision: 62290

URL: http://llvm.org/viewvc/llvm-project?rev=62290&view=rev
Log:
Extract code dealing with declarators of function type into a separate function
Sema::ActOnFunctionDeclarator().  
No functionality change.  

Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Jan 15 19:13:29 2009
@@ -277,6 +277,10 @@
   }
   DeclTy *ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup,
                           bool IsFunctionDefinition);
+  ScopedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
+                                      QualType R, ScopedDecl *LastDeclarator,
+                                      Decl* PreDecl, bool IsFunctionDefinition,
+                                      bool& InvalidDecl);
   virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D);
   virtual void ActOnParamDefaultArgument(DeclTy *param, 
                                          SourceLocation EqualLoc,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jan 15 19:13:29 2009
@@ -1325,294 +1325,8 @@
       }
     }
   } else if (R.getTypePtr()->isFunctionType()) {
-    FunctionDecl::StorageClass SC = FunctionDecl::None;
-    switch (D.getDeclSpec().getStorageClassSpec()) {
-      default: assert(0 && "Unknown storage class!");
-      case DeclSpec::SCS_auto:
-      case DeclSpec::SCS_register:
-      case DeclSpec::SCS_mutable:
-        Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_func);
-        InvalidDecl = true;
-        break;
-      case DeclSpec::SCS_unspecified: SC = FunctionDecl::None; break;
-      case DeclSpec::SCS_extern:      SC = FunctionDecl::Extern; break;
-      case DeclSpec::SCS_static:      SC = FunctionDecl::Static; break;
-      case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break;
-    }
-
-    bool isInline = D.getDeclSpec().isInlineSpecified();
-    // bool isVirtual = D.getDeclSpec().isVirtualSpecified();
-    bool isExplicit = D.getDeclSpec().isExplicitSpecified();
-
-    FunctionDecl *NewFD;
-    if (D.getKind() == Declarator::DK_Constructor) {
-      // This is a C++ constructor declaration.
-      assert(DC->isRecord() &&
-             "Constructors can only be declared in a member context");
-
-      InvalidDecl = InvalidDecl || CheckConstructorDeclarator(D, R, SC);
-
-      // Create the new declaration
-      NewFD = CXXConstructorDecl::Create(Context, 
-                                         cast<CXXRecordDecl>(DC),
-                                         D.getIdentifierLoc(), Name, R,
-                                         isExplicit, isInline,
-                                         /*isImplicitlyDeclared=*/false);
-
-      if (InvalidDecl)
-        NewFD->setInvalidDecl();
-    } else if (D.getKind() == Declarator::DK_Destructor) {
-      // This is a C++ destructor declaration.
-      if (DC->isRecord()) {
-        InvalidDecl = InvalidDecl || CheckDestructorDeclarator(D, R, SC);
-
-        NewFD = CXXDestructorDecl::Create(Context,
-                                          cast<CXXRecordDecl>(DC),
-                                          D.getIdentifierLoc(), Name, R, 
-                                          isInline,
-                                          /*isImplicitlyDeclared=*/false);
-
-        if (InvalidDecl)
-          NewFD->setInvalidDecl();
-      } else {
-        Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
-
-        // Create a FunctionDecl to satisfy the function definition parsing
-        // code path.
-        NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(),
-                                     Name, R, SC, isInline, LastDeclarator,
-                                     // FIXME: Move to DeclGroup...
-                                   D.getDeclSpec().getSourceRange().getBegin());
-        InvalidDecl = true;
-        NewFD->setInvalidDecl();
-      }
-    } else if (D.getKind() == Declarator::DK_Conversion) {
-      if (!DC->isRecord()) {
-        Diag(D.getIdentifierLoc(),
-             diag::err_conv_function_not_member);
-        return 0;
-      } else {
-        InvalidDecl = InvalidDecl || CheckConversionDeclarator(D, R, SC);
-
-        NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC),
-                                          D.getIdentifierLoc(), Name, R,
-                                          isInline, isExplicit);
-        
-        if (InvalidDecl)
-          NewFD->setInvalidDecl();
-      }
-    } else if (DC->isRecord()) {
-      // This is a C++ method declaration.
-      NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
-                                    D.getIdentifierLoc(), Name, R,
-                                    (SC == FunctionDecl::Static), isInline,
-                                    LastDeclarator);
-    } else {
-      NewFD = FunctionDecl::Create(Context, DC,
-                                   D.getIdentifierLoc(),
-                                   Name, R, SC, isInline, LastDeclarator,
-                                   // FIXME: Move to DeclGroup...
-                                   D.getDeclSpec().getSourceRange().getBegin());
-    }
-
-    // Set the lexical context. If the declarator has a C++
-    // scope specifier, the lexical context will be different
-    // from the semantic context.
-    NewFD->setLexicalDeclContext(CurContext);
-
-    // Handle GNU asm-label extension (encoded as an attribute).
-    if (Expr *E = (Expr*) D.getAsmLabel()) {
-      // The parser guarantees this is a string.
-      StringLiteral *SE = cast<StringLiteral>(E);  
-      NewFD->addAttr(new AsmLabelAttr(std::string(SE->getStrData(),
-                                                  SE->getByteLength())));
-    }
-
-    // Copy the parameter declarations from the declarator D to
-    // the function declaration NewFD, if they are available.
-    if (D.getNumTypeObjects() > 0) {
-      DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
-
-      // Create Decl objects for each parameter, adding them to the
-      // FunctionDecl.
-      llvm::SmallVector<ParmVarDecl*, 16> Params;
-  
-      // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs
-      // function that takes no arguments, not a function that takes a
-      // single void argument.
-      // We let through "const void" here because Sema::GetTypeForDeclarator
-      // already checks for that case.
-      if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
-          FTI.ArgInfo[0].Param &&
-          ((ParmVarDecl*)FTI.ArgInfo[0].Param)->getType()->isVoidType()) {
-        // empty arg list, don't push any params.
-        ParmVarDecl *Param = (ParmVarDecl*)FTI.ArgInfo[0].Param;
-
-        // In C++, the empty parameter-type-list must be spelled "void"; a
-        // typedef of void is not permitted.
-        if (getLangOptions().CPlusPlus &&
-            Param->getType().getUnqualifiedType() != Context.VoidTy) {
-          Diag(Param->getLocation(), diag::ext_param_typedef_of_void);
-        }
-      } else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) {
-        for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
-          Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param);
-      }
-  
-      NewFD->setParams(Context, &Params[0], Params.size());
-    } else if (R->getAsTypedefType()) {
-      // When we're declaring a function with a typedef, as in the
-      // following example, we'll need to synthesize (unnamed)
-      // parameters for use in the declaration.
-      //
-      // @code
-      // typedef void fn(int);
-      // fn f;
-      // @endcode
-      const FunctionTypeProto *FT = R->getAsFunctionTypeProto();
-      if (!FT) {
-        // This is a typedef of a function with no prototype, so we
-        // don't need to do anything.
-      } else if ((FT->getNumArgs() == 0) ||
-          (FT->getNumArgs() == 1 && !FT->isVariadic() &&
-           FT->getArgType(0)->isVoidType())) {
-        // This is a zero-argument function. We don't need to do anything.
-      } else {
-        // Synthesize a parameter for each argument type.
-        llvm::SmallVector<ParmVarDecl*, 16> Params;
-        for (FunctionTypeProto::arg_type_iterator ArgType = FT->arg_type_begin();
-             ArgType != FT->arg_type_end(); ++ArgType) {
-          Params.push_back(ParmVarDecl::Create(Context, DC,
-                                               SourceLocation(), 0,
-                                               *ArgType, VarDecl::None,
-                                               0, 0));
-        }
-
-        NewFD->setParams(Context, &Params[0], Params.size());
-      }
-    }
-
-    if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))
-      InvalidDecl = InvalidDecl || CheckConstructor(Constructor);
-    else if (isa<CXXDestructorDecl>(NewFD)) {
-      CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent());
-      Record->setUserDeclaredDestructor(true);
-      // C++ [class]p4: A POD-struct is an aggregate class that has [...] no
-      // user-defined destructor.
-      Record->setPOD(false);
-    } else if (CXXConversionDecl *Conversion =
-               dyn_cast<CXXConversionDecl>(NewFD))
-      ActOnConversionDeclarator(Conversion);
-
-    // Extra checking for C++ overloaded operators (C++ [over.oper]).
-    if (NewFD->isOverloadedOperator() &&
-        CheckOverloadedOperatorDeclaration(NewFD))
-      NewFD->setInvalidDecl();
-    
-    // Merge the decl with the existing one if appropriate. Since C functions
-    // are in a flat namespace, make sure we consider decls in outer scopes.
-    if (PrevDecl &&
-        (!getLangOptions().CPlusPlus||isDeclInScope(PrevDecl, DC, S))) {
-      bool Redeclaration = false;
-
-      // If C++, determine whether NewFD is an overload of PrevDecl or
-      // a declaration that requires merging. If it's an overload,
-      // there's no more work to do here; we'll just add the new
-      // function to the scope.
-      OverloadedFunctionDecl::function_iterator MatchedDecl;
-      if (!getLangOptions().CPlusPlus ||
-          !IsOverload(NewFD, PrevDecl, MatchedDecl)) {
-        Decl *OldDecl = PrevDecl;
-
-        // If PrevDecl was an overloaded function, extract the
-        // FunctionDecl that matched.
-        if (isa<OverloadedFunctionDecl>(PrevDecl))
-          OldDecl = *MatchedDecl;
-
-        // NewFD and PrevDecl represent declarations that need to be
-        // merged. 
-        NewFD = MergeFunctionDecl(NewFD, OldDecl, Redeclaration);
-
-        if (NewFD == 0) return 0;
-        if (Redeclaration) {
-          NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
-
-          // An out-of-line member function declaration must also be a
-          // definition (C++ [dcl.meaning]p1).
-          if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
-              !InvalidDecl) {
-            Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
-              << D.getCXXScopeSpec().getRange();
-            NewFD->setInvalidDecl();
-          }
-        }
-      }
-
-      if (!Redeclaration && D.getCXXScopeSpec().isSet()) {
-        // The user tried to provide an out-of-line definition for a
-        // member function, but there was no such member function
-        // declared (C++ [class.mfct]p2). For example:
-        // 
-        // class X {
-        //   void f() const;
-        // }; 
-        //
-        // void X::f() { } // ill-formed
-        //
-        // Complain about this problem, and attempt to suggest close
-        // matches (e.g., those that differ only in cv-qualifiers and
-        // whether the parameter types are references).
-        Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
-          << cast<CXXRecordDecl>(DC)->getDeclName() 
-          << D.getCXXScopeSpec().getRange();
-        InvalidDecl = true;
-        
-        PrevDecl = LookupDecl(Name, Decl::IDNS_Ordinary, S, DC);
-        if (!PrevDecl) {
-          // Nothing to suggest.
-        } else if (OverloadedFunctionDecl *Ovl 
-                   = dyn_cast<OverloadedFunctionDecl>(PrevDecl)) {
-          for (OverloadedFunctionDecl::function_iterator 
-                 Func = Ovl->function_begin(),
-                 FuncEnd = Ovl->function_end();
-               Func != FuncEnd; ++Func) {
-            if (isNearlyMatchingMemberFunction(Context, *Func, NewFD))
-              Diag((*Func)->getLocation(), diag::note_member_def_close_match);
-            
-          }
-        } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(PrevDecl)) {
-          // Suggest this no matter how mismatched it is; it's the only
-          // thing we have.
-          unsigned diag;
-          if (isNearlyMatchingMemberFunction(Context, Method, NewFD))
-            diag = diag::note_member_def_close_match;
-          else if (Method->getBody())
-            diag = diag::note_previous_definition;
-          else
-            diag = diag::note_previous_declaration;
-          Diag(Method->getLocation(), diag);
-        }
-        
-        PrevDecl = 0;
-      }
-    }
-    // Handle attributes. We need to have merged decls when handling attributes
-    // (for example to check for conflicts, etc).
-    ProcessDeclAttributes(NewFD, D);
-    New = NewFD;
-
-    if (getLangOptions().CPlusPlus) {
-      // In C++, check default arguments now that we have merged decls.
-      CheckCXXDefaultArguments(NewFD);
-
-      // An out-of-line member function declaration must also be a
-      // definition (C++ [dcl.meaning]p1).
-      if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() && !InvalidDecl) {
-        Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
-          << D.getCXXScopeSpec().getRange();
-        InvalidDecl = true;
-      }
-    }
+    New = ActOnFunctionDeclarator(S, D, DC, R, LastDeclarator, PrevDecl, 
+                                  IsFunctionDefinition, InvalidDecl);
   } else {
     // Check that there are no default arguments (C++ only).
     if (getLangOptions().CPlusPlus)
@@ -1714,6 +1428,9 @@
     }
     New = NewVD;
   }
+
+  if (New == 0)
+    return 0;
   
   // Set the lexical context. If the declarator has a C++ scope specifier, the
   // lexical context will be different from the semantic context.
@@ -1729,6 +1446,304 @@
   return New;
 }
 
+ScopedDecl* 
+Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
+                              QualType R, ScopedDecl *LastDeclarator,
+                              Decl* PrevDecl, bool IsFunctionDefinition,
+                              bool& InvalidDecl) {
+  assert(R.getTypePtr()->isFunctionType());
+
+  DeclarationName Name = GetNameForDeclarator(D);
+  FunctionDecl::StorageClass SC = FunctionDecl::None;
+  switch (D.getDeclSpec().getStorageClassSpec()) {
+  default: assert(0 && "Unknown storage class!");
+  case DeclSpec::SCS_auto:
+  case DeclSpec::SCS_register:
+  case DeclSpec::SCS_mutable:
+    Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_func);
+    InvalidDecl = true;
+    break;
+  case DeclSpec::SCS_unspecified: SC = FunctionDecl::None; break;
+  case DeclSpec::SCS_extern:      SC = FunctionDecl::Extern; break;
+  case DeclSpec::SCS_static:      SC = FunctionDecl::Static; break;
+  case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break;
+  }
+
+  bool isInline = D.getDeclSpec().isInlineSpecified();
+  // bool isVirtual = D.getDeclSpec().isVirtualSpecified();
+  bool isExplicit = D.getDeclSpec().isExplicitSpecified();
+
+  FunctionDecl *NewFD;
+  if (D.getKind() == Declarator::DK_Constructor) {
+    // This is a C++ constructor declaration.
+    assert(DC->isRecord() &&
+           "Constructors can only be declared in a member context");
+
+    InvalidDecl = InvalidDecl || CheckConstructorDeclarator(D, R, SC);
+
+    // Create the new declaration
+    NewFD = CXXConstructorDecl::Create(Context, 
+                                       cast<CXXRecordDecl>(DC),
+                                       D.getIdentifierLoc(), Name, R,
+                                       isExplicit, isInline,
+                                       /*isImplicitlyDeclared=*/false);
+
+    if (InvalidDecl)
+      NewFD->setInvalidDecl();
+  } else if (D.getKind() == Declarator::DK_Destructor) {
+    // This is a C++ destructor declaration.
+    if (DC->isRecord()) {
+      InvalidDecl = InvalidDecl || CheckDestructorDeclarator(D, R, SC);
+
+      NewFD = CXXDestructorDecl::Create(Context,
+                                        cast<CXXRecordDecl>(DC),
+                                        D.getIdentifierLoc(), Name, R, 
+                                        isInline,
+                                        /*isImplicitlyDeclared=*/false);
+
+      if (InvalidDecl)
+        NewFD->setInvalidDecl();
+    } else {
+      Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
+
+      // Create a FunctionDecl to satisfy the function definition parsing
+      // code path.
+      NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(),
+                                   Name, R, SC, isInline, LastDeclarator,
+                                   // FIXME: Move to DeclGroup...
+                                   D.getDeclSpec().getSourceRange().getBegin());
+      InvalidDecl = true;
+      NewFD->setInvalidDecl();
+    }
+  } else if (D.getKind() == Declarator::DK_Conversion) {
+    if (!DC->isRecord()) {
+      Diag(D.getIdentifierLoc(),
+           diag::err_conv_function_not_member);
+      return 0;
+    } else {
+      InvalidDecl = InvalidDecl || CheckConversionDeclarator(D, R, SC);
+
+      NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC),
+                                        D.getIdentifierLoc(), Name, R,
+                                        isInline, isExplicit);
+        
+      if (InvalidDecl)
+        NewFD->setInvalidDecl();
+    }
+  } else if (DC->isRecord()) {
+    // This is a C++ method declaration.
+    NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
+                                  D.getIdentifierLoc(), Name, R,
+                                  (SC == FunctionDecl::Static), isInline,
+                                  LastDeclarator);
+  } else {
+    NewFD = FunctionDecl::Create(Context, DC,
+                                 D.getIdentifierLoc(),
+                                 Name, R, SC, isInline, LastDeclarator,
+                                 // FIXME: Move to DeclGroup...
+                                 D.getDeclSpec().getSourceRange().getBegin());
+  }
+
+  // Set the lexical context. If the declarator has a C++
+  // scope specifier, the lexical context will be different
+  // from the semantic context.
+  NewFD->setLexicalDeclContext(CurContext);
+
+  // Handle GNU asm-label extension (encoded as an attribute).
+  if (Expr *E = (Expr*) D.getAsmLabel()) {
+    // The parser guarantees this is a string.
+    StringLiteral *SE = cast<StringLiteral>(E);  
+    NewFD->addAttr(new AsmLabelAttr(std::string(SE->getStrData(),
+                                                SE->getByteLength())));
+  }
+
+  // Copy the parameter declarations from the declarator D to
+  // the function declaration NewFD, if they are available.
+  if (D.getNumTypeObjects() > 0) {
+    DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+
+    // Create Decl objects for each parameter, adding them to the
+    // FunctionDecl.
+    llvm::SmallVector<ParmVarDecl*, 16> Params;
+  
+    // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs
+    // function that takes no arguments, not a function that takes a
+    // single void argument.
+    // We let through "const void" here because Sema::GetTypeForDeclarator
+    // already checks for that case.
+    if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
+        FTI.ArgInfo[0].Param &&
+        ((ParmVarDecl*)FTI.ArgInfo[0].Param)->getType()->isVoidType()) {
+      // empty arg list, don't push any params.
+      ParmVarDecl *Param = (ParmVarDecl*)FTI.ArgInfo[0].Param;
+
+      // In C++, the empty parameter-type-list must be spelled "void"; a
+      // typedef of void is not permitted.
+      if (getLangOptions().CPlusPlus &&
+          Param->getType().getUnqualifiedType() != Context.VoidTy) {
+        Diag(Param->getLocation(), diag::ext_param_typedef_of_void);
+      }
+    } else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) {
+      for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
+        Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param);
+    }
+  
+    NewFD->setParams(Context, &Params[0], Params.size());
+  } else if (R->getAsTypedefType()) {
+    // When we're declaring a function with a typedef, as in the
+    // following example, we'll need to synthesize (unnamed)
+    // parameters for use in the declaration.
+    //
+    // @code
+    // typedef void fn(int);
+    // fn f;
+    // @endcode
+    const FunctionTypeProto *FT = R->getAsFunctionTypeProto();
+    if (!FT) {
+      // This is a typedef of a function with no prototype, so we
+      // don't need to do anything.
+    } else if ((FT->getNumArgs() == 0) ||
+               (FT->getNumArgs() == 1 && !FT->isVariadic() &&
+                FT->getArgType(0)->isVoidType())) {
+      // This is a zero-argument function. We don't need to do anything.
+    } else {
+      // Synthesize a parameter for each argument type.
+      llvm::SmallVector<ParmVarDecl*, 16> Params;
+      for (FunctionTypeProto::arg_type_iterator ArgType = FT->arg_type_begin();
+           ArgType != FT->arg_type_end(); ++ArgType) {
+        Params.push_back(ParmVarDecl::Create(Context, DC,
+                                             SourceLocation(), 0,
+                                             *ArgType, VarDecl::None,
+                                             0, 0));
+      }
+
+      NewFD->setParams(Context, &Params[0], Params.size());
+    }
+  }
+
+  if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))
+    InvalidDecl = InvalidDecl || CheckConstructor(Constructor);
+  else if (isa<CXXDestructorDecl>(NewFD)) {
+    CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent());
+    Record->setUserDeclaredDestructor(true);
+    // C++ [class]p4: A POD-struct is an aggregate class that has [...] no
+    // user-defined destructor.
+    Record->setPOD(false);
+  } else if (CXXConversionDecl *Conversion =
+             dyn_cast<CXXConversionDecl>(NewFD))
+    ActOnConversionDeclarator(Conversion);
+
+  // Extra checking for C++ overloaded operators (C++ [over.oper]).
+  if (NewFD->isOverloadedOperator() &&
+      CheckOverloadedOperatorDeclaration(NewFD))
+    NewFD->setInvalidDecl();
+    
+  // Merge the decl with the existing one if appropriate. Since C functions
+  // are in a flat namespace, make sure we consider decls in outer scopes.
+  if (PrevDecl &&
+      (!getLangOptions().CPlusPlus||isDeclInScope(PrevDecl, DC, S))) {
+    bool Redeclaration = false;
+
+    // If C++, determine whether NewFD is an overload of PrevDecl or
+    // a declaration that requires merging. If it's an overload,
+    // there's no more work to do here; we'll just add the new
+    // function to the scope.
+    OverloadedFunctionDecl::function_iterator MatchedDecl;
+    if (!getLangOptions().CPlusPlus ||
+        !IsOverload(NewFD, PrevDecl, MatchedDecl)) {
+      Decl *OldDecl = PrevDecl;
+
+      // If PrevDecl was an overloaded function, extract the
+      // FunctionDecl that matched.
+      if (isa<OverloadedFunctionDecl>(PrevDecl))
+        OldDecl = *MatchedDecl;
+
+      // NewFD and PrevDecl represent declarations that need to be
+      // merged. 
+      NewFD = MergeFunctionDecl(NewFD, OldDecl, Redeclaration);
+
+      if (NewFD == 0) return 0;
+      if (Redeclaration) {
+        NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
+
+        // An out-of-line member function declaration must also be a
+        // definition (C++ [dcl.meaning]p1).
+        if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
+            !InvalidDecl) {
+          Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
+            << D.getCXXScopeSpec().getRange();
+          NewFD->setInvalidDecl();
+        }
+      }
+    }
+
+    if (!Redeclaration && D.getCXXScopeSpec().isSet()) {
+      // The user tried to provide an out-of-line definition for a
+      // member function, but there was no such member function
+      // declared (C++ [class.mfct]p2). For example:
+      // 
+      // class X {
+      //   void f() const;
+      // }; 
+      //
+      // void X::f() { } // ill-formed
+      //
+      // Complain about this problem, and attempt to suggest close
+      // matches (e.g., those that differ only in cv-qualifiers and
+      // whether the parameter types are references).
+      Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
+        << cast<CXXRecordDecl>(DC)->getDeclName() 
+        << D.getCXXScopeSpec().getRange();
+      InvalidDecl = true;
+        
+      PrevDecl = LookupDecl(Name, Decl::IDNS_Ordinary, S, DC);
+      if (!PrevDecl) {
+        // Nothing to suggest.
+      } else if (OverloadedFunctionDecl *Ovl 
+                 = dyn_cast<OverloadedFunctionDecl>(PrevDecl)) {
+        for (OverloadedFunctionDecl::function_iterator 
+               Func = Ovl->function_begin(),
+               FuncEnd = Ovl->function_end();
+             Func != FuncEnd; ++Func) {
+          if (isNearlyMatchingMemberFunction(Context, *Func, NewFD))
+            Diag((*Func)->getLocation(), diag::note_member_def_close_match);
+            
+        }
+      } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(PrevDecl)) {
+        // Suggest this no matter how mismatched it is; it's the only
+        // thing we have.
+        unsigned diag;
+        if (isNearlyMatchingMemberFunction(Context, Method, NewFD))
+          diag = diag::note_member_def_close_match;
+        else if (Method->getBody())
+          diag = diag::note_previous_definition;
+        else
+          diag = diag::note_previous_declaration;
+        Diag(Method->getLocation(), diag);
+      }
+        
+      PrevDecl = 0;
+    }
+  }
+  // Handle attributes. We need to have merged decls when handling attributes
+  // (for example to check for conflicts, etc).
+  ProcessDeclAttributes(NewFD, D);
+
+  if (getLangOptions().CPlusPlus) {
+    // In C++, check default arguments now that we have merged decls.
+    CheckCXXDefaultArguments(NewFD);
+
+    // An out-of-line member function declaration must also be a
+    // definition (C++ [dcl.meaning]p1).
+    if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() && !InvalidDecl) {
+      Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
+        << D.getCXXScopeSpec().getRange();
+      InvalidDecl = true;
+    }
+  }
+  return NewFD;
+}
+
 void Sema::InitializerElementNotConstant(const Expr *Init) {
   Diag(Init->getExprLoc(), diag::err_init_element_not_constant)
     << Init->getSourceRange();





More information about the cfe-commits mailing list