r185229 - PR7927, PR16247: Reimplement handling of matching extern "C" declarations
Richard Smith
richard-llvm at metafoo.co.uk
Fri Jun 28 15:03:52 PDT 2013
Author: rsmith
Date: Fri Jun 28 17:03:51 2013
New Revision: 185229
URL: http://llvm.org/viewvc/llvm-project?rev=185229&view=rev
Log:
PR7927, PR16247: Reimplement handling of matching extern "C" declarations
across scopes.
When we declare an extern "C" name that is not a redeclaration of an entity in
the same scope, check whether it redeclares some extern "C" entity from another
scope, and if not, check whether it conflicts with a (non-extern-"C") entity in
the translation unit.
When we declare a name in the translation unit that is not a redeclaration,
check whether it conflicts with any extern "C" entities (possibly from other
scopes).
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/CXX/class.access/class.friend/p1.cpp
cfe/trunk/test/Sema/overloadable.c
cfe/trunk/test/SemaCXX/extern-c.cpp
cfe/trunk/test/SemaCXX/friend.cpp
cfe/trunk/test/SemaCXX/linkage-spec.cpp
cfe/trunk/test/SemaCXX/linkage2.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=185229&r1=185228&r2=185229&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jun 28 17:03:51 2013
@@ -3493,6 +3493,11 @@ def err_static_non_static : Error<
"static declaration of %0 follows non-static declaration">;
def err_different_language_linkage : Error<
"declaration of %0 has a different language linkage">;
+def err_extern_c_global_conflict : Error<
+ "declaration of %1 %select{with C language linkage|in global scope}0 "
+ "conflicts with declaration %select{in global scope|with C language linkage}0">;
+def note_extern_c_global_conflict : Note<
+ "declared %select{in global scope|with C language linkage}0 here">;
def warn_weak_import : Warning <
"an already-declared variable is made a weak_import declaration %0">;
def warn_static_non_static : ExtWarn<
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=185229&r1=185228&r2=185229&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Jun 28 17:03:51 2013
@@ -4359,10 +4359,14 @@ TryToFixInvalidVariablyModifiedTypeSourc
/// function-scope declarations.
void
Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S) {
- assert(
- !ND->getLexicalDeclContext()->getRedeclContext()->isTranslationUnit() &&
- "Decl is not a locally-scoped decl!");
+ if (!getLangOpts().CPlusPlus &&
+ ND->getLexicalDeclContext()->getRedeclContext()->isTranslationUnit())
+ // Don't need to track declarations in the TU in C.
+ return;
+
// Note that we have a locally-scoped external with this name.
+ // FIXME: There can be multiple such declarations if they are functions marked
+ // __attribute__((overloadable)) declared in function scope in C.
LocallyScopedExternCDecls[ND->getDeclName()] = ND;
}
@@ -4681,6 +4685,32 @@ static bool isFunctionDefinitionDiscarde
return isC99Inline;
}
+/// Determine whether a variable is extern "C" prior to attaching
+/// an initializer. We can't just call isExternC() here, because that
+/// will also compute and cache whether the declaration is externally
+/// visible, which might change when we attach the initializer.
+///
+/// This can only be used if the declaration is known to not be a
+/// redeclaration of an internal linkage declaration.
+///
+/// For instance:
+///
+/// auto x = []{};
+///
+/// Attaching the initializer here makes this declaration not externally
+/// visible, because its type has internal linkage.
+///
+/// FIXME: This is a hack.
+template<typename T>
+static bool isIncompleteDeclExternC(Sema &S, const T *D) {
+ if (S.getLangOpts().CPlusPlus) {
+ // In C++, the overloadable attribute negates the effects of extern "C".
+ if (!D->isInExternCContext() || D->template hasAttr<OverloadableAttr>())
+ return false;
+ }
+ return D->isExternC();
+}
+
static bool shouldConsiderLinkage(const VarDecl *VD) {
const DeclContext *DC = VD->getDeclContext()->getRedeclContext();
if (DC->isFunctionOrMethod())
@@ -5070,16 +5100,10 @@ Sema::ActOnVariableDeclarator(Scope *S,
ProcessPragmaWeak(S, NewVD);
checkAttributesAfterMerging(*this, *NewVD);
- // If this is the first declaration of an extern C variable that is not
- // declared directly in the translation unit, update the map of such
- // variables.
- if (!CurContext->getRedeclContext()->isTranslationUnit() &&
- !NewVD->getPreviousDecl() && !NewVD->isInvalidDecl() &&
- // FIXME: We only check isExternC if we're in an extern C context,
- // to avoid computing and caching an 'externally visible' flag which
- // could change if the variable's type is not visible.
- (!getLangOpts().CPlusPlus || NewVD->isInExternCContext()) &&
- NewVD->isExternC())
+ // If this is the first declaration of an extern C variable, update
+ // the map of such variables.
+ if (!NewVD->getPreviousDecl() && !NewVD->isInvalidDecl() &&
+ isIncompleteDeclExternC(*this, NewVD))
RegisterLocallyScopedExternCDecl(NewVD, S);
return NewVD;
@@ -5180,30 +5204,120 @@ void Sema::CheckShadow(Scope *S, VarDecl
CheckShadow(S, D, R);
}
+/// Check for conflict between this global or extern "C" declaration and
+/// previous global or extern "C" declarations. This is only used in C++.
template<typename T>
-static bool mayConflictWithNonVisibleExternC(const T *ND) {
- const DeclContext *DC = ND->getDeclContext();
- if (DC->getRedeclContext()->isTranslationUnit())
- return true;
+static bool checkGlobalOrExternCConflict(
+ Sema &S, const T *ND, bool IsGlobal, LookupResult &Previous) {
+ assert(S.getLangOpts().CPlusPlus && "only C++ has extern \"C\"");
+ NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName());
+
+ if (!Prev && IsGlobal && !isIncompleteDeclExternC(S, ND)) {
+ // The common case: this global doesn't conflict with any extern "C"
+ // declaration.
+ return false;
+ }
- // We know that is the first decl we see, other than function local
- // extern C ones. If this is C++ and the decl is not in a extern C context
- // it cannot have C language linkage. Avoid calling isExternC in that case.
- // We need to this because of code like
- //
- // namespace { struct bar {}; }
- // auto foo = bar();
- //
- // This code runs before the init of foo is set, and therefore before
- // the type of foo is known. Not knowing the type we cannot know its linkage
- // unless it is in an extern C block.
- if (!ND->isInExternCContext()) {
- const ASTContext &Context = ND->getASTContext();
- if (Context.getLangOpts().CPlusPlus)
+ if (Prev) {
+ if (!IsGlobal || isIncompleteDeclExternC(S, ND)) {
+ // Both the old and new declarations have C language linkage. This is a
+ // redeclaration.
+ Previous.clear();
+ Previous.addDecl(Prev);
+ return true;
+ }
+
+ // This is a global, non-extern "C" declaration, and there is a previous
+ // non-global extern "C" declaration. Diagnose.
+ } else {
+ // The declaration is extern "C". Check for any declaration in the
+ // translation unit which might conflict.
+ if (IsGlobal) {
+ // We have already performed the lookup into the translation unit.
+ IsGlobal = false;
+ for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
+ I != E; ++I) {
+ if (isa<VarDecl>(*I) || isa<FunctionDecl>(*I)) {
+ Prev = *I;
+ break;
+ }
+ }
+ } else {
+ DeclContext::lookup_result R =
+ S.Context.getTranslationUnitDecl()->lookup(ND->getDeclName());
+ for (DeclContext::lookup_result::iterator I = R.begin(), E = R.end();
+ I != E; ++I) {
+ if (isa<VarDecl>(*I) || isa<FunctionDecl>(*I)) {
+ Prev = *I;
+ break;
+ }
+ // FIXME: If we have any other entity with this name in global scope,
+ // the declaration is ill-formed, but that is a defect: it breaks the
+ // 'stat' hack, for instance.
+ }
+ }
+
+ if (!Prev)
return false;
}
- return ND->isExternC();
+ // Use the first declaration's location to ensure we point at something which
+ // is lexically inside an extern "C" linkage-spec.
+ assert(Prev && "should have found a previous declaration to diagnose");
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Prev))
+ Prev = FD->getFirstDeclaration();
+ else
+ Prev = cast<VarDecl>(Prev)->getFirstDeclaration();
+
+ S.Diag(ND->getLocation(), diag::err_extern_c_global_conflict)
+ << IsGlobal << ND;
+ S.Diag(Prev->getLocation(), diag::note_extern_c_global_conflict)
+ << IsGlobal;
+ return false;
+}
+
+/// Apply special rules for handling extern "C" declarations. Returns \c true
+/// if we have found that this is a redeclaration of some prior entity.
+///
+/// Per C++ [dcl.link]p6:
+/// Two declarations [for a function or variable] with C language linkage
+/// with the same name that appear in different scopes refer to the same
+/// [entity]. An entity with C language linkage shall not be declared with
+/// the same name as an entity in global scope.
+template<typename T>
+static bool checkForConflictWithNonVisibleExternC(Sema &S, const T *ND,
+ LookupResult &Previous) {
+ if (!S.getLangOpts().CPlusPlus) {
+ // In C, when declaring a global variable, look for a corresponding 'extern'
+ // variable declared in function scope.
+ //
+ // FIXME: The corresponding case in C++ does not work. We should instead
+ // set the semantic DC for an extern local variable to be the innermost
+ // enclosing namespace, and ensure they are only found by redeclaration
+ // lookup.
+ if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
+ if (NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName())) {
+ Previous.clear();
+ Previous.addDecl(Prev);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // A declaration in the translation unit can conflict with an extern "C"
+ // declaration.
+ if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit())
+ return checkGlobalOrExternCConflict(S, ND, /*IsGlobal*/true, Previous);
+
+ // An extern "C" declaration can conflict with a declaration in the
+ // translation unit or can be a redeclaration of an extern "C" declaration
+ // in another scope.
+ if (isIncompleteDeclExternC(S,ND))
+ return checkGlobalOrExternCConflict(S, ND, /*IsGlobal*/false, Previous);
+
+ // Neither global nor extern "C": nothing to do.
+ return false;
}
void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
@@ -5386,14 +5500,9 @@ bool Sema::CheckVariableDeclaration(VarD
// The most important point here is that we're not allowed to
// update our understanding of the type according to declarations
// not in scope.
- bool PreviousWasHidden = false;
- if (Previous.empty() && mayConflictWithNonVisibleExternC(NewVD)) {
- if (NamedDecl *ExternCPrev =
- findLocallyScopedExternCDecl(NewVD->getDeclName())) {
- Previous.addDecl(ExternCPrev);
- PreviousWasHidden = true;
- }
- }
+ bool PreviousWasHidden =
+ Previous.empty() &&
+ checkForConflictWithNonVisibleExternC(*this, NewVD, Previous);
// Filter out any non-conflicting previous declarations.
filterNonConflictingPreviousDecls(Context, NewVD, Previous);
@@ -6625,12 +6734,10 @@ Sema::ActOnFunctionDeclarator(Scope *S,
// marking the function.
AddCFAuditedAttribute(NewFD);
- // If this is the first declaration of an extern C variable that is not
- // declared directly in the translation unit, update the map of such
- // variables.
- if (!CurContext->getRedeclContext()->isTranslationUnit() &&
- !NewFD->getPreviousDecl() && NewFD->isExternC() &&
- !NewFD->isInvalidDecl())
+ // If this is the first declaration of an extern C variable, update
+ // the map of such variables.
+ if (!NewFD->getPreviousDecl() && !NewFD->isInvalidDecl() &&
+ isIncompleteDeclExternC(*this, NewFD))
RegisterLocallyScopedExternCDecl(NewFD, S);
// Set this FunctionDecl's range up to the right paren.
@@ -6734,15 +6841,6 @@ bool Sema::CheckFunctionDeclaration(Scop
assert(!NewFD->getResultType()->isVariablyModifiedType()
&& "Variably modified return types are not handled here");
- // Check for a previous declaration of this name.
- if (Previous.empty() && mayConflictWithNonVisibleExternC(NewFD)) {
- // Since we did not find anything by this name, look for a non-visible
- // extern "C" declaration with the same name.
- if (NamedDecl *ExternCPrev =
- findLocallyScopedExternCDecl(NewFD->getDeclName()))
- Previous.addDecl(ExternCPrev);
- }
-
// Filter out any non-conflicting previous declarations.
filterNonConflictingPreviousDecls(Context, NewFD, Previous);
@@ -6796,6 +6894,34 @@ bool Sema::CheckFunctionDeclaration(Scop
}
}
}
+
+ // Check for a previous extern "C" declaration with this name.
+ if (!Redeclaration &&
+ checkForConflictWithNonVisibleExternC(*this, NewFD, Previous)) {
+ filterNonConflictingPreviousDecls(Context, NewFD, Previous);
+ if (!Previous.empty()) {
+ // This is an extern "C" declaration with the same name as a previous
+ // declaration, and thus redeclares that entity...
+ Redeclaration = true;
+ OldDecl = Previous.getFoundDecl();
+
+ // ... except in the presence of __attribute__((overloadable)).
+ if (OldDecl->hasAttr<OverloadableAttr>()) {
+ if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) {
+ Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
+ << Redeclaration << NewFD;
+ Diag(Previous.getFoundDecl()->getLocation(),
+ diag::note_attribute_overloadable_prev_overload);
+ NewFD->addAttr(::new (Context) OverloadableAttr(SourceLocation(),
+ Context));
+ }
+ if (IsOverload(NewFD, cast<FunctionDecl>(OldDecl), false)) {
+ Redeclaration = false;
+ OldDecl = 0;
+ }
+ }
+ }
+ }
// C++11 [dcl.constexpr]p8:
// A constexpr specifier for a non-static member function that is not
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=185229&r1=185228&r2=185229&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Jun 28 17:03:51 2013
@@ -977,21 +977,12 @@ Sema::CheckOverload(Scope *S, FunctionDe
return Ovl_Overload;
}
-static bool canBeOverloaded(const FunctionDecl &D) {
- if (D.getAttr<OverloadableAttr>())
- return true;
- if (D.isExternC())
- return false;
-
- // Main cannot be overloaded (basic.start.main).
- if (D.isMain())
+bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
+ bool UseUsingDeclRules) {
+ // C++ [basic.start.main]p2: This function shall not be overloaded.
+ if (New->isMain())
return false;
- return true;
-}
-
-static bool shouldTryToOverload(Sema &S, FunctionDecl *New, FunctionDecl *Old,
- bool UseUsingDeclRules) {
FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
@@ -1002,8 +993,8 @@ static bool shouldTryToOverload(Sema &S,
return true;
// Is the function New an overload of the function Old?
- QualType OldQType = S.Context.getCanonicalType(Old->getType());
- QualType NewQType = S.Context.getCanonicalType(New->getType());
+ QualType OldQType = Context.getCanonicalType(Old->getType());
+ QualType NewQType = Context.getCanonicalType(New->getType());
// Compare the signatures (C++ 1.3.10) of the two functions to
// determine whether they are overloads. If we find any mismatch
@@ -1024,7 +1015,7 @@ static bool shouldTryToOverload(Sema &S,
if (OldQType != NewQType &&
(OldType->getNumArgs() != NewType->getNumArgs() ||
OldType->isVariadic() != NewType->isVariadic() ||
- !S.FunctionArgTypesAreEqual(OldType, NewType)))
+ !FunctionArgTypesAreEqual(OldType, NewType)))
return true;
// C++ [temp.over.link]p4:
@@ -1040,9 +1031,9 @@ static bool shouldTryToOverload(Sema &S,
// However, we don't consider either of these when deciding whether
// a member introduced by a shadow declaration is hidden.
if (!UseUsingDeclRules && NewTemplate &&
- (!S.TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
- OldTemplate->getTemplateParameters(),
- false, S.TPL_TemplateMatch) ||
+ (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
+ OldTemplate->getTemplateParameters(),
+ false, TPL_TemplateMatch) ||
OldType->getResultType() != NewType->getResultType()))
return true;
@@ -1068,9 +1059,9 @@ static bool shouldTryToOverload(Sema &S,
// declarations with the same name, the same parameter-type-list, and
// the same template parameter lists cannot be overloaded if any of
// them, but not all, have a ref-qualifier (8.3.5).
- S.Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
+ Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
<< NewMethod->getRefQualifier() << OldMethod->getRefQualifier();
- S.Diag(OldMethod->getLocation(), diag::note_previous_declaration);
+ Diag(OldMethod->getLocation(), diag::note_previous_declaration);
}
return true;
}
@@ -1080,7 +1071,7 @@ static bool shouldTryToOverload(Sema &S,
// or non-static member function). Add it now, on the assumption that this
// is a redeclaration of OldMethod.
unsigned NewQuals = NewMethod->getTypeQualifiers();
- if (!S.getLangOpts().CPlusPlus1y && NewMethod->isConstexpr() &&
+ if (!getLangOpts().CPlusPlus1y && NewMethod->isConstexpr() &&
!isa<CXXConstructorDecl>(NewMethod))
NewQuals |= Qualifiers::Const;
if (OldMethod->getTypeQualifiers() != NewQuals)
@@ -1091,19 +1082,6 @@ static bool shouldTryToOverload(Sema &S,
return false;
}
-bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
- bool UseUsingDeclRules) {
- if (!shouldTryToOverload(*this, New, Old, UseUsingDeclRules))
- return false;
-
- // If both of the functions are extern "C", then they are not
- // overloads.
- if (!canBeOverloaded(*Old) && !canBeOverloaded(*New))
- return false;
-
- return true;
-}
-
/// \brief Checks availability of the function depending on the current
/// function context. Inside an unavailable function, unavailability is ignored.
///
Modified: cfe/trunk/test/CXX/class.access/class.friend/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/class.friend/p1.cpp?rev=185229&r1=185228&r2=185229&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/class.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/class.access/class.friend/p1.cpp Fri Jun 28 17:03:51 2013
@@ -287,22 +287,22 @@ namespace test9 {
// PR7230
namespace test10 {
- extern "C" void f(void);
- extern "C" void g(void);
+ extern "C" void test10_f(void);
+ extern "C" void test10_g(void);
namespace NS {
class C {
void foo(void); // expected-note {{declared private here}}
- friend void test10::f(void);
+ friend void test10::test10_f(void);
};
static C* bar;
}
- void f(void) {
+ void test10_f(void) {
NS::bar->foo();
}
- void g(void) {
+ void test10_g(void) {
NS::bar->foo(); // expected-error {{private member}}
}
}
Modified: cfe/trunk/test/Sema/overloadable.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/overloadable.c?rev=185229&r1=185228&r2=185229&view=diff
==============================================================================
--- cfe/trunk/test/Sema/overloadable.c (original)
+++ cfe/trunk/test/Sema/overloadable.c Fri Jun 28 17:03:51 2013
@@ -69,3 +69,18 @@ void test() {
f0();
f1();
}
+
+void before_local_1(int) __attribute__((overloadable)); // expected-note {{here}}
+void before_local_2(int); // expected-note {{here}}
+void before_local_3(int) __attribute__((overloadable));
+void local() {
+ void before_local_1(char); // expected-error {{must have the 'overloadable' attribute}}
+ void before_local_2(char) __attribute__((overloadable)); // expected-error {{conflicting types}}
+ void before_local_3(char) __attribute__((overloadable));
+ void after_local_1(char); // expected-note {{here}}
+ void after_local_2(char) __attribute__((overloadable)); // expected-note {{here}}
+ void after_local_3(char) __attribute__((overloadable));
+}
+void after_local_1(int) __attribute__((overloadable)); // expected-error {{conflicting types}}
+void after_local_2(int); // expected-error {{must have the 'overloadable' attribute}}
+void after_local_3(int) __attribute__((overloadable));
Modified: cfe/trunk/test/SemaCXX/extern-c.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/extern-c.cpp?rev=185229&r1=185228&r2=185229&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/extern-c.cpp (original)
+++ cfe/trunk/test/SemaCXX/extern-c.cpp Fri Jun 28 17:03:51 2013
@@ -3,20 +3,20 @@
namespace test1 {
extern "C" {
void test1_f() {
- void test1_g(int); // expected-note {{previous declaration is here}}
+ void test1_g(int); // expected-note {{declared with C language linkage here}}
}
}
}
-int test1_g(int); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+int test1_g(int); // expected-error {{declaration of 'test1_g' in global scope conflicts with declaration with C language linkage}}
namespace test2 {
extern "C" {
void test2_f() {
- extern int test2_x; // expected-note {{previous definition is here}}
+ extern int test2_x; // expected-note {{declared with C language linkage here}}
}
}
}
-float test2_x; // expected-error {{redefinition of 'test2_x' with a different type: 'float' vs 'int'}}
+float test2_x; // expected-error {{declaration of 'test2_x' in global scope conflicts with declaration with C language linkage}}
namespace test3 {
extern "C" {
@@ -31,18 +31,18 @@ namespace test3 {
extern "C" {
void test4_f() {
- extern int test4_b; // expected-note {{previous definition is here}}
+ extern int test4_b; // expected-note {{declared with C language linkage here}}
}
}
-static float test4_b; // expected-error {{redefinition of 'test4_b' with a different type: 'float' vs 'int'}}
+static float test4_b; // expected-error {{declaration of 'test4_b' in global scope conflicts with declaration with C language linkage}}
extern "C" {
void test5_f() {
- extern int test5_b; // expected-note {{previous definition is here}}
+ extern int test5_b; // expected-note {{declared with C language linkage here}}
}
}
extern "C" {
- static float test5_b; // expected-error {{redefinition of 'test5_b' with a different type: 'float' vs 'int'}}
+ static float test5_b; // expected-error {{declaration of 'test5_b' in global scope conflicts with declaration with C language linkage}}
}
extern "C" {
@@ -69,11 +69,11 @@ namespace linkage {
}
}
namespace from_outer {
- void linkage_from_outer_1();
+ void linkage_from_outer_1(); // expected-note {{previous}}
void linkage_from_outer_2(); // expected-note {{previous}}
extern "C" {
- void linkage_from_outer_1(int); // expected-note {{previous}}
- void linkage_from_outer_1(); // expected-error {{conflicting types}}
+ void linkage_from_outer_1(int);
+ void linkage_from_outer_1(); // expected-error {{different language linkage}}
void linkage_from_outer_2(); // expected-error {{different language linkage}}
}
}
@@ -98,11 +98,44 @@ namespace linkage {
}
}
-void lookup_in_global_f();
+void lookup_in_global_f(); // expected-note {{here}}
namespace lookup_in_global {
void lookup_in_global_f();
+ void lookup_in_global_g();
extern "C" {
- // FIXME: We should reject this.
- void lookup_in_global_f(int);
+ void lookup_in_global_f(int); // expected-error {{conflicts with declaration in global scope}}
+ void lookup_in_global_g(int); // expected-note {{here}}
}
}
+void lookup_in_global_g(); // expected-error {{conflicts with declaration with C language linkage}}
+
+namespace N1 {
+ extern "C" int different_kind_1; // expected-note {{here}}
+ extern "C" void different_kind_2(); // expected-note {{here}}
+}
+namespace N2 {
+ extern "C" void different_kind_1(); // expected-error {{different kind of symbol}}
+ extern "C" int different_kind_2; // expected-error {{different kind of symbol}}
+}
+
+extern "C" {
+ struct stat {};
+ void stat(struct stat);
+}
+namespace X {
+ extern "C" {
+ void stat(struct ::stat);
+ }
+}
+
+extern "C" void name_with_using_decl_1(int);
+namespace using_decl {
+ void name_with_using_decl_1();
+ void name_with_using_decl_2();
+ void name_with_using_decl_3();
+}
+using using_decl::name_with_using_decl_1;
+using using_decl::name_with_using_decl_2;
+extern "C" void name_with_using_decl_2(int);
+extern "C" void name_with_using_decl_3(int);
+using using_decl::name_with_using_decl_3;
Modified: cfe/trunk/test/SemaCXX/friend.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/friend.cpp?rev=185229&r1=185228&r2=185229&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/friend.cpp (original)
+++ cfe/trunk/test/SemaCXX/friend.cpp Fri Jun 28 17:03:51 2013
@@ -134,7 +134,7 @@ namespace test6_3 {
namespace test7 {
extern "C" {
class X {
- friend int f() { return 42; }
+ friend int test7_f() { return 42; }
};
}
}
Modified: cfe/trunk/test/SemaCXX/linkage-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/linkage-spec.cpp?rev=185229&r1=185228&r2=185229&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/linkage-spec.cpp (original)
+++ cfe/trunk/test/SemaCXX/linkage-spec.cpp Fri Jun 28 17:03:51 2013
@@ -41,20 +41,32 @@ namespace pr5430 {
using namespace pr5430;
extern "C" void pr5430::func(void) { }
-// PR5404
-int f2(char *)
+// PR5405
+int f2(char *) // expected-note {{here}}
{
return 0;
}
extern "C"
{
- int f2(int)
+ int f2(int) // expected-error {{with C language linkage conflicts with declaration in global scope}}
{
return f2((char *)0);
}
}
+namespace PR5405 {
+ int f2b(char *) {
+ return 0;
+ }
+
+ extern "C" {
+ int f2b(int) {
+ return f2b((char *)0); // ok
+ }
+ }
+}
+
// PR6991
extern "C" typedef int (*PutcFunc_t)(int);
@@ -117,3 +129,28 @@ namespace pr14958 {
extern "C" void PR16167; // expected-error {{variable has incomplete type 'void'}}
extern void PR16167_0; // expected-error {{variable has incomplete type 'void'}}
+
+// PR7927
+enum T_7927 {
+ E_7927
+};
+
+extern "C" void f_pr7927(int);
+
+namespace {
+ extern "C" void f_pr7927(int);
+
+ void foo_pr7927() {
+ f_pr7927(E_7927);
+ f_pr7927(0);
+ ::f_pr7927(E_7927);
+ ::f_pr7927(0);
+ }
+}
+
+void bar_pr7927() {
+ f_pr7927(E_7927);
+ f_pr7927(0);
+ ::f_pr7927(E_7927);
+ ::f_pr7927(0);
+}
Modified: cfe/trunk/test/SemaCXX/linkage2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/linkage2.cpp?rev=185229&r1=185228&r2=185229&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/linkage2.cpp (original)
+++ cfe/trunk/test/SemaCXX/linkage2.cpp Fri Jun 28 17:03:51 2013
@@ -201,3 +201,15 @@ namespace test18 {
}
void *h() { return f(); }
}
+
+extern "C" void pr16247_foo(int); // expected-note {{here}}
+static void pr16247_foo(double); // expected-error {{conflicts with declaration with C language linkage}}
+void pr16247_foo(int) {}
+void pr16247_foo(double) {}
+
+namespace PR16247 {
+ extern "C" void pr16247_bar(int);
+ static void pr16247_bar(double);
+ void pr16247_bar(int) {}
+ void pr16247_bar(double) {}
+}
More information about the cfe-commits
mailing list