diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index bb75895df538..12b6c4a98070 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -903,6 +903,12 @@ public: /// external, C linkage. bool isExternC() const; + /// Checks if this variable has C language linkage. Note that this is not the + /// same as isExternC since decls with non external linkage can have C + /// language linkage. They can also have C language linkage when they are not + /// declared in an extern C context, but a previous decl is. + bool hasCLanguageLinkage() const; + /// isLocalVarDecl - Returns true for local variable declarations /// other than parameters. Note that this includes static variables /// inside of functions. It also includes variables inside blocks. @@ -1790,6 +1796,12 @@ public: /// external, C linkage. bool isExternC() const; + /// Checks if this function has C language linkage. Note that this is not the + /// same as isExternC since decls with non external linkage can have C + /// language linkage. They can also have C language linkage when they are not + /// declared in an extern C context, but a previous decl is. + bool hasCLanguageLinkage() const; + /// \brief Determines whether this is a global function. bool isGlobal() const; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 85ab0024852a..92b1e4abf2ec 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1177,6 +1177,32 @@ SourceRange VarDecl::getSourceRange() const { return DeclaratorDecl::getSourceRange(); } +template +static bool hasCLanguageLinkageTemplate(const decl_type &D) { + // Language linkage is a C++ concept, but saying that everything in C has + // C language linkage fits the implementation nicelly. + ASTContext &Context = D.getASTContext(); + if (!Context.getLangOpts().CPlusPlus) + return true; + + // dcl.link 4: A C language linkage is ignored in determining the language + // linkage of the names of class members and the function type of class member + // functions. + const DeclContext *DC = D.getDeclContext(); + if (DC->isRecord()) + return false; + + // If the first decl is in an extern "C" context, any other redeclaration + // will have C language linkage. If the first one is not in an extern "C" + // context, we would have reported an error for any other decl being in one. + const decl_type *First = D.getFirstDeclaration(); + return First->getDeclContext()->isExternCContext(); +} + +bool VarDecl::hasCLanguageLinkage() const { + return hasCLanguageLinkageTemplate(*this); +} + bool VarDecl::isExternC() const { if (getLinkage() != ExternalLinkage) return false; @@ -1702,6 +1728,10 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const { return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy); } +bool FunctionDecl::hasCLanguageLinkage() const { + return hasCLanguageLinkageTemplate(*this); +} + bool FunctionDecl::isExternC() const { if (getLinkage() != ExternalLinkage) return false; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 7c193e13bd45..c9d0c7750c6c 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1969,32 +1969,6 @@ static bool isABIDefaultCC(Sema &S, CallingConv CC, FunctionDecl *D) { return ABIDefaultCC == CC; } -/// Check if the given decl has C language linkage. Note that this is not -/// the same as D.isExternC() since decls with non external linkage can have C -/// language linkage. They can also have C language linkage when they are -/// not declared in an extern C context, but a previous decl is. -template -bool hasCLanguageLinkage(const T &D) { - // Language linkage is a C++ concept, but saying that everything in C has - // C language linkage fits the implementation nicelly. - ASTContext &Context = D.getASTContext(); - if (!Context.getLangOpts().CPlusPlus) - return true; - - // dcl.link 4: A C language linkage is ignored in determining the language - // linkage of the names of class members and the function type of class member - // functions. - const DeclContext *DC = D.getDeclContext(); - if (DC->isRecord()) - return false; - - // If the first decl is in an extern "C" context, any other redeclaration - // will have C language linkage. If the first one is not in an extern "C" - // context, we would have reported an error for any other decl being in one. - const T *First = D.getFirstDeclaration(); - return First->getDeclContext()->isExternCContext(); -} - /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, @@ -2255,7 +2229,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { assert(OldQTypeForComparison.isCanonical()); } - if (!hasCLanguageLinkage(*Old) && hasCLanguageLinkage(*New)) { + if (!Old->hasCLanguageLinkage() && New->hasCLanguageLinkage()) { Diag(New->getLocation(), diag::err_different_language_linkage) << New; Diag(Old->getLocation(), PrevDiag); return true; @@ -2645,7 +2619,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { return; } - if (!hasCLanguageLinkage(*Old) && hasCLanguageLinkage(*New)) { + if (!Old->hasCLanguageLinkage() && New->hasCLanguageLinkage()) { Diag(New->getLocation(), diag::err_different_language_linkage) << New; Diag(Old->getLocation(), diag::note_previous_definition); New->setInvalidDecl(); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 7ae6d9d5af7d..02584525c97c 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -930,11 +930,19 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, return Ovl_Overload; } +static bool canBeOverloaded(const FunctionDecl &D) { + if (D.getAttr()) + return true; + if (D.hasCLanguageLinkage()) + return false; + return true; +} + bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, bool UseUsingDeclRules) { // If both of the functions are extern "C", then they are not // overloads. - if (Old->isExternC() && New->isExternC()) + if (!canBeOverloaded(*Old) && !canBeOverloaded(*New)) return false; FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate(); diff --git a/clang/test/SemaCXX/linkage2.cpp b/clang/test/SemaCXX/linkage2.cpp index ccf32008f132..f6561b9f1256 100644 --- a/clang/test/SemaCXX/linkage2.cpp +++ b/clang/test/SemaCXX/linkage2.cpp @@ -11,3 +11,10 @@ namespace test1 { void f(); // expected-error {{declaration of 'f' has a different language linkage}} } } + +extern "C" { + static void test2_f() { // expected-note {{previous definition is here}} + } + static void test2_f(int x) { // expected-error {{conflicting types for 'test2_f'}} + } +}