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}}
+ // [email protected]: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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits