Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -325,6 +325,11 @@ def warn_unused_private_field: Warning<"private field %0 is not used">, InGroup, DefaultIgnore; +def err_return_value_linkage: Error< + "%0 has C-linkage specified, but return type %1 has internal linkage">; +def err_parameter_value_linkage: Error< + "%0 has C-linkage specified, but parameter type %1 has internal linkage">; + def warn_parameter_size: Warning< "%0 is a large (%1 bytes) pass-by-value argument; " "pass it by reference instead ?">, InGroup; Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -8218,6 +8218,25 @@ Diag(NewFD->getLocation(), diag::ext_out_of_line_declaration) << D.getCXXScopeSpec().getRange(); } + + if (NewFD->isExternC()) { + // Check return type linkage + QualType R = NewFD->getReturnType(); + if (R.getTypePtr()->getLinkage() != Linkage::ExternalLinkage) { + Diag(NewFD->getLocation(), diag::err_return_value_linkage) + << NewFD << R; + NewFD->setInvalidDecl(); + } + // Check parameter type linkage + for (auto param : NewFD->parameters()) { + QualType P = param->getOriginalType(); + if (P.getTypePtr()->getLinkage() != Linkage::ExternalLinkage) { + Diag(NewFD->getLocation(), diag::err_parameter_value_linkage) + << NewFD << P; + NewFD->setInvalidDecl(); + } + } + } } ProcessPragmaWeak(S, NewFD); Index: test/CXX/drs/dr3xx.cpp =================================================================== --- test/CXX/drs/dr3xx.cpp +++ test/CXX/drs/dr3xx.cpp @@ -232,8 +232,8 @@ typedef struct { int i; } *ps; - extern "C" void f(ps); - void g(ps); // FIXME: ill-formed, type 'ps' has no linkage + extern "C" void f(ps); // expected-error-re {{'f' has C-linkage specified, but parameter type 'ps' (aka 'dr319::(anonymous struct {{.*}} *') has internal linkage}} + void g(ps); static enum { e } a1; enum { e2 } a2; // FIXME: ill-formed, enum type has no linkage Index: test/Sema/pr23090-crash-on-invalid.cpp =================================================================== --- /dev/null +++ test/Sema/pr23090-crash-on-invalid.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// Don't crash (PR23090). + +namespace { + +// check return type +struct A; +extern "C" A *foo(); // expected-error {{'foo' has C-linkage specified, but return type '(anonymous namespace)::A *' has internal linkage}} +A *foo(); + +// check parameter +struct B; +extern "C" void bar(B*); // expected-error {{'bar' has C-linkage specified, but parameter type '(anonymous namespace)::B *' has internal linkage}} +void bar(B*); + +} Index: test/SemaCXX/linkage.cpp =================================================================== --- test/SemaCXX/linkage.cpp +++ test/SemaCXX/linkage.cpp @@ -57,13 +57,14 @@ namespace test3 { namespace { struct A {}; } + struct B {}; // CHECK: define internal void @_ZN5test34testENS_12_GLOBAL__N_11AE( void test(A a) {} void force() { test(A()); } // CHECK: define void @test3( - extern "C" void test3(A a) {} + extern "C" void test3(B b) {} } namespace { @@ -71,29 +72,6 @@ extern "C" void test4(void) {} } -// PR9316: Ensure that even non-namespace-scope function declarations in -// a C declaration context respect that over the anonymous namespace. -extern "C" { - namespace { - struct X { - int f() { - extern int g(); - extern int a; - - // Test both for mangling in the code generation and warnings from use - // of internal, undefined names via -Werror. - // CHECK: call i32 @g( - // CHECK: load i32, i32* @a, - return g() + a; - } - }; - } - // Force the above function to be emitted by codegen. - int test(X& x) { - return x.f(); - } -} - // CHECK: define linkonce_odr i8* @_ZN5test11A3fooILj0EEEPvv( // CHECK: define linkonce_odr i8* @_ZN5test21A1BILj0EE3fooEv( Index: test/SemaCXX/warn-unused-filescoped.cpp =================================================================== --- test/SemaCXX/warn-unused-filescoped.cpp +++ test/SemaCXX/warn-unused-filescoped.cpp @@ -121,7 +121,6 @@ namespace { struct A {}; } void test(A a); // expected-warning {{unused function}} - extern "C" void test4(A a); } namespace rdar8733476 {