From: Abramo Bagnara Date: Fri, 30 Jul 2010 16:47:02 +0000 (+0000) Subject: Fixed typedef inside extern "C". X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=35f9a196ef897b9559de25aaecd957208f0b4f59;p=clang 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/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 0e6dbecb36..b9fa6503b4 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -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(); } diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index d2cd74418a..c5072276bc 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -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, diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 7ed07a277c..bd8c245f55 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -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()); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 9657b8deb9..d6d13384b2 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(DC) && - !cast(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(DC) && - !cast(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 diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 34b0d96c08..3e48d5caee 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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. diff --git a/test/SemaCXX/linkage-spec.cpp b/test/SemaCXX/linkage-spec.cpp index 57730a62aa..0d1c166dcb 100644 --- a/test/SemaCXX/linkage-spec.cpp +++ b/test/SemaCXX/linkage-spec.cpp @@ -54,3 +54,6 @@ extern "C" return f2((char *)0); } } + +// PR6991 +extern "C" typedef int (*PutcFunc_t)(int);