Fixed typedef inside extern "C".

llvm-svn: 109865
This commit is contained in:
Abramo Bagnara 2010-07-30 16:47:02 +00:00
parent 14eb7bd769
commit ed5b6899ab
6 changed files with 40 additions and 36 deletions

View File

@ -162,6 +162,7 @@ private:
// 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;
@ -221,9 +222,7 @@ private:
WrittenBuiltinSpecs writtenBS;
void SaveWrittenBuiltinSpecs();
void SaveStorageSpecifierAsWritten() {
StorageClassSpecAsWritten = StorageClassSpec;
}
void SaveStorageSpecifierAsWritten();
DeclSpec(const DeclSpec&); // DO NOT IMPLEMENT
void operator=(const DeclSpec&); // DO NOT IMPLEMENT
@ -232,6 +231,7 @@ public:
DeclSpec()
: StorageClassSpec(SCS_unspecified),
SCS_thread_specified(false),
SCS_extern_in_linkage_spec(false),
TypeSpecWidth(TSW_unspecified),
TypeSpecComplex(TSC_unspecified),
TypeSpecSign(TSS_unspecified),
@ -262,6 +262,10 @@ public:
// 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; }
@ -269,6 +273,7 @@ public:
void ClearStorageClassSpecs() {
StorageClassSpec = DeclSpec::SCS_unspecified;
SCS_thread_specified = false;
SCS_extern_in_linkage_spec = false;
StorageClassSpecLoc = SourceLocation();
SCS_threadLoc = SourceLocation();
}

View File

@ -219,8 +219,15 @@ const char *DeclSpec::getSpecifierName(TQ T) {
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 @@ bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc,
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::SaveWrittenBuiltinSpecs() {
}
}
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,

View File

@ -196,6 +196,7 @@ Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS,
}
if (Tok.isNot(tok::l_brace)) {
DS.setExternInLinkageSpec(true);
ParseDeclarationOrFunctionDefinition(DS, Attr.AttrList);
return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec,
SourceLocation());

View File

@ -1667,21 +1667,11 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S,
/// 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 @@ StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec,
/// 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 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
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 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
}
SCSpec = DS.getStorageClassSpecAsWritten();
VarDecl::StorageClass SCAsWritten
= StorageClassSpecToVarDeclStorageClass(SCSpec, 0);
= StorageClassSpecToVarDeclStorageClass(SCSpec);
Anon = VarDecl::Create(Context, Owner, Record->getLocation(),
/*IdentifierInfo=*/0,
@ -2521,7 +2501,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
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 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
VarDecl::StorageClass SCAsWritten
= StorageClassSpecToVarDeclStorageClass(SCSpec, DC);
= StorageClassSpecToVarDeclStorageClass(SCSpec);
IdentifierInfo *II = Name.getAsIdentifierInfo();
if (!II) {
@ -3016,7 +2996,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
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

View File

@ -5909,7 +5909,7 @@ Sema::DeclPtrTy Sema::ActOnStartLinkageSpecification(Scope *S,
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.

View File

@ -54,3 +54,6 @@ extern "C"
return f2((char *)0);
}
}
// PR6991
extern "C" typedef int (*PutcFunc_t)(int);