r175117 - Add a getLanguageLinkage method to VarDecls and FunctionDecls. Use it to fix
Rafael Espindola
rafael.espindola at gmail.com
Wed Feb 13 17:18:38 PST 2013
Author: rafael
Date: Wed Feb 13 19:18:37 2013
New Revision: 175117
URL: http://llvm.org/viewvc/llvm-project?rev=175117&view=rev
Log:
Add a getLanguageLinkage method to VarDecls and FunctionDecls. Use it to fix
some cases where functions with no language linkage were being treated as having
C language linkage. In particular, don't warn in
extern "C" {
static NonPod foo();
}
Since getLanguageLinkage checks the language linkage, the linkage computation
cannot use the language linkage. Break the loop by checking just the context
in the linkage computation.
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/include/clang/AST/DeclBase.h
cfe/trunk/include/clang/Basic/Linkage.h
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/AST/DeclBase.cpp
cfe/trunk/lib/AST/ItaniumMangle.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/CodeGenCXX/c-linkage.cpp
cfe/trunk/test/SemaCXX/function-extern-c.cpp
cfe/trunk/test/SemaCXX/linkage2.cpp
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=175117&r1=175116&r2=175117&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Feb 13 19:18:37 2013
@@ -898,11 +898,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;
+ /// Compute the language linkage.
+ LanguageLinkage getLanguageLinkage() const;
+
+ bool hasCLanguageLinkage() const {
+ return getLanguageLinkage() == CLanguageLinkage;
+ }
/// isLocalVarDecl - Returns true for local variable declarations
/// other than parameters. Note that this includes static variables
@@ -1790,11 +1791,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;
+ /// Compute the language linkage.
+ LanguageLinkage getLanguageLinkage() const;
+
+ bool hasCLanguageLinkage() const {
+ return getLanguageLinkage() == CLanguageLinkage;
+ }
/// \brief Determines whether this is a global function.
bool isGlobal() const;
Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=175117&r1=175116&r2=175117&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Wed Feb 13 19:18:37 2013
@@ -1090,6 +1090,10 @@ public:
/// a C++ extern "C" linkage spec.
bool isExternCContext() const;
+ /// \brief Determines whether this context is, or is nested within,
+ /// a C++ extern "C++" linkage spec.
+ bool isExternCXXContext() const;
+
/// \brief Determine whether this declaration context is equivalent
/// to the declaration context DC.
bool Equals(const DeclContext *DC) const {
Modified: cfe/trunk/include/clang/Basic/Linkage.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Linkage.h?rev=175117&r1=175116&r2=175117&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Linkage.h (original)
+++ cfe/trunk/include/clang/Basic/Linkage.h Wed Feb 13 19:18:37 2013
@@ -42,6 +42,14 @@ enum Linkage {
ExternalLinkage
};
+/// \brief Describes the different kinds of language linkage
+/// (C++ [dcl.link]) that an entity may have.
+enum LanguageLinkage {
+ CLanguageLinkage,
+ CXXLanguageLinkage,
+ NoLanguageLinkage
+};
+
/// \brief A more specific kind of linkage than enum Linkage.
///
/// This is relevant to CodeGen and AST file reading.
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=175117&r1=175116&r2=175117&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Wed Feb 13 19:18:37 2013
@@ -196,6 +196,12 @@ static bool useInlineVisibilityHidden(co
FD->hasBody(Def) && Def->isInlined() && !Def->hasAttr<GNUInlineAttr>();
}
+template<typename T>
+bool isInExternCContext(T *D) {
+ const T *First = D->getFirstDeclaration();
+ return First->getDeclContext()->isExternCContext();
+}
+
static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
bool OnlyTemplate) {
assert(D->getDeclContext()->getRedeclContext()->isFileContext() &&
@@ -262,8 +268,8 @@ static LinkageInfo getLVForNamespaceScop
if (D->isInAnonymousNamespace()) {
const VarDecl *Var = dyn_cast<VarDecl>(D);
const FunctionDecl *Func = dyn_cast<FunctionDecl>(D);
- if ((!Var || !Var->hasCLanguageLinkage()) &&
- (!Func || !Func->hasCLanguageLinkage()))
+ if ((!Var || !isInExternCContext(Var)) &&
+ (!Func || !isInExternCContext(Func)))
return LinkageInfo::uniqueExternal();
}
@@ -1210,29 +1216,36 @@ SourceRange VarDecl::getSourceRange() co
}
template<typename T>
-static bool hasCLanguageLinkageTemplate(const T &D) {
+static LanguageLinkage getLanguageLinkageTemplate(const T &D) {
// Language linkage is a C++ concept, but saying that everything in C has
// C language linkage fits the implementation nicely.
ASTContext &Context = D.getASTContext();
if (!Context.getLangOpts().CPlusPlus)
- return true;
+ return CLanguageLinkage;
+
+ // dcl.link 1: All function types, function names with external linkage, and
+ // variable names with external linkage have a language linkage.
+ if (!isExternalLinkage(D.getLinkage()))
+ return NoLanguageLinkage;
// 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;
+ return CXXLanguageLinkage;
// 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();
+ if (First->getDeclContext()->isExternCContext())
+ return CLanguageLinkage;
+ return CXXLanguageLinkage;
}
-bool VarDecl::hasCLanguageLinkage() const {
- return hasCLanguageLinkageTemplate(*this);
+LanguageLinkage VarDecl::getLanguageLinkage() const {
+ return getLanguageLinkageTemplate(*this);
}
bool VarDecl::isExternC() const {
@@ -1757,14 +1770,14 @@ bool FunctionDecl::isReservedGlobalPlace
return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy);
}
-bool FunctionDecl::hasCLanguageLinkage() const {
+LanguageLinkage FunctionDecl::getLanguageLinkage() const {
// Users expect to be able to write
// extern "C" void *__builtin_alloca (size_t);
// so consider builtins as having C language linkage.
if (getBuiltinID())
- return true;
+ return CLanguageLinkage;
- return hasCLanguageLinkageTemplate(*this);
+ return getLanguageLinkageTemplate(*this);
}
bool FunctionDecl::isExternC() const {
Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=175117&r1=175116&r2=175117&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Wed Feb 13 19:18:37 2013
@@ -806,6 +806,17 @@ bool DeclContext::isExternCContext() con
return false;
}
+bool DeclContext::isExternCXXContext() const {
+ const DeclContext *DC = this;
+ while (DC->DeclKind != Decl::TranslationUnit) {
+ if (DC->DeclKind == Decl::LinkageSpec)
+ return cast<LinkageSpecDecl>(DC)->getLanguage()
+ == LinkageSpecDecl::lang_cxx;
+ DC = DC->getParent();
+ }
+ return false;
+}
+
bool DeclContext::Encloses(const DeclContext *DC) const {
if (getPrimaryContext() != this)
return getPrimaryContext()->Encloses(DC);
Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=175117&r1=175116&r2=175117&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Wed Feb 13 19:18:37 2013
@@ -356,17 +356,6 @@ private:
}
-static bool isInCLinkageSpecification(const Decl *D) {
- D = D->getCanonicalDecl();
- for (const DeclContext *DC = getEffectiveDeclContext(D);
- !DC->isTranslationUnit(); DC = getEffectiveParentContext(DC)) {
- if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC))
- return Linkage->getLanguage() == LinkageSpecDecl::lang_c;
- }
-
- return false;
-}
-
bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
// In C, functions with no attributes never need to be mangled. Fastpath them.
if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
@@ -405,8 +394,12 @@ bool ItaniumMangleContext::shouldMangleD
return true;
// C functions and "main" are not mangled.
- if ((FD && FD->isMain()) || isInCLinkageSpecification(D))
- return false;
+ if (FD)
+ return !FD->isMain() && !FD->hasCLanguageLinkage();
+
+ // C variables are not mangled.
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ return !VD->hasCLanguageLinkage();
return true;
}
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=175117&r1=175116&r2=175117&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Feb 13 19:18:37 2013
@@ -2065,6 +2065,22 @@ static bool isABIDefaultCC(Sema &S, Call
return ABIDefaultCC == CC;
}
+template<typename T>
+bool haveIncompatibleLanguageLinkages(const T *Old, const T *New) {
+ const DeclContext *DC = Old->getDeclContext();
+ if (DC->isRecord())
+ return false;
+
+ LanguageLinkage OldLinkage = Old->getLanguageLinkage();
+ if (OldLinkage == CXXLanguageLinkage &&
+ New->getDeclContext()->isExternCContext())
+ return true;
+ if (OldLinkage == CLanguageLinkage &&
+ New->getDeclContext()->isExternCXXContext())
+ return true;
+ return false;
+}
+
/// 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,
@@ -2366,7 +2382,7 @@ bool Sema::MergeFunctionDecl(FunctionDec
assert(OldQTypeForComparison.isCanonical());
}
- if (!Old->hasCLanguageLinkage() && New->hasCLanguageLinkage()) {
+ if (haveIncompatibleLanguageLinkages(Old, New)) {
Diag(New->getLocation(), diag::err_different_language_linkage) << New;
Diag(Old->getLocation(), PrevDiag);
return true;
@@ -2756,7 +2772,7 @@ void Sema::MergeVarDecl(VarDecl *New, Lo
return;
}
- if (!Old->hasCLanguageLinkage() && New->hasCLanguageLinkage()) {
+ if (haveIncompatibleLanguageLinkages(Old, New)) {
Diag(New->getLocation(), diag::err_different_language_linkage) << New;
Diag(Old->getLocation(), diag::note_previous_definition);
New->setInvalidDecl();
Modified: cfe/trunk/test/CodeGenCXX/c-linkage.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/c-linkage.cpp?rev=175117&r1=175116&r2=175117&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/c-linkage.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/c-linkage.cpp Wed Feb 13 19:18:37 2013
@@ -11,3 +11,16 @@ extern "C" {
}
// CHECK: define void @_ZN1N1X1fEv
+
+extern "C" {
+ static void test2_f() {
+ }
+ // CHECK: define internal void @_Z7test2_fv
+ static void test2_f(int x) {
+ }
+ // CHECK: define internal void @_Z7test2_fi
+ void test2_use() {
+ test2_f();
+ test2_f(42);
+ }
+}
Modified: cfe/trunk/test/SemaCXX/function-extern-c.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/function-extern-c.cpp?rev=175117&r1=175116&r2=175117&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/function-extern-c.cpp (original)
+++ cfe/trunk/test/SemaCXX/function-extern-c.cpp Wed Feb 13 19:18:37 2013
@@ -51,3 +51,13 @@ namespace test2 {
};
A f(void); // expected-warning {{'f' has C-linkage specified, but returns user-defined type 'test2::A' which is incompatible with C}}
}
+
+namespace test3 {
+ struct A {
+ A(const A&);
+ };
+ extern "C" {
+ // Don't warn for static functions.
+ static A f(void);
+ }
+}
Modified: cfe/trunk/test/SemaCXX/linkage2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/linkage2.cpp?rev=175117&r1=175116&r2=175117&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/linkage2.cpp (original)
+++ cfe/trunk/test/SemaCXX/linkage2.cpp Wed Feb 13 19:18:37 2013
@@ -2,20 +2,22 @@
namespace test1 {
int x; // expected-note {{previous definition is here}}
- static int y; // expected-note {{previous definition is here}}
+ static int y;
void f() {} // expected-note {{previous definition is here}}
extern "C" {
extern int x; // expected-error {{declaration of 'x' has a different language linkage}}
- extern int y; // expected-error {{declaration of 'y' has a different language linkage}}
+ extern int y; // OK, has internal linkage, so no language linkage.
void f(); // expected-error {{declaration of 'f' has a different language linkage}}
}
}
+// This is OK. Both test2_f don't have language linkage since they have
+// internal linkage.
extern "C" {
- static void test2_f() { // expected-note {{previous definition is here}}
+ static void test2_f() {
}
- static void test2_f(int x) { // expected-error {{conflicting types for 'test2_f'}}
+ static void test2_f(int x) {
}
}
@@ -71,3 +73,36 @@ namespace test6 {
shared_future<int&> f1 = get_future<int&>();
}
}
+
+// This is OK. The variables have internal linkage and therefore no language
+// linkage.
+extern "C" {
+ static int test7_x;
+}
+extern "C++" {
+ extern int test7_x;
+}
+extern "C++" {
+ static int test7_y;
+}
+extern "C" {
+ extern int test7_y;
+}
+extern "C" { typedef int test7_F(); static test7_F test7_f; }
+extern "C++" { extern test7_F test7_f; }
+
+// FIXME: This should be invalid. The function has no language linkage, but
+// the function type has, so this is redeclaring the function with a different
+// type.
+extern "C++" {
+ static void test8_f();
+}
+extern "C" {
+ extern void test8_f();
+}
+extern "C" {
+ static void test8_g();
+}
+extern "C++" {
+ extern void test8_g();
+}
More information about the cfe-commits
mailing list