[cfe-commits] r65360 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/Basic/DiagnosticSemaKinds.def lib/AST/Decl.cpp lib/CodeGen/Mangle.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp test/CodeGen/linkage-redecl.c test/Sema/function-redecl.c test/Sema/function.c test/Sema/nested-redef.c test/SemaCXX/function-redecl.cpp

Douglas Gregor dgregor at apple.com
Mon Feb 23 17:23:02 PST 2009


Author: dgregor
Date: Mon Feb 23 19:23:02 2009
New Revision: 65360

URL: http://llvm.org/viewvc/llvm-project?rev=65360&view=rev
Log:
Improve merging of function declarations. Specifically:

  - When we are declaring a function in local scope, we can merge with
    a visible declaration from an outer scope if that declaration
    refers to an entity with linkage. This behavior now works in C++
    and properly ignores entities without linkage.
  - Diagnose the use of "static" on a function declaration in local
    scope.
  - Diagnose the declaration of a static function after a non-static
    declaration of the same function.
  - Propagate the storage specifier to a function declaration from a
    prior declaration (PR3425)
  - Don't name-mangle "main"


Added:
    cfe/trunk/test/CodeGen/linkage-redecl.c
    cfe/trunk/test/SemaCXX/function-redecl.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/CodeGen/Mangle.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/Sema/function-redecl.c
    cfe/trunk/test/Sema/function.c
    cfe/trunk/test/Sema/nested-redef.c

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

==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Mon Feb 23 19:23:02 2009
@@ -64,10 +64,7 @@
 
 protected:
   NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N)
-    : Decl(DK, DC, L), Name(N) {}
-  
-  NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
-    : Decl(DK, DC, L), Name(Id) {}
+    : Decl(DK, DC, L), Name(N) { }
 
 public:
   /// getIdentifier - Get the identifier that names this declaration,
@@ -614,6 +611,10 @@
   bool isDeleted() const { return IsDeleted; }
   void setDeleted() { IsDeleted = true; }
 
+  /// \brief Determines whether this is a function "main", which is
+  /// the entry point into an executable program.
+  bool isMain() const;
+
   /// getPreviousDeclaration - Return the previous declaration of this
   /// function.
   const FunctionDecl *getPreviousDeclaration() const {
@@ -658,8 +659,10 @@
     return getType()->getAsFunctionType()->getResultType();
   }
   StorageClass getStorageClass() const { return StorageClass(SClass); }
+  void setStorageClass(StorageClass SC) { SClass = SC; }
+
   bool isInline() const { return IsInline; }
- 
+
   /// isOverloadedOperator - Whether this function declaration
   /// represents an C++ overloaded operator, e.g., "operator+".
   bool isOverloadedOperator() const { 

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

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Mon Feb 23 19:23:02 2009
@@ -839,6 +839,8 @@
      "illegal storage class on file-scoped variable")
 DIAG(err_typecheck_sclass_func, ERROR,
      "illegal storage class on function")
+DIAG(err_static_block_func, ERROR,
+     "function declared in block scope cannot have 'static' storage class")
 DIAG(err_typecheck_address_of, ERROR,
      "address of %0 requested")
 DIAG(err_typecheck_invalid_lvalue_addrof, ERROR,

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

==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Mon Feb 23 19:23:02 2009
@@ -255,6 +255,11 @@
   return 0;
 }
 
+bool FunctionDecl::isMain() const {
+  return getDeclContext()->getLookupContext()->isTranslationUnit() &&
+    getIdentifier() && getIdentifier()->isStr("main");
+}
+
 /// \brief Returns a value indicating whether this function
 /// corresponds to a builtin function.
 ///

Modified: cfe/trunk/lib/CodeGen/Mangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/Mangle.cpp?rev=65360&r1=65359&r2=65360&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/Mangle.cpp (original)
+++ cfe/trunk/lib/CodeGen/Mangle.cpp Mon Feb 23 19:23:02 2009
@@ -70,7 +70,7 @@
     else if (Context.getSourceManager().getFileCharacteristic(FD->getLocation())
           == SrcMgr::C_ExternCSystem)
       RequiresMangling = false;
-    else if (Context.getLangOptions().CPlusPlus) {
+    else if (Context.getLangOptions().CPlusPlus && !FD->isMain()) {
       // C++ requires name mangling, unless we're in a C linkage
       // specification.
       RequiresMangling = true;

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Feb 23 19:23:02 2009
@@ -265,7 +265,8 @@
                                      bool &Redeclaration);
   NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
                                      QualType R, Decl *LastDeclarator,
-                                     Decl* PrevDecl, bool IsFunctionDefinition,
+                                     NamedDecl* PrevDecl, 
+                                     bool IsFunctionDefinition,
                                      bool& InvalidDecl, bool &Redeclaration);
   virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D);
   virtual void ActOnParamDefaultArgument(DeclTy *param, 
@@ -374,6 +375,7 @@
                                 Decl *LastDecl);
   bool MergeTypeDefDecl(TypedefDecl *New, Decl *Old);
   bool MergeFunctionDecl(FunctionDecl *New, Decl *Old);
+  bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old);
   bool MergeVarDecl(VarDecl *New, Decl *Old);
   bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old);
   void CheckForFileScopedRedefinitions(Scope *S, VarDecl *VD);

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Feb 23 19:23:02 2009
@@ -210,7 +210,7 @@
                      IdResolver.end(),
                      std::bind1st(std::mem_fun(&NamedDecl::declarationReplaces),
                                   FD));
-    if (Redecl != IdResolver.end()) {
+    if (Redecl != IdResolver.end() && S->isDeclScope(*Redecl)) {
       // There is already a declaration of a function on our
       // IdResolver chain. Replace it with this declaration.
       S->RemoveDecl(*Redecl);
@@ -537,6 +537,15 @@
   QualType OldQType = Context.getCanonicalType(Old->getType());
   QualType NewQType = Context.getCanonicalType(New->getType());
   
+  if (!isa<CXXMethodDecl>(New) && !isa<CXXMethodDecl>(Old) &&
+      New->getStorageClass() == FunctionDecl::Static &&
+      Old->getStorageClass() != FunctionDecl::Static) {
+    Diag(New->getLocation(), diag::err_static_non_static)
+      << New;
+    Diag(Old->getLocation(), PrevDiag);
+    return true;
+  }
+
   if (getLangOptions().CPlusPlus) {
     // (C++98 13.1p2):
     //   Certain function declarations cannot be overloaded:
@@ -588,16 +597,8 @@
     // (C++98 8.3.5p3):
     //   All declarations for a function shall agree exactly in both the
     //   return type and the parameter-type-list.
-    if (OldQType == NewQType) {
-      // We have a redeclaration.
-      MergeAttributes(New, Old);
-
-      // Merge the "deleted" flag.
-      if (Old->isDeleted())
-        New->setDeleted();
-
-      return MergeCXXFunctionDecl(New, Old);
-    } 
+    if (OldQType == NewQType)
+      return MergeCompatibleFunctionDecls(New, Old);
 
     // Fall through for conflicting redeclarations and redefinitions.
   }
@@ -639,13 +640,7 @@
 
     }
 
-    MergeAttributes(New, Old);
-
-    // Merge the "deleted" flag.
-    if (Old->isDeleted())
-      New->setDeleted();
-    
-    return false;
+    return MergeCompatibleFunctionDecls(New, Old);
   }
 
   // A function that has already been declared has been redeclared or defined
@@ -671,6 +666,38 @@
   return true;
 }
 
+/// \brief Completes the merge of two function declarations that are
+/// known to be compatible. 
+///
+/// This routine handles the merging of attributes and other
+/// properties of function declarations form the old declaration to
+/// the new declaration, once we know that New is in fact a
+/// redeclaration of Old.
+///
+/// \returns false
+bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
+  // Merge the attributes
+  MergeAttributes(New, Old);
+
+  // Merge the storage class.
+  New->setStorageClass(Old->getStorageClass());
+
+  // FIXME: need to implement inline semantics
+
+  // Merge "pure" flag.
+  if (Old->isPure())
+    New->setPure();
+
+  // Merge the "deleted" flag.
+  if (Old->isDeleted())
+    New->setDeleted();
+  
+  if (getLangOptions().CPlusPlus)
+    return MergeCXXFunctionDecl(New, Old);
+
+  return false;
+}
+
 /// Predicate for C "tentative" external object definitions (C99 6.9.2).
 static bool isTentativeDefinition(VarDecl *VD) {
   if (VD->isFileVarDecl())
@@ -1626,7 +1653,7 @@
 NamedDecl* 
 Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
                               QualType R, Decl *LastDeclarator,
-                              Decl* PrevDecl, bool IsFunctionDefinition,
+                              NamedDecl* PrevDecl, bool IsFunctionDefinition,
                               bool& InvalidDecl, bool &Redeclaration) {
   assert(R.getTypePtr()->isFunctionType());
 
@@ -1637,12 +1664,26 @@
   case DeclSpec::SCS_auto:
   case DeclSpec::SCS_register:
   case DeclSpec::SCS_mutable:
-    Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_func);
+    Diag(D.getDeclSpec().getStorageClassSpecLoc(), 
+         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_static: {
+    if (DC->getLookupContext()->isFunctionOrMethod()) {
+      // C99 6.7.1p5:
+      //   The declaration of an identifier for a function that has
+      //   block scope shall have no explicit storage-class specifier
+      //   other than extern
+      // See also (C++ [dcl.stc]p4).
+      Diag(D.getDeclSpec().getStorageClassSpecLoc(), 
+           diag::err_static_block_func);
+      SC = FunctionDecl::None;
+    } else
+      SC = FunctionDecl::Static; 
+    break;
+  }
   case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break;
   }
 
@@ -1817,11 +1858,60 @@
       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 && !isDeclInScope(PrevDecl, DC, S)) {
+    // Name lookup has found a previous declaration that is not in the
+    // same scope as the new declaration. However, these two
+    // declarations might still declare the same thing (C99 6.2.2p3-4,
+    // C++ [basic.link]p6).
+
+    // FIXME: PrevDecl could be an OverloadedFunctionDecl, in which
+    // case we need to check each of the overloaded functions.
+
+    if (getLangOptions().CPlusPlus) {
+      // C++ [basic.link]p6:
+      //   If there is a visible declaration of an entity with linkage
+      //   having the same name and type, ignoring entities declared
+      //   outside the innermost enclosing namespace scope, the block
+      //   scope declaration declares that same entity and receives the
+      //   linkage of the previous declaration.
+      DeclContext *OuterContext = DC->getLookupContext();
+      if (!OuterContext->isFunctionOrMethod())
+        // This rule only applies to block-scope declarations.
+        PrevDecl = 0;
+      else {
+        DeclContext *PrevOuterContext = PrevDecl->getDeclContext();
+        if (PrevOuterContext->isRecord())
+          // We found a member function: ignore it.
+          PrevDecl = 0;
+        else {
+          // Find the innermost enclosing namespace for the new and
+          // previous declarations.
+          while (!OuterContext->isFileContext())
+            OuterContext = OuterContext->getParent();
+          while (!PrevOuterContext->isFileContext())
+            PrevOuterContext = PrevOuterContext->getParent();
+          
+          // The previous declaration is in a different namespace, so it
+          // isn't the same function.
+          if (OuterContext->getPrimaryContext() != 
+              PrevOuterContext->getPrimaryContext())
+            PrevDecl = 0;
+        }
+      }
+    }
+
+    // If the declaration we've found has no linkage, ignore it. 
+    if (VarDecl *VD = dyn_cast_or_null<VarDecl>(PrevDecl)) {
+      if (!VD->hasGlobalStorage())
+        PrevDecl = 0;
+    } else if (PrevDecl && !isa<FunctionDecl>(PrevDecl))
+      PrevDecl = 0;
+  }
+
+  // Merge or overload the declaration with an existing declaration of
+  // the same name, if appropriate.
   bool OverloadableAttrRequired = false;
-  if (PrevDecl &&
-      (!getLangOptions().CPlusPlus||isDeclInScope(PrevDecl, DC, S))) {
+  if (PrevDecl) {
     // 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

Added: cfe/trunk/test/CodeGen/linkage-redecl.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/linkage-redecl.c?rev=65360&view=auto

==============================================================================
--- cfe/trunk/test/CodeGen/linkage-redecl.c (added)
+++ cfe/trunk/test/CodeGen/linkage-redecl.c Mon Feb 23 19:23:02 2009
@@ -0,0 +1,11 @@
+// RUN: clang -emit-llvm %s -o - |grep internal
+
+// C99 6.2.2p3
+// PR3425
+static void f(int x);
+
+void g0() {
+  f(5);
+}
+
+extern void f(int x) { } // still has internal linkage

Modified: cfe/trunk/test/Sema/function-redecl.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/function-redecl.c?rev=65360&r1=65359&r2=65360&view=diff

==============================================================================
--- cfe/trunk/test/Sema/function-redecl.c (original)
+++ cfe/trunk/test/Sema/function-redecl.c Mon Feb 23 19:23:02 2009
@@ -28,3 +28,33 @@
 {
   return x;
 }
+
+void test() {
+  int f1;
+  {
+    void f1(double);
+    {
+      void f1(double); // expected-note{{previous declaration is here}}
+      {
+        int f1(int); // expected-error{{conflicting types for 'f1'}}
+      }
+    }
+  }
+}
+
+extern void g3(int); // expected-note{{previous declaration is here}}
+static void g3(int x) { } // expected-error{{static declaration of 'g3' follows non-static declaration}}
+
+void test2() {
+  extern int f2; // expected-note{{previous definition is here}}
+  {
+    void f2(int); // expected-error{{redefinition of 'f2' as different kind of symbol}}
+  }
+
+  {
+    int f2;
+    {
+      void f2(int); // okay
+    }
+  }
+}

Modified: cfe/trunk/test/Sema/function.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/function.c?rev=65360&r1=65359&r2=65360&view=diff

==============================================================================
--- cfe/trunk/test/Sema/function.c (original)
+++ cfe/trunk/test/Sema/function.c Mon Feb 23 19:23:02 2009
@@ -53,3 +53,8 @@
 void f1_3137() {
   int (*fp)(void) = g0_3137;
 }
+
+void f1static() {
+  static void f2static(int); // expected-error{{function declared in block scope cannot have 'static' storage class}}
+  register void f2register(int); // expected-error{{illegal storage class on function}}
+}

Modified: cfe/trunk/test/Sema/nested-redef.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/nested-redef.c?rev=65360&r1=65359&r2=65360&view=diff

==============================================================================
--- cfe/trunk/test/Sema/nested-redef.c (original)
+++ cfe/trunk/test/Sema/nested-redef.c Mon Feb 23 19:23:02 2009
@@ -17,7 +17,7 @@
 
 void f2(void) {
   struct T t;
-  // FIXME: this is well-formed, but Clang breaks on it struct U u;
+  struct U u;
 }
 
 

Added: cfe/trunk/test/SemaCXX/function-redecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/function-redecl.cpp?rev=65360&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/function-redecl.cpp (added)
+++ cfe/trunk/test/SemaCXX/function-redecl.cpp Mon Feb 23 19:23:02 2009
@@ -0,0 +1,26 @@
+// RUN: clang -fsyntax-only -verify %s
+int foo(int);
+
+namespace N {
+  void f1() {
+    void foo(int); // okay
+  }
+
+  // FIXME: we shouldn't even need this declaration to detect errors
+  // below.
+  void foo(int); // expected-note{{previous declaration is here}}
+
+  void f2() {
+    int foo(int); // expected-error{{functions that differ only in their return type cannot be overloaded}}
+
+    {
+      int foo;
+      {
+        // FIXME: should diagnose this because it's incompatible with
+        // N::foo. However, name lookup isn't properly "skipping" the
+        // "int foo" above.
+        float foo(int); 
+      }
+    }
+  }
+}





More information about the cfe-commits mailing list