Mike Stump wrote:
On Dec 22, 2007, at 5:28 PM, Chris Lattner wrote:
Please attach patches as attachments, not inline. If you're using
'mail', just name the file "whatever.patch" and this will happen.
Until this happens, I can't properly review the patch as it's all
wrapped and nastified :(
Odd, you must be using an old mail viewer... In modern viewers, it
should come out just fine. I pretested cutting and pasting and
ensured there were no problems with it. Oh well... What mail viewer
do you use?
I think the line-breaks may be caused by oter tools than the mail
viewer. At least the source my viewer received had additional
linebreaks in it.
Nevertheless, the new patch you provided as attachment was ok as far as
line-breaks. I did have other problems using it with my diff/patch
tools, but I managed to apply it with some manual hacking. Problems may
have been cased by us not being in sync with svn revisions. I am not
that hot on svn, but svn-diff and friends may be a better choice in . I
attached the output of running
svn diff > cxx-extern-linkage-spec.patch
in my tools/clang directory after I applied Mike's patches the best I could.
It seems Mike are done with most of what I set out to do :-). I
reviewed the patch for the sake of learning, and applied it to my
source. It now work fine with my test code for C++ extern keword.
Extern template instanciation stuff is of scale and no tests is written
for that.
I also attach my test source which run nicely with Mike's patch :-)
Good work Mike.
+/// LinkageSpecDecl - This represents a linkage specification.
+class LinkageSpecDecl : public Decl {
Please give an example of what a linkage spec is in the header. At
some point, we probably want to make a DeclCXX.h file, but deferring
this for now is fine.
+private:
+ /// Language - The language for this linkage specification.
+ Language language;
+ bool inside_braces;
+ Decl *D;
inside_braces is good for "remembering" the original source,
I did that merely because we're calling them ASTs and because we form
ParenExprs. If we didn't want ASTs, we could get rid of ParenExprs?
but unless there is a client,
-ast-print uses that information to print the ast. Absent that
information we can't faithfully reproduce the syntax tree. Do we care
that the printed ast is wrong? Do we care if the ast isn't actually
an ast?
Does this support nested linkage specifiers as well? There is a test
case in my test file.
Should we not let support for linkage be a backend issue (e.g. llvm
CodeGen), not frontend, as it is now, the AST is unusable for backends
supporting linking to other languages.
This would mean a change of Sema::ActOnLinkageSpec to support more
lang_xxx enums and/or pass the language string to the AST consumer.
Something like:
Sema::DeclTy* Sema::ActOnLinkageSpec(SourceLocation Loc,
const char *Lang,
bool inside_brace,
DeclTy *D) {
LinkageSpecDecl::Language language;
Decl *dcl = static_cast<Decl *>(D);
if (strcmp (Lang, "\"C\"") == 0)
language = LinkageSpecDecl::lang_c;
else if (strcmp (Lang, "\"C++\"") == 0)
language = LinkageSpecDecl::lang_cxx;
// could include enum support for other typical, but not required
languages also
else
language = LinkageSpecDecl::lang_other;
return new LinkageSpecDecl(Loc, language, inside_brace, dcl);
}
And let the backend codegen emit diagnostics, something similar to
pseudocode:
switch ( laguage )
{
case lang::lang_cxx:
DoCXXLinkageCodeGen(...);
break;
case lang::lang_c:
DoCLinkageCodeGen(...);
break;
case lang::lang_other:
if ( (strcmp (language_str, "\"FORTRAN\"") == 0) &&
(strcmp (language_str, "\"Fortran\"") == 0) )
DoFortranLinkageCodeGen(...);
else if (strcmp (language_str, "\"Ada\"") == 0)
DoAdaLinkageCodeGen(...);
Diag(Loc, diag::err_bad_language);
break;
}
-------------
any thoughts ?
--
Bjørn
Index: include/clang/Basic/DiagnosticKinds.def
===================================================================
--- include/clang/Basic/DiagnosticKinds.def (revision 45481)
+++ include/clang/Basic/DiagnosticKinds.def (working copy)
@@ -529,6 +529,8 @@
"'%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,
Index: include/clang/CodeGen/ModuleBuilder.h
===================================================================
--- include/clang/CodeGen/ModuleBuilder.h (revision 45481)
+++ include/clang/CodeGen/ModuleBuilder.h (working copy)
@@ -22,6 +22,7 @@
namespace clang {
class ASTContext;
class FunctionDecl;
+ class LinkageSpecDecl;
class FileVarDecl;
struct LangOptions;
class Diagnostic;
@@ -37,6 +38,8 @@
/// 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);
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h (revision 45481)
+++ include/clang/AST/ASTContext.h (working copy)
@@ -30,6 +30,7 @@
/// ASTContext - This class holds long-lived AST nodes (such as types and
/// decls) that can be referred to throughout the semantic analysis of a file.
+
class ASTContext {
std::vector<Type*> Types;
llvm::FoldingSet<ComplexType> ComplexTypes;
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h (revision 45481)
+++ include/clang/AST/Decl.h (working copy)
@@ -70,6 +70,7 @@
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,34 @@
friend Decl* Decl::Create(llvm::Deserializer& D);
};
+
+/// LinkageSpecDecl - This represents a linkage specification.
+class LinkageSpecDecl : public Decl {
+public:
+ enum Language { lang_cxx, lang_c };
+private:
+ /// Language - The language for this linkage specification.
+ Language language;
+ bool inside_braces;
+ Decl *D;
+public:
+ LinkageSpecDecl(SourceLocation L, Language lang, bool inside, Decl *d)
+ : Decl(LinkageSpec, L), language(lang), inside_braces(inside), D(d) {}
+
+ Language getLanguage() const { return language; }
+ bool is_inside_braces() { return inside_braces; }
+ Decl *getD() { 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
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h (revision 45481)
+++ include/clang/AST/Type.h (working copy)
@@ -319,7 +319,7 @@
/// type type. This takes off typedefs, typeof's etc. If the outer level of
/// the type is already concrete, it returns it unmodified. This is similar
/// to getting the canonical type, but it doesn't remove *all* typedefs. For
- /// example, it return "T*" as "T*", (not as "int*"), because the pointer is
+ /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is
/// concrete.
const Type *getDesugaredType() const;
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h (revision 45481)
+++ include/clang/Parse/Parser.h (working copy)
@@ -434,6 +434,7 @@
// C++ 7: Declarations [dcl.dcl]
DeclTy *ParseNamespace(unsigned Context);
+ DeclTy *ParseLinkage(unsigned Context);
};
Index: include/clang/Parse/Action.h
===================================================================
--- include/clang/Parse/Action.h (revision 45481)
+++ include/clang/Parse/Action.h (working copy)
@@ -154,6 +154,11 @@
virtual DeclTy *ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
return 0;
}
+
+ virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, const char *, bool
inside_braces,
+ DeclTy *D) {
+ return 0;
+ }
//===--------------------------------------------------------------------===//
// Type Parsing Callbacks.
Index: Sema/Sema.h
===================================================================
--- Sema/Sema.h (revision 45481)
+++ Sema/Sema.h (working copy)
@@ -190,6 +190,8 @@
virtual void ObjcActOnStartOfMethodDef(Scope *S, DeclTy *D);
virtual DeclTy *ActOnFinishFunctionBody(DeclTy *Decl, StmtTy *Body);
+ virtual DeclTy *ActOnLinkageSpec(SourceLocation Loc, const char *Lang,
+ bool inside_braces, DeclTy *D);
/// Scope actions.
virtual void ActOnPopScope(SourceLocation Loc, Scope *S);
Index: Sema/SemaDecl.cpp
===================================================================
--- Sema/SemaDecl.cpp (revision 45481)
+++ Sema/SemaDecl.cpp (working copy)
@@ -1649,6 +1649,25 @@
Enum->defineElements(EltList, BestType);
}
+Sema::DeclTy* Sema::ActOnLinkageSpec(SourceLocation Loc,
+ const char *Lang,
+ bool inside_brace,
+ DeclTy *D) {
+ LinkageSpecDecl::Language language;
+ Decl *dcl = static_cast<Decl *>(D);
+ if (strcmp (Lang, "\"C\"") == 0)
+ language = LinkageSpecDecl::lang_c;
+ else if (strcmp (Lang, "\"C++\"") == 0)
+ language = LinkageSpecDecl::lang_cxx;
+ else
+ {
+ Diag(Loc, diag::err_bad_language);
+ return 0;
+ }
+
+ return new LinkageSpecDecl(Loc, language, inside_brace, dcl);
+}
+
void Sema::HandleDeclAttribute(Decl *New, AttributeList *rawAttr) {
const char *attrName = rawAttr->getAttributeName()->getName();
unsigned attrLen = rawAttr->getAttributeName()->getLength();
Index: AST/Decl.cpp
===================================================================
--- AST/Decl.cpp (revision 45481)
+++ AST/Decl.cpp (working copy)
@@ -37,6 +37,7 @@
static unsigned nObjcCategoryImpl = 0;
static unsigned nObjcCompatibleAlias = 0;
static unsigned nObjcPropertyDecl = 0;
+static unsigned nLinkageSpecDecl = 0;
static bool StatSwitch = false;
@@ -151,12 +152,28 @@
nObjcPropertyDecl, (int)sizeof(ObjcPropertyDecl),
int(nObjcPropertyDecl*sizeof(ObjcPropertyDecl)));
+ fprintf(stderr, " %d linkage specifications, %d each (%d bytes)\n",
+ nLinkageSpecDecl, (int)sizeof(LinkageSpecDecl),
+ int(nLinkageSpecDecl*sizeof(LinkageSpecDecl)));
+
fprintf(stderr, "Total bytes = %d\n",
int(nFuncs*sizeof(FunctionDecl)+nBlockVars*sizeof(BlockVarDecl)+
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)+
+ nInterfaceDecls*sizeof(ObjcInterfaceDecl)+
+ nIvarDecls*sizeof(ObjcIvarDecl)+
+ nClassDecls*sizeof(ObjcClassDecl)+
+ nMethodDecls*sizeof(ObjcMethodDecl)+
+ nProtocolDecls*sizeof(ObjcProtocolDecl)+
+ nForwardProtocolDecls*sizeof(ObjcForwardProtocolDecl)+
+ nCategoryDecls*sizeof(ObjcCategoryDecl)+
+ nObjcImplementationDecls*sizeof(ObjcImplementationDecl)+
+ nObjcCategoryImpl*sizeof(ObjcCategoryImplDecl)+
+ nObjcCompatibleAlias*sizeof(ObjcCompatibleAliasDecl)+
+ nObjcPropertyDecl*sizeof(ObjcPropertyDecl)+
+ nLinkageSpecDecl*sizeof(LinkageSpecDecl)));
}
void Decl::addDeclKind(const Kind k) {
@@ -223,6 +240,9 @@
case PropertyDecl:
nObjcPropertyDecl++;
break;
+ case LinkageSpec:
+ nLinkageSpecDecl++;
+ break;
}
}
Index: Driver/clang.cpp
===================================================================
--- Driver/clang.cpp (revision 45481)
+++ Driver/clang.cpp (working copy)
@@ -798,35 +798,19 @@
// FIXME: get these from the target?
if (!nostdinc) {
if (Lang.CPlusPlus) {
- AddPath("/usr/include/c++/4.0.0", System, true, false, false, Headers);
- AddPath("/usr/include/c++/4.0.0/i686-apple-darwin8", System, true, false,
+ AddPath("/usr/include/c++/4.0.2", System, true, false, false, Headers);
+ AddPath("/usr/include/c++/4.0.2/i386-redhat-linux", System, true, false,
false, Headers);
- AddPath("/usr/include/c++/4.0.0/backward", System, true, false, false,
+ AddPath("/usr/include/c++/4.0.2/backward", System, true, false, false,
Headers);
}
AddPath("/usr/local/include", System, false, false, false, Headers);
// leopard
- AddPath("/usr/lib/gcc/i686-apple-darwin9/4.0.1/include", System,
+ AddPath("/usr/lib/gcc/i386-redhat-linux/4.0.2/include", System,
false, false, false, Headers);
- AddPath("/usr/lib/gcc/powerpc-apple-darwin9/4.0.1/include",
- System, false, false, false, Headers);
- AddPath("/usr/lib/gcc/powerpc-apple-darwin9/"
- "4.0.1/../../../../powerpc-apple-darwin0/include",
- System, false, false, false, Headers);
- // tiger
- AddPath("/usr/lib/gcc/i686-apple-darwin8/4.0.1/include", System,
- false, false, false, Headers);
- AddPath("/usr/lib/gcc/powerpc-apple-darwin8/4.0.1/include",
- System, false, false, false, Headers);
- AddPath("/usr/lib/gcc/powerpc-apple-darwin8/"
- "4.0.1/../../../../powerpc-apple-darwin8/include",
- System, false, false, false, Headers);
-
AddPath("/usr/include", System, false, false, false, Headers);
- AddPath("/System/Library/Frameworks", System, true, false, true, Headers);
- AddPath("/Library/Frameworks", System, true, false, true, Headers);
}
// Now that we have collected all of the include paths, merge them all
Index: Driver/ASTConsumers.cpp
===================================================================
--- Driver/ASTConsumers.cpp (revision 45481)
+++ Driver/ASTConsumers.cpp (working copy)
@@ -38,6 +38,7 @@
void PrintFunctionDeclStart(FunctionDecl *FD);
void PrintTypeDefDecl(TypedefDecl *TD);
+ void PrintLinkageSpec(LinkageSpecDecl *LS);
void PrintObjcMethodDecl(ObjcMethodDecl *OMD);
void PrintObjcImplementationDecl(ObjcImplementationDecl *OID);
void PrintObjcInterfaceDecl(ObjcInterfaceDecl *OID);
@@ -101,6 +102,21 @@
Out << "typedef " << S << ";\n";
}
+void DeclPrinter::PrintLinkageSpec(LinkageSpecDecl *LS) {
+ std::string 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 << "\" ";
+ if (LS->is_inside_braces())
+ Out << "{\n";
+ // PrintDecl(LS->getD()); // FIXME: bjornr: merging patch out of sync
+ if (LS->is_inside_braces())
+ Out << "}\n";
+}
+
void DeclPrinter::PrintObjcMethodDecl(ObjcMethodDecl *OMD) {
if (OMD->isInstance())
Out << "\n- ";
@@ -589,6 +605,8 @@
CodeGen::CodeGenFunction(Builder, FD);
} else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
CodeGen::CodeGenGlobalVar(Builder, FVD);
+ } else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
+ CodeGen::CodeGenLinkageSpec(Builder, LSD);
} else {
assert(isa<TypeDecl>(D) && "Only expected type decls here");
// don't codegen for now, eventually pass down for debug info.
Index: CodeGen/ModuleBuilder.cpp
===================================================================
--- CodeGen/ModuleBuilder.cpp (revision 45481)
+++ CodeGen/ModuleBuilder.cpp (working copy)
@@ -34,6 +34,10 @@
B->EmitFunction(D);
}
+void clang::CodeGen::CodeGenLinkageSpec(CodeGenModule *B, LinkageSpecDecl *LS)
{
+
+}
+
/// CodeGenGlobalVar - Emit the specified global variable to LLVM.
void clang::CodeGen::CodeGenGlobalVar(CodeGenModule *Builder, FileVarDecl *D) {
Builder->EmitGlobalVarDeclarator(D);
Index: Parse/ParseDeclCXX.cpp
===================================================================
--- Parse/ParseDeclCXX.cpp (revision 45481)
+++ Parse/ParseDeclCXX.cpp (working copy)
@@ -80,3 +80,27 @@
return 0;
}
+
+// C++ 7.5p2
+Parser::DeclTy *Parser::ParseLinkage(unsigned Context) {
+ std::string lang = PP.getSpelling(Tok);
+ SourceLocation Loc = ConsumeStringToken ();
+ bool saw_braces = false;
+ DeclTy *D = 0;
+
+ if (Tok.is(tok::l_brace))
+ {
+ SourceLocation LBrace = ConsumeBrace();
+ saw_braces = true;
+ while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
+ // FIXME capture the decls.
+ D = ParseExternalDeclaration();
+ }
+
+ SourceLocation RBrace = MatchRHSPunctuation(tok::r_brace, LBrace);
+ }
+ else
+ D = ParseDeclaration(Context);
+
+ return Actions.ActOnLinkageSpec(Loc, lang.c_str(), saw_braces, D);
+}
Index: Parse/Parser.cpp
===================================================================
--- Parse/Parser.cpp (revision 45481)
+++ Parse/Parser.cpp (working copy)
@@ -381,6 +381,14 @@
}
return ParseObjCAtInterfaceDeclaration(AtLoc, DS.getAttributes());
}
+
+ 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);
// RUN: clang -fsyntax-only -verify %s
// --- decl-specifier storage-class-specifier extern ---
//objects
extern char foo;
struct DS;
extern struct DS ds;
extern struct S s;
extern union U u;
// extern class C c; // FIXME: support for class keyword
//functions
extern char bar(int);
// --- linkage-specification ---
// syntax: extern string-literal declaration
extern "C" int g();
extern "C++" int h();
extern "FORTRAN" int F(); // expected-error {{unknown linkage language}}
extern "Fortran" int F(); // expected-error {{unknown linkage language}}
// syntax: extern string-literal { declaration-seqopt }
extern "C" {
int cg();
int ch();
}
extern "C++" {
int cxxg();
int cxxh();
}
// extern { // should be "C++" as default language I think,
// but g++ emit: cxx-extern.cpp:33: error: expected
unqualified-id before â{â token
// int cxxg(); // redeclare cxxg(), Ok
// int cxxh(); // redeclare cxxh(), Ok
// }
extern "FORTRAN" { // expected-error {{unknown linkage language}}
int FG();
int FH();
}
extern "Ada" { // expected-error {{unknown linkage language}}
int AG();
int AH();
}
// --- nested linkage-specifier
extern "C++" {
int cpp_ggg(); // C++ linkage
extern "C" {
void c_ggg(); // C linkage
extern "Ada" { // expected-error {{unknown linkage language}}
void ada_ggg(); // Ada linkage
extern int cpp_ggg2(); // C++ linkage ??
extern int c_ggg2(); // C linkage ??
}
}
}
// --- explicit-instantiation ---
// extern template declaration
// FIXME: need tests if C++ explicit-instantiation dark corners are ever
explored
_______________________________________________
cfe-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev