// storage-class-specifier
/*SCS*/unsigned StorageClassSpec : 3;
bool SCS_thread_specified : 1;
+ bool SCS_extern_in_linkage_spec : 1;
// type-specifier
/*TSW*/unsigned TypeSpecWidth : 2;
WrittenBuiltinSpecs writtenBS;
void SaveWrittenBuiltinSpecs();
- void SaveStorageSpecifierAsWritten() {
- StorageClassSpecAsWritten = StorageClassSpec;
- }
+ void SaveStorageSpecifierAsWritten();
DeclSpec(const DeclSpec&); // DO NOT IMPLEMENT
void operator=(const DeclSpec&); // DO NOT IMPLEMENT
DeclSpec()
: StorageClassSpec(SCS_unspecified),
SCS_thread_specified(false),
+ SCS_extern_in_linkage_spec(false),
TypeSpecWidth(TSW_unspecified),
TypeSpecComplex(TSC_unspecified),
TypeSpecSign(TSS_unspecified),
// storage-class-specifier
SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; }
bool isThreadSpecified() const { return SCS_thread_specified; }
+ bool isExternInLinkageSpec() const { return SCS_extern_in_linkage_spec; }
+ void setExternInLinkageSpec(bool Value) {
+ SCS_extern_in_linkage_spec = Value;
+ }
SourceLocation getStorageClassSpecLoc() const { return StorageClassSpecLoc; }
SourceLocation getThreadSpecLoc() const { return SCS_threadLoc; }
void ClearStorageClassSpecs() {
StorageClassSpec = DeclSpec::SCS_unspecified;
SCS_thread_specified = false;
+ SCS_extern_in_linkage_spec = false;
StorageClassSpecLoc = SourceLocation();
SCS_threadLoc = SourceLocation();
}
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");
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).
}
}
+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,
/// 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;
/// 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.
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
}
SCSpec = DS.getStorageClassSpecAsWritten();
VarDecl::StorageClass SCAsWritten
- = StorageClassSpecToVarDeclStorageClass(SCSpec, 0);
+ = StorageClassSpecToVarDeclStorageClass(SCSpec);
Anon = VarDecl::Create(Context, Owner, Record->getLocation(),
/*IdentifierInfo=*/0,
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
}
SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
VarDecl::StorageClass SCAsWritten
- = StorageClassSpecToVarDeclStorageClass(SCSpec, DC);
+ = StorageClassSpecToVarDeclStorageClass(SCSpec);
IdentifierInfo *II = Name.getAsIdentifierInfo();
if (!II) {
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