From 38376f159513e5041d04e7cc8b5c62d59e8fa9d0 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 12 Jan 2008 07:05:38 +0000 Subject: [PATCH] Add first pieces of support for parsing and representing extern "C" in C++ mode. Patch by Mike Stump! llvm-svn: 45904 --- clang/AST/Decl.cpp | 8 +++- clang/AST/DeclSerialization.cpp | 16 ++++++++ clang/CodeGen/CodeGenModule.cpp | 10 +++++ clang/CodeGen/CodeGenModule.h | 4 ++ clang/CodeGen/ModuleBuilder.cpp | 11 ++++++ clang/Driver/ASTConsumers.cpp | 17 +++++++++ clang/Parse/ParseDeclCXX.cpp | 37 +++++++++++++++++++ clang/Parse/Parser.cpp | 9 +++++ clang/Sema/Sema.h | 3 ++ clang/Sema/SemaDecl.cpp | 21 +++++++++++ clang/include/clang/AST/Decl.h | 37 +++++++++++++++++++ clang/include/clang/Basic/DiagnosticKinds.def | 2 + clang/include/clang/CodeGen/ModuleBuilder.h | 3 ++ clang/include/clang/Parse/Action.h | 6 +++ clang/include/clang/Parse/Parser.h | 1 + 15 files changed, 184 insertions(+), 1 deletion(-) diff --git a/clang/AST/Decl.cpp b/clang/AST/Decl.cpp index f67d7124f5af..bf1ffee83233 100644 --- a/clang/AST/Decl.cpp +++ b/clang/AST/Decl.cpp @@ -37,6 +37,7 @@ static unsigned nObjCImplementationDecls = 0; static unsigned nObjCCategoryImpl = 0; static unsigned nObjCCompatibleAlias = 0; static unsigned nObjCPropertyDecl = 0; +static unsigned nLinkageSpecDecl = 0; static bool StatSwitch = false; @@ -156,7 +157,9 @@ void Decl::PrintStats() { nFileVars*sizeof(FileVarDecl)+nParmVars*sizeof(ParmVarDecl)+ nFieldDecls*sizeof(FieldDecl)+nSUC*sizeof(RecordDecl)+ nEnumDecls*sizeof(EnumDecl)+nEnumConst*sizeof(EnumConstantDecl)+ - nTypedef*sizeof(TypedefDecl)) /* FIXME: add ObjC decls */); + nTypedef*sizeof(TypedefDecl)+ + nLinkageSpecDecl*sizeof(LinkageSpecDecl)) + /* FIXME: add ObjC decls */); } void Decl::addDeclKind(const Kind k) { @@ -223,6 +226,9 @@ void Decl::addDeclKind(const Kind k) { case PropertyDecl: nObjCPropertyDecl++; break; + case LinkageSpec: + nLinkageSpecDecl++; + break; } } diff --git a/clang/AST/DeclSerialization.cpp b/clang/AST/DeclSerialization.cpp index 6baa26260265..146ebbacbe19 100644 --- a/clang/AST/DeclSerialization.cpp +++ b/clang/AST/DeclSerialization.cpp @@ -422,3 +422,19 @@ TypedefDecl* TypedefDecl::CreateImpl(Deserializer& D) { return decl; } + +//===----------------------------------------------------------------------===// +// LinkageSpec Serialization. +//===----------------------------------------------------------------------===// + +void LinkageSpecDecl::EmitInRec(Serializer& S) const { + Decl::EmitInRec(S); + S.EmitInt(getLanguage()); + S.EmitPtr(D); +} + +void LinkageSpecDecl::ReadInRec(Deserializer& D) { + Decl::ReadInRec(D); + Language = static_cast(D.ReadInt()); + D.ReadPtr(this->D); +} diff --git a/clang/CodeGen/CodeGenModule.cpp b/clang/CodeGen/CodeGenModule.cpp index 9a65d2e29671..bb61dc7cd825 100644 --- a/clang/CodeGen/CodeGenModule.cpp +++ b/clang/CodeGen/CodeGenModule.cpp @@ -44,6 +44,16 @@ void CodeGenModule::WarnUnsupported(const Stmt *S, const char *Type) { &Msg, 1, &Range, 1); } +/// WarnUnsupported - Print out a warning that codegen doesn't support the +/// specified decl yet. +void CodeGenModule::WarnUnsupported(const Decl *D, const char *Type) { + unsigned DiagID = getDiags().getCustomDiagID(Diagnostic::Warning, + "cannot codegen this %0 yet"); + std::string Msg = Type; + getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID, + &Msg, 1); +} + /// ReplaceMapValuesWith - This is a really slow and bad function that /// searches for any entries in GlobalDeclMap that point to OldVal, changing /// them to point to NewVal. This is badbadbad, FIXME! diff --git a/clang/CodeGen/CodeGenModule.h b/clang/CodeGen/CodeGenModule.h index 6653e508813e..b86ceba426be 100644 --- a/clang/CodeGen/CodeGenModule.h +++ b/clang/CodeGen/CodeGenModule.h @@ -95,6 +95,10 @@ public: /// specified stmt yet. void WarnUnsupported(const Stmt *S, const char *Type); + /// WarnUnsupported - Print out a warning that codegen doesn't support the + /// specified decl yet. + void WarnUnsupported(const Decl *D, const char *Type); + private: /// ReplaceMapValuesWith - This is a really slow and bad function that /// searches for any entries in GlobalDeclMap that point to OldVal, changing diff --git a/clang/CodeGen/ModuleBuilder.cpp b/clang/CodeGen/ModuleBuilder.cpp index 49881c36d940..fff5b3fbfff2 100644 --- a/clang/CodeGen/ModuleBuilder.cpp +++ b/clang/CodeGen/ModuleBuilder.cpp @@ -13,6 +13,7 @@ #include "clang/CodeGen/ModuleBuilder.h" #include "CodeGenModule.h" +#include "clang/AST/Decl.h" using namespace clang; @@ -34,6 +35,16 @@ void clang::CodeGen::CodeGenFunction(CodeGenModule *B, FunctionDecl *D) { B->EmitFunction(D); } +/// CodeGenLinkageSpec - Emit the specified linkage space to LLVM. +void clang::CodeGen::CodeGenLinkageSpec(CodeGenModule *Builder, + LinkageSpecDecl *LS) { + if (LS->getLanguage() == LinkageSpecDecl::lang_cxx) + Builder->WarnUnsupported(LS, "linkage spec"); + + // FIXME: implement C++ linkage, C linkage works mostly by C + // language reuse already. +} + /// CodeGenGlobalVar - Emit the specified global variable to LLVM. void clang::CodeGen::CodeGenGlobalVar(CodeGenModule *Builder, FileVarDecl *D) { Builder->EmitGlobalVarDeclarator(D); diff --git a/clang/Driver/ASTConsumers.cpp b/clang/Driver/ASTConsumers.cpp index aa49e2adc548..1bbdf388c499 100644 --- a/clang/Driver/ASTConsumers.cpp +++ b/clang/Driver/ASTConsumers.cpp @@ -39,6 +39,7 @@ namespace { void PrintDecl(Decl *D); void PrintFunctionDeclStart(FunctionDecl *FD); void PrintTypeDefDecl(TypedefDecl *TD); + void PrintLinkageSpec(LinkageSpecDecl *LS); void PrintObjCMethodDecl(ObjCMethodDecl *OMD); void PrintObjCImplementationDecl(ObjCImplementationDecl *OID); void PrintObjCInterfaceDecl(ObjCInterfaceDecl *OID); @@ -94,6 +95,8 @@ void DeclPrinter:: PrintDecl(Decl *D) { Out << "Read top-level tag decl: '" << TD->getName() << "'\n"; } else if (ScopedDecl *SD = dyn_cast(D)) { Out << "Read top-level variable decl: '" << SD->getName() << "'\n"; + } else if (LinkageSpecDecl *LSD = dyn_cast(D)) { + PrintLinkageSpec(LSD); } else { assert(0 && "Unknown decl type!"); } @@ -152,6 +155,18 @@ void DeclPrinter::PrintTypeDefDecl(TypedefDecl *TD) { Out << "typedef " << S << ";\n"; } +void DeclPrinter::PrintLinkageSpec(LinkageSpecDecl *LS) { + const char *l; + if (LS->getLanguage() == LinkageSpecDecl::lang_c) + l = "C"; + else if (LS->getLanguage() == LinkageSpecDecl::lang_cxx) + l = "C++"; + else assert(0 && "unknown language in linkage specification"); + Out << "extern \"" << l << "\" { "; + PrintDecl(LS->getDecl()); + Out << "}\n"; +} + void DeclPrinter::PrintObjCMethodDecl(ObjCMethodDecl *OMD) { if (OMD->isInstance()) Out << "\n- "; @@ -608,6 +623,8 @@ namespace { CodeGen::CodeGenFunction(Builder, FD); } else if (FileVarDecl *FVD = dyn_cast(D)) { CodeGen::CodeGenGlobalVar(Builder, FVD); + } else if (LinkageSpecDecl *LSD = dyn_cast(D)) { + CodeGen::CodeGenLinkageSpec(Builder, LSD); } else { assert(isa(D) && "Only expected type decls here"); // don't codegen for now, eventually pass down for debug info. diff --git a/clang/Parse/ParseDeclCXX.cpp b/clang/Parse/ParseDeclCXX.cpp index 20c1fab4fbe2..46dcb5748191 100644 --- a/clang/Parse/ParseDeclCXX.cpp +++ b/clang/Parse/ParseDeclCXX.cpp @@ -80,3 +80,40 @@ Parser::DeclTy *Parser::ParseNamespace(unsigned Context) { return 0; } + +/// ParseLinkage - We know that the current token is a string_literal +/// and just before that, that extern was seen. +/// +/// linkage-specification: [C++ 7.5p2: dcl.link] +/// 'extern' string-literal '{' declaration-seq[opt] '}' +/// 'extern' string-literal declaration +/// +Parser::DeclTy *Parser::ParseLinkage(unsigned Context) { + assert(Tok.is(tok::string_literal) && "Not a stringliteral!"); + llvm::SmallVector LangBuffer; + // LangBuffer is guaranteed to be big enough. + LangBuffer.resize(Tok.getLength()); + const char *LangBufPtr = &LangBuffer[0]; + unsigned StrSize = PP.getSpelling(Tok, LangBufPtr); + + SourceLocation Loc = ConsumeStringToken(); + DeclTy *D = 0; + SourceLocation LBrace, RBrace; + + if (Tok.isNot(tok::l_brace)) { + D = ParseDeclaration(Context); + } else { + LBrace = ConsumeBrace(); + while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { + // FIXME capture the decls. + D = ParseExternalDeclaration(); + } + + RBrace = MatchRHSPunctuation(tok::r_brace, LBrace); + } + + if (!D) + return 0; + + return Actions.ActOnLinkageSpec(Loc, LBrace, RBrace, LangBufPtr, StrSize, D); +} diff --git a/clang/Parse/Parser.cpp b/clang/Parse/Parser.cpp index cc2c5d90c969..eeced570bb44 100644 --- a/clang/Parse/Parser.cpp +++ b/clang/Parse/Parser.cpp @@ -386,6 +386,15 @@ Parser::DeclTy *Parser::ParseDeclarationOrFunctionDefinition() { return ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes()); } + // If the declspec consisted only of 'extern' and we have a string + // literal following it, this must be a C++ linkage specifier like + // 'extern "C"'. + // FIXME: This should be limited to just C++/ObjectiveC++ + if (Tok.is(tok::string_literal) && + DS.getStorageClassSpec() == DeclSpec::SCS_extern && + DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) + return ParseLinkage(Declarator::FileContext); + // Parse the first declarator. Declarator DeclaratorInfo(DS, Declarator::FileContext); ParseDeclarator(DeclaratorInfo); diff --git a/clang/Sema/Sema.h b/clang/Sema/Sema.h index ef208290533b..3ab8be7c2857 100644 --- a/clang/Sema/Sema.h +++ b/clang/Sema/Sema.h @@ -192,6 +192,9 @@ private: virtual void ObjCActOnStartOfMethodDef(Scope *S, DeclTy *D); virtual DeclTy *ActOnFinishFunctionBody(DeclTy *Decl, StmtTy *Body); + virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, SourceLocation LBrace, + SourceLocation RBrace, const char *Lang, + unsigned StrSize, DeclTy *D); /// Scope actions. virtual void ActOnPopScope(SourceLocation Loc, Scope *S); diff --git a/clang/Sema/SemaDecl.cpp b/clang/Sema/SemaDecl.cpp index cbcd79ea4f8c..1610008191b0 100644 --- a/clang/Sema/SemaDecl.cpp +++ b/clang/Sema/SemaDecl.cpp @@ -1615,6 +1615,27 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX, Enum->defineElements(EltList, BestType); } +Sema::DeclTy* Sema::ActOnLinkageSpec(SourceLocation Loc, + SourceLocation LBrace, + SourceLocation RBrace, + const char *Lang, + unsigned StrSize, + DeclTy *D) { + LinkageSpecDecl::LanguageIDs Language; + Decl *dcl = static_cast(D); + if (strncmp(Lang, "\"C\"", StrSize) == 0) + Language = LinkageSpecDecl::lang_c; + else if (strncmp(Lang, "\"C++\"", StrSize) == 0) + Language = LinkageSpecDecl::lang_cxx; + else { + Diag(Loc, diag::err_bad_language); + return 0; + } + + // FIXME: Add all the various semantics of linkage specifications + return new LinkageSpecDecl(Loc, Language, dcl); +} + void Sema::HandleDeclAttribute(Decl *New, AttributeList *rawAttr) { const char *attrName = rawAttr->getAttributeName()->getName(); unsigned attrLen = rawAttr->getAttributeName()->getLength(); diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 321eb4b70ca4..40af7bada0bd 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -70,6 +70,7 @@ public: ObjCMethod, ObjCClass, ObjCForwardProtocol, + LinkageSpec, // For each non-leaf class, we now define a mapping to the first/last member // of the class, to allow efficient classof. @@ -753,6 +754,42 @@ protected: friend Decl* Decl::Create(llvm::Deserializer& D); }; + +/// LinkageSpecDecl - This represents a linkage specification. For example: +/// extern "C" void foo(); +/// +class LinkageSpecDecl : public Decl { +public: + /// LanguageIDs - Used to represent the language in a linkage + /// specification. The values are part of the serialization abi for + /// ASTs and cannot be changed without altering that abi. To help + /// ensure a stable abi for this, we choose the DW_LANG_ encodings + /// from the dwarf standard. + enum LanguageIDs { lang_c = /* DW_LANG_C */ 0x0002, + lang_cxx = /* DW_LANG_C_plus_plus */ 0x0004 }; +private: + /// Language - The language for this linkage specification. + LanguageIDs Language; + /// D - This is the Decl of the linkage specification. + Decl *D; +public: + LinkageSpecDecl(SourceLocation L, LanguageIDs lang, Decl *d) + : Decl(LinkageSpec, L), Language(lang), D(d) {} + + LanguageIDs getLanguage() const { return Language; } + const Decl *getDecl() const { return D; } + Decl *getDecl() { return D; } + + static bool classof(const Decl *D) { + return D->getKind() == LinkageSpec; + } + static bool classof(const LinkageSpecDecl *D) { return true; } + +protected: + void EmitInRec(llvm::Serializer& S) const; + void ReadInRec(llvm::Deserializer& D); +}; + } // end namespace clang #endif diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 1191455d743c..b91c7313f187 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -537,6 +537,8 @@ DIAG(err_invalid_reference_qualifier_application, ERROR, "'%0' qualifier may not be applied to a reference") DIAG(err_declarator_need_ident, ERROR, "declarator requires an identifier") +DIAG(err_bad_language, ERROR, + "unknown linkage language") // Attributes DIAG(err_attribute_wrong_number_arguments, ERROR, diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h index 7fddcadae14f..b27e3d35f535 100644 --- a/clang/include/clang/CodeGen/ModuleBuilder.h +++ b/clang/include/clang/CodeGen/ModuleBuilder.h @@ -22,6 +22,7 @@ namespace llvm { namespace clang { class ASTContext; class FunctionDecl; + class LinkageSpecDecl; class FileVarDecl; struct LangOptions; class Diagnostic; @@ -37,6 +38,8 @@ namespace CodeGen { /// CodeGenFunction - Convert the AST node for a FunctionDecl into LLVM. /// void CodeGenFunction(CodeGenModule *Builder, FunctionDecl *D); + + void CodeGenLinkageSpec(CodeGenModule *Builder, LinkageSpecDecl *LS); /// CodeGenGlobalVar - Emit the specified global variable to LLVM. void CodeGenGlobalVar(CodeGenModule *Builder, FileVarDecl *D); diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 8b4a0c1bfd4b..0e5ae2a79baf 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -154,6 +154,12 @@ public: virtual DeclTy *ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { return 0; } + + virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, SourceLocation LBrace, + SourceLocation RBrace, const char *Lang, + unsigned StrSize, DeclTy *D) { + return 0; + } //===--------------------------------------------------------------------===// // Type Parsing Callbacks. diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index c1069c25f65f..508dc306ad25 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -437,6 +437,7 @@ private: // C++ 7: Declarations [dcl.dcl] DeclTy *ParseNamespace(unsigned Context); + DeclTy *ParseLinkage(unsigned Context); };