]> granicus.if.org Git - clang/commitdiff
In C, when we see a function declaration within a local scope, export
authorDouglas Gregor <dgregor@apple.com>
Tue, 24 Feb 2009 04:26:15 +0000 (04:26 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 24 Feb 2009 04:26:15 +0000 (04:26 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65373 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 2016d4ff47ce80e9c3d38113ae50a3b6dece5330..24bca6a0cf287745cecb5e5e06336c2ca485f071 100644 (file)
@@ -84,6 +84,8 @@ DIAG(err_declarator_need_ident, ERROR,
      "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,
index 634017330d26792dc96989b748f9428303831a1f..00136badfea8dfb908e49da721aa4973bee7aa78 100644 (file)
@@ -2033,6 +2033,58 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
       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;
 }
 
index aef66619f6b1bfd6c2f7f27a5f79f558d75a1917..a58752cb42a7b5f067b76a7ba9306b50eeccdf70 100644 (file)
@@ -70,12 +70,13 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
   }
 
   // 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 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) {
     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;
 }
index 4be03227227cfb73ecdfa258732b805a6baadf90..daa5044dd085285770dbb13a51ddb0178b186256 100644 (file)
@@ -58,3 +58,31 @@ void test2() {
     }
   }
 }
+
+// <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);
+}