diff options
author | Rafael Espindola <rafael.espindola@gmail.com> | 2012-12-27 03:56:20 +0000 |
---|---|---|
committer | Rafael Espindola <rafael.espindola@gmail.com> | 2012-12-27 03:56:20 +0000 |
commit | e57e3d3783586934e26191cfc06ed5f3d966ea9c (patch) | |
tree | ca02d1724e33450239d366a39296898d856e309d /lib/Sema | |
parent | 66c0899c132fcc678ad72cd4fde621fb572adf69 (diff) |
Implement dcl.link paragraph 5.
The language linkage of redeclarations must match. GCC was already reporting
an error for this.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@171139 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index e1d772b084..7c193e13bd 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1969,6 +1969,32 @@ 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<typename T> +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, @@ -2229,6 +2255,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { assert(OldQTypeForComparison.isCanonical()); } + if (!hasCLanguageLinkage(*Old) && hasCLanguageLinkage(*New)) { + Diag(New->getLocation(), diag::err_different_language_linkage) << New; + Diag(Old->getLocation(), PrevDiag); + return true; + } + if (OldQTypeForComparison == NewQType) return MergeCompatibleFunctionDecls(New, Old, S); @@ -2612,6 +2644,14 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { New->setInvalidDecl(); return; } + + if (!hasCLanguageLinkage(*Old) && hasCLanguageLinkage(*New)) { + Diag(New->getLocation(), diag::err_different_language_linkage) << New; + Diag(Old->getLocation(), diag::note_previous_definition); + New->setInvalidDecl(); + return; + } + // c99 6.2.2 P4. // For an identifier declared with the storage-class specifier extern in a // scope in which a prior declaration of that identifier is visible, if |