Currently clang marks these two declarations
extern "C" int a;
extern "C" void foo();
as extern in StorageClassAsWritten, but the inner declarations does not
have any storage class specified (and C++ standard does not allow any).
The attached patch wrt r102259 fixes the problem (and do not introduce
any regressions).
This patch has already been sent to cfe-dev, currently without pending
objections but without explicit approval.
http://lists.cs.uiuc.edu/pipermail/cfe-dev/2010-April/008773.html
Having just obtained write access, is it ok if I commit it in?
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp (revision 102259)
+++ lib/Sema/SemaDecl.cpp (working copy)
@@ -1595,11 +1595,21 @@
/// StorageClassSpecToVarDeclStorageClass - Maps a DeclSpec::SCS to
/// a VarDecl::StorageClass. Any error reporting is up to the caller:
/// illegal input values are mapped to VarDecl::None.
+/// If the input declaration context is a linkage specification
+/// with no braces, then Extern is mapped to None.
static VarDecl::StorageClass
-StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec) {
+StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec,
+ DeclContext *DC) {
switch (StorageClassSpec) {
case DeclSpec::SCS_unspecified: return VarDecl::None;
- case DeclSpec::SCS_extern: return VarDecl::Extern;
+ case DeclSpec::SCS_extern:
+ // If the current context is a C++ linkage specification
+ // having no braces, then the keyword "extern" is properly part
+ // of the linkage specification itself, rather than being
+ // the written storage class specifier.
+ return (DC && isa<LinkageSpecDecl>(DC) &&
+ !cast<LinkageSpecDecl>(DC)->hasBraces())
+ ? VarDecl::None : VarDecl::Extern;
case DeclSpec::SCS_static: return VarDecl::Static;
case DeclSpec::SCS_auto: return VarDecl::Auto;
case DeclSpec::SCS_register: return VarDecl::Register;
@@ -1614,11 +1624,21 @@
/// StorageClassSpecToFunctionDeclStorageClass - Maps a DeclSpec::SCS to
/// a FunctionDecl::StorageClass. Any error reporting is up to the caller:
/// illegal input values are mapped to FunctionDecl::None.
+/// If the input declaration context is a linkage specification
+/// with no braces, then Extern is mapped to None.
static FunctionDecl::StorageClass
-StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec) {
+StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec,
+ DeclContext *DC) {
switch (StorageClassSpec) {
case DeclSpec::SCS_unspecified: return FunctionDecl::None;
- case DeclSpec::SCS_extern: return FunctionDecl::Extern;
+ case DeclSpec::SCS_extern:
+ // If the current context is a C++ linkage specification
+ // having no braces, then the keyword "extern" is properly part
+ // of the linkage specification itself, rather than being
+ // the written storage class specifier.
+ return (DC && isa<LinkageSpecDecl>(DC) &&
+ !cast<LinkageSpecDecl>(DC)->hasBraces())
+ ? FunctionDecl::None : FunctionDecl::Extern;
case DeclSpec::SCS_static: return FunctionDecl::Static;
case DeclSpec::SCS_private_extern: return FunctionDecl::PrivateExtern;
// Illegal SCSs map to None: error reporting is up to the caller.
@@ -1753,7 +1773,7 @@
DeclSpec::SCS SCSpec = DS.getStorageClassSpec();
assert(SCSpec != DeclSpec::SCS_typedef &&
"Parser allowed 'typedef' as storage class VarDecl.");
- VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec);
+ VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec, 0);
if (SCSpec == DeclSpec::SCS_mutable) {
// mutable can only appear on non-static class members, so it's always
// an error here
@@ -1763,7 +1783,7 @@
}
SCSpec = DS.getStorageClassSpecAsWritten();
VarDecl::StorageClass SCAsWritten
- = StorageClassSpecToVarDeclStorageClass(SCSpec);
+ = StorageClassSpecToVarDeclStorageClass(SCSpec, 0);
Anon = VarDecl::Create(Context, Owner, Record->getLocation(),
/*IdentifierInfo=*/0,
@@ -2369,7 +2389,7 @@
DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
assert(SCSpec != DeclSpec::SCS_typedef &&
"Parser allowed 'typedef' as storage class VarDecl.");
- VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec);
+ VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec, 0);
if (SCSpec == DeclSpec::SCS_mutable) {
// mutable can only appear on non-static class members, so it's always
// an error here
@@ -2379,7 +2399,7 @@
}
SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
VarDecl::StorageClass SCAsWritten
- = StorageClassSpecToVarDeclStorageClass(SCSpec);
+ = StorageClassSpecToVarDeclStorageClass(SCSpec, DC);
IdentifierInfo *II = Name.getAsIdentifierInfo();
if (!II) {
@@ -2834,7 +2854,7 @@
DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
FunctionDecl::StorageClass SCAsWritten
- = StorageClassSpecToFunctionDeclStorageClass(SCSpec);
+ = StorageClassSpecToFunctionDeclStorageClass(SCSpec, DC);
// Check that the return type is not an abstract class type.
// For record types, this is done by the AbstractClassUsageDiagnoser once
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits