ahatanak updated this revision to Diff 92742.
ahatanak added a comment.

Update patch.

1. In isSameEntity, call typesAreCompatible instead of hasSameType so that 
non-prototype function declarations are merged with function prototypes.
2. Define a function (mergeCompatibleFunctionDecls) that changes the type of 
non-prototype functions declarations and adds parameters.
3. Make hasSameOverloadableAttrs check the presence of noreturn function 
attributes. Without this change, test/Modules/redecl-merge.m would fail after 
making the changes in 1.
4. Add a test case that declares a non-prototype declaration in the header and 
function prototype in the .c file.


https://reviews.llvm.org/D25001

Files:
  lib/Serialization/ASTReaderDecl.cpp
  test/Modules/Inputs/merge-non-prototype-fn/header2.h
  test/Modules/Inputs/merge-non-prototype-fn/module.map
  test/Modules/merge-non-prototype-fn.c

Index: test/Modules/merge-non-prototype-fn.c
===================================================================
--- /dev/null
+++ test/Modules/merge-non-prototype-fn.c
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -I%S/Inputs/merge-non-prototype-fn -fmodules -fimplicit-module-maps -x c -fmodules-cache-path=%t -fsyntax-only -verify %s
+
+char *func1();
+char *func2(const char*, int);
+
+#include "header2.h"
+
+void foo1(void) {
+  func1("abc", 12);
+  func2(1, 2, 3, 4); // expected-error {{too many arguments to function call, expected 2, have 4}}
+                     // expected-note@header2.h:5 {{'func2' declared here}}
+}
Index: test/Modules/Inputs/merge-non-prototype-fn/module.map
===================================================================
--- /dev/null
+++ test/Modules/Inputs/merge-non-prototype-fn/module.map
@@ -0,0 +1,5 @@
+module header2 {
+  header "header2.h"
+  export *
+}
+
Index: test/Modules/Inputs/merge-non-prototype-fn/header2.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/merge-non-prototype-fn/header2.h
@@ -0,0 +1,7 @@
+#ifndef FUNC1
+#define FUNC1
+
+char *func1(const char *, int);
+char *func2();
+
+#endif
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -766,6 +766,8 @@
   FD->setCachedLinkage(Linkage(Record.readInt()));
   FD->EndRangeLoc = ReadSourceLocation();
 
+  bool IsFunctionNoProtoType = FD->getType()->getAs<FunctionNoProtoType>();
+
   switch ((FunctionDecl::TemplatedKind)Record.readInt()) {
   case FunctionDecl::TK_NonTemplate:
     mergeRedeclarable(FD, Redecl);
@@ -873,6 +875,12 @@
 
   // Read in the parameters.
   unsigned NumParams = Record.readInt();
+
+  // Return here if FD is a non-prototype function declaration and has been
+  // merged with a function prototype.
+  if (IsFunctionNoProtoType && FD->getType()->getAs<FunctionProtoType>())
+    return;
+
   SmallVector<ParmVarDecl *, 16> Params;
   Params.reserve(NumParams);
   for (unsigned I = 0; I != NumParams; ++I)
@@ -2402,6 +2410,35 @@
   llvm_unreachable("merged an unknown kind of redeclarable template");
 }
 
+static void mergeCompatibleFunctionDecls(FunctionDecl *OldFD,
+                                         FunctionDecl *NewFD,
+                                         ASTContext &Context) {
+  const auto *OldFuncType = OldFD->getType()->getAs<FunctionType>();
+  const auto *NewFuncType = NewFD->getType()->getAs<FunctionType>();
+  const FunctionProtoType *OldProto = dyn_cast<FunctionProtoType>(OldFuncType);
+
+  if (!OldProto || !isa<FunctionNoProtoType>(NewFuncType))
+    return;
+
+  SmallVector<QualType, 4> ParamTypes(OldProto->param_types());
+  QualType NewType = Context.getFunctionType(
+      NewFuncType->getReturnType(), ParamTypes, OldProto->getExtProtoInfo());
+  NewFD->setType(NewType);
+  NewFD->setHasInheritedPrototype();
+
+  SmallVector<ParmVarDecl *, 4> Params;
+  for (const auto &ParamType : OldProto->param_types()) {
+    auto *Param = ParmVarDecl::Create(Context, NewFD, SourceLocation(),
+                                      SourceLocation(), nullptr, ParamType,
+                                      nullptr, SC_None, nullptr);
+    Param->setScopeInfo(0, Params.size());
+    Param->setImplicit();
+    Params.push_back(Param);
+  }
+
+  NewFD->setParams(Params);
+}
+
 /// \brief Attempts to merge the given declaration (D) with another declaration
 /// of the same entity.
 template<typename T>
@@ -2423,6 +2460,13 @@
     ExistingCanon->Used |= D->Used;
     D->Used = false;
 
+    if (!Reader.getContext().getLangOpts().CPlusPlus) {
+      auto *OldFD = dyn_cast<FunctionDecl>(Existing);
+      auto *FD = dyn_cast<FunctionDecl>(D);
+      if (OldFD && FD)
+        mergeCompatibleFunctionDecls(OldFD, FD, Reader.getContext());
+    }
+
     // When we merge a namespace, update its pointer to the first namespace.
     // We cannot have loaded any redeclarations of this declaration yet, so
     // there's nothing else that needs to be updated.
@@ -2672,6 +2716,10 @@
 /// B. Will ignore any overloadable attrs represented in the type of A and B.
 static bool hasSameOverloadableAttrs(const FunctionDecl *A,
                                      const FunctionDecl *B) {
+  if (A->getType()->getAs<FunctionType>()->getNoReturnAttr() !=
+      B->getType()->getAs<FunctionType>()->getNoReturnAttr())
+    return false;
+
   // Note that pass_object_size attributes are represented in the function's
   // ExtParameterInfo, so we don't need to check them here.
 
@@ -2763,7 +2811,7 @@
         return false;
     }
     ASTContext &C = FuncX->getASTContext();
-    if (!C.hasSameType(FuncX->getType(), FuncY->getType())) {
+    if (!C.typesAreCompatible(FuncX->getType(), FuncY->getType())) {
       // We can get functions with different types on the redecl chain in C++17
       // if they have differing exception specifications and at least one of
       // the excpetion specs is unresolved.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to