[cfe-commits] r65373 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.def lib/Sema/SemaDecl.cpp lib/Sema/SemaExpr.cpp test/Sema/function-redecl.c

Douglas Gregor dgregor at apple.com
Mon Feb 23 20:26:15 PST 2009


Author: dgregor
Date: Mon Feb 23 22:26:15 2009
New Revision: 65373

URL: http://llvm.org/viewvc/llvm-project?rev=65373&view=rev
Log:
In C, when we see a function declaration within a local scope, export
that declaration to global scope so that it can be found from other
scopes. This allows us to diagnose redeclaration errors for external
declarations across scopes. We also warn when name lookup finds such
an out-of-scope declaration. This is part of <rdar://problem/6127293>;
we'll also need to do the same thing for variables.


Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/Sema/function-redecl.c

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

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Mon Feb 23 22:26:15 2009
@@ -84,6 +84,8 @@
      "declarator requires an identifier")
 DIAG(err_bad_language, ERROR,
      "unknown linkage language")
+DIAG(warn_use_out_of_scope_declaration, WARNING,
+     "use of out-of-scope declaration of %0")
 
 /// Built-in functions.
 DIAG(ext_implicit_lib_function_decl, EXTWARN,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Feb 23 22:26:15 2009
@@ -2033,6 +2033,58 @@
       InvalidDecl = true;
     }
   }
+
+  if (!getLangOptions().CPlusPlus && CurContext->isFunctionOrMethod()) {
+    // If this is a function declaration in local scope, inject its
+    // name into the top-level scope so that it will be visible to
+    // later uses and declarations of the same function, since the
+    // function is external.
+    // FIXME: We don't do this in C++ because, although we would like
+    // to get the extra checking that this operation implies, 
+    // the declaration itself is not visible according to C++'s rules.
+    IdentifierResolver::iterator I = IdResolver.begin(Name),
+                              IEnd = IdResolver.end();
+    NamedDecl *PrevIdDecl = 0;
+    while (I != IEnd && !isa<TranslationUnitDecl>((*I)->getDeclContext())) {
+      PrevIdDecl = *I;
+      ++I;
+    }
+
+    if (I == IEnd) {
+      // No name with this identifier has been declared at translation
+      // unit scope. Add this name into the appropriate scope.
+      if (PrevIdDecl)
+        IdResolver.AddShadowedDecl(NewFD, PrevIdDecl);
+      else
+        IdResolver.AddDecl(NewFD);
+      TUScope->AddDecl(NewFD);
+      return NewFD;      
+    }
+
+    if (isa<TagDecl>(*I)) {
+      // The first thing we found was a tag declaration, so insert
+      // this function so that it will be found before the tag
+      // declaration.
+      if (PrevIdDecl)
+        IdResolver.AddShadowedDecl(NewFD, PrevIdDecl);
+      else
+        IdResolver.AddDecl(NewFD);
+      TUScope->AddDecl(NewFD);
+    } else if (isa<FunctionDecl>(*I) && NewFD->declarationReplaces(*I)) {
+      // We found a previous declaration of the same function. Replace
+      // that declaration with this one.
+      TUScope->RemoveDecl(*I);
+      TUScope->AddDecl(NewFD);
+      IdResolver.RemoveDecl(*I);
+      if (PrevIdDecl)
+        IdResolver.AddShadowedDecl(NewFD, PrevIdDecl);
+      else
+        IdResolver.AddDecl(NewFD);
+    }
+
+    return NewFD;
+  }
+
   return NewFD;
 }
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Feb 23 22:26:15 2009
@@ -70,12 +70,13 @@
   }
 
   // See if this is a deleted function.
-  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
     if (FD->isDeleted()) {
       Diag(Loc, diag::err_deleted_function_use);
       Diag(D->getLocation(), diag::note_unavailable_here) << true;
       return true;
     }
+  }
 
   // See if the decl is unavailable
   if (D->getAttr<UnavailableAttr>()) {
@@ -83,6 +84,28 @@
     Diag(D->getLocation(), diag::note_unavailable_here) << 0;
   }
 
+  if (D->getDeclContext()->isFunctionOrMethod() && 
+      !D->getDeclContext()->Encloses(CurContext)) {
+    // We've found the name of a function or variable that was
+    // declared with external linkage within another function (and,
+    // therefore, a scope where we wouldn't normally see the
+    // declaration). Once we've made sure that no previous declaration
+    // was properly made visible, produce a warning.
+    bool HasGlobalScopedDeclaration = false;
+    for (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); FD;
+         FD = FD->getPreviousDeclaration()) {
+      if (FD->getDeclContext()->isFileContext()) {
+        HasGlobalScopedDeclaration = true;
+        break;
+      }
+    }
+    // FIXME: do the same thing for variable declarations
+    
+    if (!HasGlobalScopedDeclaration) {
+      Diag(Loc, diag::warn_use_out_of_scope_declaration) << D;
+      Diag(D->getLocation(), diag::note_previous_declaration);
+    }
+  }
 
   return false;
 }

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

==============================================================================
--- cfe/trunk/test/Sema/function-redecl.c (original)
+++ cfe/trunk/test/Sema/function-redecl.c Mon Feb 23 22:26:15 2009
@@ -58,3 +58,31 @@
     }
   }
 }
+
+// <rdar://problem/6127293>
+int outer1(int); // expected-note{{previous declaration is here}}
+struct outer3 { };
+int outer4(int);
+int outer5; // expected-note{{previous definition is here}}
+int *outer7(int);
+
+void outer_test() {
+  int outer1(float); // expected-error{{conflicting types for 'outer1'}}
+  int outer2(int); // expected-note{{previous declaration is here}}
+  int outer3(int); // expected-note{{previous declaration is here}}
+  int outer4(int); // expected-note{{previous declaration is here}}
+  int outer5(int); // expected-error{{redefinition of 'outer5' as different kind of symbol}}
+  int* outer6(int); // expected-note{{previous declaration is here}}
+  int *outer7(int);
+
+  int *ip7 = outer7(6);
+}
+
+int outer2(float); // expected-error{{conflicting types for 'outer2'}}
+int outer3(float); // expected-error{{conflicting types for 'outer3'}}
+int outer4(float); // expected-error{{conflicting types for 'outer4'}}
+
+void outer_test2(int x) {
+  int* ip = outer6(x); // expected-warning{{use of out-of-scope declaration of 'outer6'}}
+  int *ip2 = outer7(x);
+}





More information about the cfe-commits mailing list