Fixed typedef inside extern "C".
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109865 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index d2cd744..c507227 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -219,8 +219,15 @@
bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc,
const char *&PrevSpec,
unsigned &DiagID) {
- if (StorageClassSpec != SCS_unspecified)
- return BadSpecifier(S, (SCS)StorageClassSpec, PrevSpec, DiagID);
+ if (StorageClassSpec != SCS_unspecified) {
+ // Changing storage class is allowed only if the previous one
+ // was the 'extern' that is part of a linkage specification and
+ // the new storage class is 'typedef'.
+ if (!(SCS_extern_in_linkage_spec &&
+ StorageClassSpec == SCS_extern &&
+ S == SCS_typedef))
+ return BadSpecifier(S, (SCS)StorageClassSpec, PrevSpec, DiagID);
+ }
StorageClassSpec = S;
StorageClassSpecLoc = Loc;
assert((unsigned)S == StorageClassSpec && "SCS constants overflow bitfield");
@@ -240,7 +247,6 @@
return false;
}
-
/// These methods set the specified attribute of the DeclSpec, but return true
/// and ignore the request if invalid (e.g. "extern" then "auto" is
/// specified).
@@ -430,6 +436,15 @@
}
}
+void DeclSpec::SaveStorageSpecifierAsWritten() {
+ if (SCS_extern_in_linkage_spec && StorageClassSpec == SCS_extern)
+ // If 'extern' is part of a linkage specification,
+ // then it is not a storage class "as written".
+ StorageClassSpecAsWritten = SCS_unspecified;
+ else
+ StorageClassSpecAsWritten = StorageClassSpec;
+}
+
/// Finish - This does final analysis of the declspec, rejecting things like
/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 7ed07a2..bd8c245 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -196,6 +196,7 @@
}
if (Tok.isNot(tok::l_brace)) {
+ DS.setExternInLinkageSpec(true);
ParseDeclarationOrFunctionDefinition(DS, Attr.AttrList);
return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec,
SourceLocation());
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 9657b8d..d6d1338 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1667,21 +1667,11 @@
/// 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,
- DeclContext *DC) {
+StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec) {
switch (StorageClassSpec) {
case DeclSpec::SCS_unspecified: return VarDecl::None;
- 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_extern: return VarDecl::Extern;
case DeclSpec::SCS_static: return VarDecl::Static;
case DeclSpec::SCS_auto: return VarDecl::Auto;
case DeclSpec::SCS_register: return VarDecl::Register;
@@ -1696,21 +1686,11 @@
/// 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,
- DeclContext *DC) {
+StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec) {
switch (StorageClassSpec) {
case DeclSpec::SCS_unspecified: return FunctionDecl::None;
- 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_extern: return 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.
@@ -1851,7 +1831,7 @@
DeclSpec::SCS SCSpec = DS.getStorageClassSpec();
assert(SCSpec != DeclSpec::SCS_typedef &&
"Parser allowed 'typedef' as storage class VarDecl.");
- VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec, 0);
+ VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec);
if (SCSpec == DeclSpec::SCS_mutable) {
// mutable can only appear on non-static class members, so it's always
// an error here
@@ -1861,7 +1841,7 @@
}
SCSpec = DS.getStorageClassSpecAsWritten();
VarDecl::StorageClass SCAsWritten
- = StorageClassSpecToVarDeclStorageClass(SCSpec, 0);
+ = StorageClassSpecToVarDeclStorageClass(SCSpec);
Anon = VarDecl::Create(Context, Owner, Record->getLocation(),
/*IdentifierInfo=*/0,
@@ -2521,7 +2501,7 @@
DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
assert(SCSpec != DeclSpec::SCS_typedef &&
"Parser allowed 'typedef' as storage class VarDecl.");
- VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec, 0);
+ VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec);
if (SCSpec == DeclSpec::SCS_mutable) {
// mutable can only appear on non-static class members, so it's always
// an error here
@@ -2531,7 +2511,7 @@
}
SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
VarDecl::StorageClass SCAsWritten
- = StorageClassSpecToVarDeclStorageClass(SCSpec, DC);
+ = StorageClassSpecToVarDeclStorageClass(SCSpec);
IdentifierInfo *II = Name.getAsIdentifierInfo();
if (!II) {
@@ -3016,7 +2996,7 @@
DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
FunctionDecl::StorageClass SCAsWritten
- = StorageClassSpecToFunctionDeclStorageClass(SCSpec, DC);
+ = StorageClassSpecToFunctionDeclStorageClass(SCSpec);
// Check that the return type is not an abstract class type.
// For record types, this is done by the AbstractClassUsageDiagnoser once
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 34b0d96..3e48d5c 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -5909,7 +5909,7 @@
return DeclPtrTy::make(D);
}
-/// ActOnFinishLinkageSpecification - Completely the definition of
+/// ActOnFinishLinkageSpecification - Complete the definition of
/// the C++ linkage specification LinkageSpec. If RBraceLoc is
/// valid, it's the position of the closing '}' brace in a linkage
/// specification that uses braces.