]> granicus.if.org Git - clang/commitdiff
Implement declaration merging for non-template functions from
authorDouglas Gregor <dgregor@apple.com>
Wed, 4 Jan 2012 17:13:46 +0000 (17:13 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 4 Jan 2012 17:13:46 +0000 (17:13 +0000)
different modules. This implementation is a first approximation of
what we want, using only the function type to determine
equivalence. Later, we'll want to deal with some of the more subtle
issues, including:

  - C allows a prototyped declaration and a non-prototyped declaration
    to be merged, which we should support
  - We may want to ignore the return type when merging, then
    complain if the return types differ. Or, we may want to leave it
    as it us, so that we only complain if overload resolution
    eventually fails.
  - C++ non-static member functions need to consider cv-qualifiers
    and ref-qualifiers.
  - Function templates need to consider the template parameters and
    return type.
  - Function template specializations will have special rules.
  - We can now (accidentally!) end up overloading in C, even without
    the "overloadable" attribute, and will need to detect this at some
    point.

The actual detection of "is this an overload?" is implemented by
Sema::IsOverload(), which will need to be moved into the AST library
for re-use here. That will be a future refactor.

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

lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriterDecl.cpp
test/Modules/Inputs/redecl-merge-left.h
test/Modules/Inputs/redecl-merge-right.h
test/Modules/redecl-merge.m

index c00b69cf75b0a503f1e16964072ae3ac95af2738..c34243f60163ef233f4d643fb2b3713f866c0619 100644 (file)
@@ -490,14 +490,38 @@ void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
 }
 
 void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
-  VisitRedeclarable(FD);
+  // Record the declaration -> global ID mapping.
+  Reader.DeclToID[FD] = ThisDeclID;
+  
+  RedeclarableResult Redecl = VisitRedeclarable(FD);
   VisitDeclaratorDecl(FD);
 
   ReadDeclarationNameLoc(FD->DNLoc, FD->getDeclName(), Record, Idx);
   FD->IdentifierNamespace = Record[Idx++];
+  
+  // FunctionDecl's body is handled last at ASTDeclReader::Visit,
+  // after everything else is read.
+  
+  FD->SClass = (StorageClass)Record[Idx++];
+  FD->SClassAsWritten = (StorageClass)Record[Idx++];
+  FD->IsInline = Record[Idx++];
+  FD->IsInlineSpecified = Record[Idx++];
+  FD->IsVirtualAsWritten = Record[Idx++];
+  FD->IsPure = Record[Idx++];
+  FD->HasInheritedPrototype = Record[Idx++];
+  FD->HasWrittenPrototype = Record[Idx++];
+  FD->IsDeleted = Record[Idx++];
+  FD->IsTrivial = Record[Idx++];
+  FD->IsDefaulted = Record[Idx++];
+  FD->IsExplicitlyDefaulted = Record[Idx++];
+  FD->HasImplicitReturnZero = Record[Idx++];
+  FD->IsConstexpr = Record[Idx++];
+  FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
+
   switch ((FunctionDecl::TemplatedKind)Record[Idx++]) {
   default: llvm_unreachable("Unhandled TemplatedKind!");
   case FunctionDecl::TK_NonTemplate:
+    mergeRedeclarable(FD, Redecl);      
     break;
   case FunctionDecl::TK_FunctionTemplate:
     FD->setDescribedFunctionTemplate(ReadDeclAs<FunctionTemplateDecl>(Record, 
@@ -591,25 +615,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
   }
   }
 
-  // FunctionDecl's body is handled last at ASTDeclReader::Visit,
-  // after everything else is read.
-
-  FD->SClass = (StorageClass)Record[Idx++];
-  FD->SClassAsWritten = (StorageClass)Record[Idx++];
-  FD->IsInline = Record[Idx++];
-  FD->IsInlineSpecified = Record[Idx++];
-  FD->IsVirtualAsWritten = Record[Idx++];
-  FD->IsPure = Record[Idx++];
-  FD->HasInheritedPrototype = Record[Idx++];
-  FD->HasWrittenPrototype = Record[Idx++];
-  FD->IsDeleted = Record[Idx++];
-  FD->IsTrivial = Record[Idx++];
-  FD->IsDefaulted = Record[Idx++];
-  FD->IsExplicitlyDefaulted = Record[Idx++];
-  FD->HasImplicitReturnZero = Record[Idx++];
-  FD->IsConstexpr = Record[Idx++];
-  FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
-
   // Read in the parameters.
   unsigned NumParams = Record[Idx++];
   SmallVector<ParmVarDecl *, 16> Params;
@@ -1696,12 +1701,19 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
   // Compatible tags match.
   if (TagDecl *TagX = dyn_cast<TagDecl>(X)) {
     TagDecl *TagY = cast<TagDecl>(Y);
-    if ((TagX->getTagKind() == TagY->getTagKind()) ||
-        ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class)&&
-         (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class)))
-      return true;
+    return (TagX->getTagKind() == TagY->getTagKind()) ||
+      ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class) &&
+       (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class));
   }
-        
+  
+  // Functions with the same type and linkage match.
+  if (FunctionDecl *FuncX = dyn_cast<FunctionDecl>(X)) {
+    FunctionDecl *FuncY = cast<FunctionDecl>(Y);
+    return (FuncX->getLinkage() == FuncY->getLinkage()) &&
+      FuncX->getASTContext().hasSameType(FuncX->getType(), FuncY->getType());
+  }
+  
+  
   // FIXME: Many other cases to implement.
   return false;
 }
index a995e37ee7b88f0cc5dec574dcc6b4f3aaaae932..f6c65f0870be5ab6b77ea76e6fd7f3382c25d324 100644 (file)
@@ -302,6 +302,26 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
 
   Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record);
   Record.push_back(D->getIdentifierNamespace());
+  
+  // FunctionDecl's body is handled last at ASTWriterDecl::Visit,
+  // after everything else is written.
+  
+  Record.push_back(D->getStorageClass()); // FIXME: stable encoding
+  Record.push_back(D->getStorageClassAsWritten());
+  Record.push_back(D->IsInline);
+  Record.push_back(D->isInlineSpecified());
+  Record.push_back(D->isVirtualAsWritten());
+  Record.push_back(D->isPure());
+  Record.push_back(D->hasInheritedPrototype());
+  Record.push_back(D->hasWrittenPrototype());
+  Record.push_back(D->isDeletedAsWritten());
+  Record.push_back(D->isTrivial());
+  Record.push_back(D->isDefaulted());
+  Record.push_back(D->isExplicitlyDefaulted());
+  Record.push_back(D->hasImplicitReturnZero());
+  Record.push_back(D->isConstexpr());
+  Writer.AddSourceLocation(D->getLocEnd(), Record);
+
   Record.push_back(D->getTemplatedKind());
   switch (D->getTemplatedKind()) {
   default: llvm_unreachable("Unhandled TemplatedKind!");
@@ -368,25 +388,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
   }
   }
 
-  // FunctionDecl's body is handled last at ASTWriterDecl::Visit,
-  // after everything else is written.
-
-  Record.push_back(D->getStorageClass()); // FIXME: stable encoding
-  Record.push_back(D->getStorageClassAsWritten());
-  Record.push_back(D->IsInline);
-  Record.push_back(D->isInlineSpecified());
-  Record.push_back(D->isVirtualAsWritten());
-  Record.push_back(D->isPure());
-  Record.push_back(D->hasInheritedPrototype());
-  Record.push_back(D->hasWrittenPrototype());
-  Record.push_back(D->isDeletedAsWritten());
-  Record.push_back(D->isTrivial());
-  Record.push_back(D->isDefaulted());
-  Record.push_back(D->isExplicitlyDefaulted());
-  Record.push_back(D->hasImplicitReturnZero());
-  Record.push_back(D->isConstexpr());
-  Writer.AddSourceLocation(D->getLocEnd(), Record);
-
   Record.push_back(D->param_size());
   for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
        P != PEnd; ++P)
index 47f3492f309b319997b3455d123a82d9d488c337..3eb0a735fa96b3ea6539d3612473e33f20313adf 100644 (file)
@@ -59,6 +59,10 @@ void consume_S4(struct S4*);
 typedef int T1;
 typedef float T2;
 
+int func0(int);
+int func1(int);
+int func2(int);
+
 #ifdef __cplusplus
 template<typename T> class Vector;
 
index 315a9c37fff5e45ec632e0c09d3276e105633d03..9660199c72d80ee2fa5f9a4bfce3111f1e5f6583 100644 (file)
@@ -62,6 +62,13 @@ struct S4 *produce_S4(void);
 typedef int T1;
 typedef double T2;
 
+int func0(int);
+int func1(int);
+int func1(int);
+int func1(int);
+int func1(int);
+static int func2(int);
+
 #ifdef __cplusplus
 template<typename T> class Vector { 
 public:
index 44d427c4c7551d6ee115b257267cdacf9ef3bba9..b8752610fb4db468b9b6b32a662bba28a34ffc80 100644 (file)
@@ -61,9 +61,17 @@ void testTypedefMerge(int i, double d) {
   // FIXME: Typedefs aren't actually merged in the sense of other merges, because
   // we should only merge them when the types are identical.
   // in other file: expected-note{{candidate found by name lookup is 'T2'}}
+  // in other file: expected-note{{candidate function}}
   T2 *dp = &d; // expected-error{{reference to 'T2' is ambiguous}}
 }
 
+void testFuncMerge(int i) {
+  func0(i);
+  // in other file: expected-note{{candidate function}}
+  func1(i);
+  func2(i); // expected-error{{call to 'func2' is ambiguous}}
+}
+
 // Test redeclarations of entities in explicit submodules, to make
 // sure we're maintaining the declaration chains even when normal name
 // lookup can't see what we're looking for.