diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 3d865383cc..a13b48a420 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -162,6 +162,7 @@ class Parser : public CodeCompletionHandler { OwningPtr MSStructHandler; OwningPtr UnusedHandler; OwningPtr WeakHandler; + OwningPtr RedefineExtnameHandler; OwningPtr FPContractHandler; OwningPtr OpenCLExtensionHandler; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 97cd27f7ed..bd285c78b9 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -469,6 +469,13 @@ public: /// identifier, declared or undeclared llvm::DenseMap WeakUndeclaredIdentifiers; + /// ExtnameUndeclaredIdentifiers - Identifiers contained in + /// #pragma redefine_extname before declared. Used in Solaris system headers + /// to define functions that occur in multiple standards to call the version + /// in the currently selected standard. + llvm::DenseMap ExtnameUndeclaredIdentifiers; + + /// \brief Load weak undeclared identifiers from the external source. void LoadExternalWeakUndeclaredIdentifiers(); @@ -5719,6 +5726,14 @@ public: SourceLocation PragmaLoc, SourceLocation WeakNameLoc); + /// ActOnPragmaRedefineExtname - Called on well formed + /// #pragma redefine_extname oldname newname. + void ActOnPragmaRedefineExtname(IdentifierInfo* WeakName, + IdentifierInfo* AliasName, + SourceLocation PragmaLoc, + SourceLocation WeakNameLoc, + SourceLocation AliasNameLoc); + /// ActOnPragmaWeakAlias - Called on well formed #pragma weak ident = ident. void ActOnPragmaWeakAlias(IdentifierInfo* WeakName, IdentifierInfo* AliasName, diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index f0cf7f4914..504ef01601 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -333,6 +333,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__ATOMIC_ACQ_REL", "4"); Builder.defineMacro("__ATOMIC_SEQ_CST", "5"); + // Support for #pragma redefine_extname (Sun compatibility) + Builder.defineMacro("__PRAGMA_REDEFINE_EXTNAME", "1"); + // As sad as it is, enough software depends on the __VERSION__ for version // checks that it is necessary to report 4.2.1 (the base GCC version we claim // compatibility with) first. diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index f47b32f513..433c76b83b 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -426,6 +426,44 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP, } } +// #pragma redefine_extname identifier identifier +void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &RedefToken) { + SourceLocation RedefLoc = RedefToken.getLocation(); + + Token Tok; + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << + "redefine_extname"; + return; + } + + IdentifierInfo *RedefName = Tok.getIdentifierInfo(), *AliasName = 0; + SourceLocation RedefNameLoc = Tok.getLocation(), AliasNameLoc; + + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) + << "redefine_extname"; + return; + } + AliasName = Tok.getIdentifierInfo(); + AliasNameLoc = Tok.getLocation(); + PP.Lex(Tok); + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << + "redefine_extname"; + return; + } + + Actions.ActOnPragmaRedefineExtname(RedefName, AliasName, RedefLoc, + RedefNameLoc, AliasNameLoc); +} + + void PragmaFPContractHandler::HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h index 1d3138fa70..ebb185ad1a 100644 --- a/lib/Parse/ParsePragma.h +++ b/lib/Parse/ParsePragma.h @@ -90,6 +90,16 @@ public: Token &FirstToken); }; +class PragmaRedefineExtnameHandler : public PragmaHandler { + Sema &Actions; +public: + explicit PragmaRedefineExtnameHandler(Sema &A) + : PragmaHandler("redefine_extname"), Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + class PragmaOpenCLExtensionHandler : public PragmaHandler { Sema &Actions; Parser &parser; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index c797436948..4c5df4d2ff 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -64,6 +64,9 @@ Parser::Parser(Preprocessor &pp, Sema &actions) WeakHandler.reset(new PragmaWeakHandler(actions)); PP.AddPragmaHandler(WeakHandler.get()); + RedefineExtnameHandler.reset(new PragmaRedefineExtnameHandler(actions)); + PP.AddPragmaHandler(RedefineExtnameHandler.get()); + FPContractHandler.reset(new PragmaFPContractHandler(actions, *this)); PP.AddPragmaHandler("STDC", FPContractHandler.get()); @@ -382,6 +385,8 @@ Parser::~Parser() { UnusedHandler.reset(); PP.RemovePragmaHandler(WeakHandler.get()); WeakHandler.reset(); + PP.RemovePragmaHandler(RedefineExtnameHandler.get()); + RedefineExtnameHandler.reset(); if (getLang().OpenCL) { PP.RemovePragmaHandler("OPENCL", OpenCLExtensionHandler.get()); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 796d2a2bb3..89f22cb72b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4059,6 +4059,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), Context, Label)); + } else if (!ExtnameUndeclaredIdentifiers.empty()) { + llvm::DenseMap::iterator I = + ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); + if (I != ExtnameUndeclaredIdentifiers.end()) { + NewVD->addAttr(I->second); + ExtnameUndeclaredIdentifiers.erase(I); + } } // Diagnose shadowed variables before filtering for scope. @@ -5157,6 +5164,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, StringLiteral *SE = cast(E); NewFD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), Context, SE->getString())); + } else if (!ExtnameUndeclaredIdentifiers.empty()) { + llvm::DenseMap::iterator I = + ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier()); + if (I != ExtnameUndeclaredIdentifiers.end()) { + NewFD->addAttr(I->second); + ExtnameUndeclaredIdentifiers.erase(I); + } } // Copy the parameter declarations from the declarator D to the function @@ -10152,6 +10166,24 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc, return Import; } +void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, + IdentifierInfo* AliasName, + SourceLocation PragmaLoc, + SourceLocation NameLoc, + SourceLocation AliasNameLoc) { + Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, + LookupOrdinaryName); + AsmLabelAttr *Attr = + ::new (Context) AsmLabelAttr(AliasNameLoc, Context, AliasName->getName()); + fprintf(stderr, "Alias name: %s\n", AliasName->getName().str().c_str()); + + if (PrevDecl) + PrevDecl->addAttr(Attr); + else + (void)ExtnameUndeclaredIdentifiers.insert( + std::pair(Name, Attr)); +} + void Sema::ActOnPragmaWeakID(IdentifierInfo* Name, SourceLocation PragmaLoc, SourceLocation NameLoc) { diff --git a/test/CodeGen/redefine_extname.c b/test/CodeGen/redefine_extname.c new file mode 100644 index 0000000000..e73a3ad8df --- /dev/null +++ b/test/CodeGen/redefine_extname.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple=i386-pc-solaris2.11 -w -emit-llvm %s -o - | FileCheck %s + +#pragma redefine_extname fake real +#pragma redefine_extname name alias + +extern int fake(void); + +int name; + +// __PRAGMA_REDEFINE_EXTNAME should be defined. This will fail if it isn't... +int fish() { return fake() + __PRAGMA_REDEFINE_EXTNAME + name; } +// Check that the call to fake() is emitted as a call to real() +// CHECK: call i32 @real() +// Check that this also works with variables names +// CHECK: load i32* @alias