Support L__FUNCTION__ in microsoft mode, PR11789

Heavily based on a patch from
Aaron Wishnick <aaron.s.wishnick@gmail.com>.

I'll clean up the duplicated function in CodeGen as
a follow-up, later today or tomorrow.

llvm-svn: 159060
This commit is contained in:
Nico Weber 2012-06-23 02:07:59 +00:00
parent 9137c399bd
commit 3a691a367c
8 changed files with 109 additions and 6 deletions

View File

@ -1047,6 +1047,7 @@ public:
enum IdentType {
Func,
Function,
LFunction, // Same as Function, but as wide string.
PrettyFunction,
/// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the
/// 'virtual' keyword is omitted for virtual member functions.

View File

@ -342,6 +342,9 @@ KEYWORD(__PRETTY_FUNCTION__ , KEYALL)
// GNU Extensions (outside impl-reserved namespace)
KEYWORD(typeof , KEYGNU)
// MS Extensions
KEYWORD(L__FUNCTION__ , KEYMS)
// GNU and MS Type Traits
KEYWORD(__has_nothrow_assign , KEYCXX)
KEYWORD(__has_nothrow_copy , KEYCXX)

View File

@ -424,6 +424,7 @@ void StmtDumper::VisitPredefinedExpr(PredefinedExpr *Node) {
default: llvm_unreachable("unknown case");
case PredefinedExpr::Func: OS << " __func__"; break;
case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
}
}

View File

@ -643,6 +643,9 @@ void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
case PredefinedExpr::Function:
OS << "__FUNCTION__";
break;
case PredefinedExpr::LFunction:
OS << "L__FUNCTION__";
break;
case PredefinedExpr::PrettyFunction:
OS << "__PRETTY_FUNCTION__";
break;

View File

@ -21,6 +21,7 @@
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/ConvertUTF.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/Intrinsics.h"
#include "llvm/LLVMContext.h"
@ -1701,6 +1702,73 @@ LValue CodeGenFunction::EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E) {
E->getType());
}
static llvm::Constant*
GetAddrOfConstantWideString(StringRef Str,
const char *GlobalName,
ASTContext &Context,
QualType Ty, SourceLocation Loc,
CodeGenModule &CGM) {
StringLiteral *SL = StringLiteral::Create(Context,
Str,
StringLiteral::Wide,
/*Pascal = */false,
Ty, Loc);
llvm::Constant *C = CGM.GetConstantArrayFromStringLiteral(SL);
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), C->getType(),
!CGM.getLangOpts().WritableStrings,
llvm::GlobalValue::PrivateLinkage,
C, GlobalName);
const unsigned WideAlignment =
Context.getTypeAlignInChars(Ty).getQuantity();
GV->setAlignment(WideAlignment);
return GV;
}
// FIXME: Mostly copied from StringLiteralParser::CopyStringFragment
static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source,
SmallString<32>& Target) {
Target.resize(CharByteWidth * (Source.size() + 1));
char* ResultPtr = &Target[0];
assert(CharByteWidth==1 || CharByteWidth==2 || CharByteWidth==4);
ConversionResult result = conversionOK;
// Copy the character span over.
if (CharByteWidth == 1) {
if (!isLegalUTF8String(reinterpret_cast<const UTF8*>(&*Source.begin()),
reinterpret_cast<const UTF8*>(&*Source.end())))
result = sourceIllegal;
memcpy(ResultPtr, Source.data(), Source.size());
ResultPtr += Source.size();
} else if (CharByteWidth == 2) {
UTF8 const *sourceStart = (UTF8 const *)Source.data();
// FIXME: Make the type of the result buffer correct instead of
// using reinterpret_cast.
UTF16 *targetStart = reinterpret_cast<UTF16*>(ResultPtr);
ConversionFlags flags = strictConversion;
result = ConvertUTF8toUTF16(
&sourceStart,sourceStart + Source.size(),
&targetStart,targetStart + 2*Source.size(),flags);
if (result==conversionOK)
ResultPtr = reinterpret_cast<char*>(targetStart);
} else if (CharByteWidth == 4) {
UTF8 const *sourceStart = (UTF8 const *)Source.data();
// FIXME: Make the type of the result buffer correct instead of
// using reinterpret_cast.
UTF32 *targetStart = reinterpret_cast<UTF32*>(ResultPtr);
ConversionFlags flags = strictConversion;
result = ConvertUTF8toUTF32(
&sourceStart,sourceStart + Source.size(),
&targetStart,targetStart + 4*Source.size(),flags);
if (result==conversionOK)
ResultPtr = reinterpret_cast<char*>(targetStart);
}
assert((result != targetExhausted)
&& "ConvertUTF8toUTFXX exhausted target buffer");
assert(result == conversionOK);
Target.resize(ResultPtr - &Target[0]);
}
LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
switch (E->getIdentType()) {
@ -1709,11 +1777,12 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
case PredefinedExpr::Func:
case PredefinedExpr::Function:
case PredefinedExpr::LFunction:
case PredefinedExpr::PrettyFunction: {
unsigned Type = E->getIdentType();
unsigned IdentType = E->getIdentType();
std::string GlobalVarName;
switch (Type) {
switch (IdentType) {
default: llvm_unreachable("Invalid type");
case PredefinedExpr::Func:
GlobalVarName = "__func__.";
@ -1721,6 +1790,9 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
case PredefinedExpr::Function:
GlobalVarName = "__FUNCTION__.";
break;
case PredefinedExpr::LFunction:
GlobalVarName = "L__FUNCTION__.";
break;
case PredefinedExpr::PrettyFunction:
GlobalVarName = "__PRETTY_FUNCTION__.";
break;
@ -1738,10 +1810,27 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
std::string FunctionName =
(isa<BlockDecl>(CurDecl)
? FnName.str()
: PredefinedExpr::ComputeName((PredefinedExpr::IdentType)Type, CurDecl));
: PredefinedExpr::ComputeName((PredefinedExpr::IdentType)IdentType,
CurDecl));
llvm::Constant *C =
CGM.GetAddrOfConstantCString(FunctionName, GlobalVarName.c_str());
const Type* ElemType = E->getType()->getArrayElementTypeNoTypeQual();
llvm::Constant *C;
if (ElemType->isWideCharType()) {
SmallString<32> RawChars;
ConvertUTF8ToWideString(
getContext().getTypeSizeInChars(ElemType).getQuantity(),
FunctionName, RawChars);
C = GetAddrOfConstantWideString(RawChars,
GlobalVarName.c_str(),
getContext(),
E->getType(),
E->getLocation(),
CGM);
} else {
C = CGM.GetAddrOfConstantCString(FunctionName,
GlobalVarName.c_str(),
1);
}
return MakeAddrLValue(C, E->getType());
}
}

View File

@ -854,6 +854,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
break;
case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2]
case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU]
case tok::kw_L__FUNCTION__: // primary-expression: L__FUNCTION__ [MS]
case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU]
Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind);
ConsumeToken();

View File

@ -744,6 +744,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___imag:
case tok::kw___real:
case tok::kw___FUNCTION__:
case tok::kw_L__FUNCTION__:
case tok::kw___PRETTY_FUNCTION__:
case tok::kw___has_nothrow_assign:
case tok::kw___has_nothrow_copy:

View File

@ -2463,6 +2463,7 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
default: llvm_unreachable("Unknown simple primary expr!");
case tok::kw___func__: IT = PredefinedExpr::Func; break; // [C99 6.4.2.2]
case tok::kw___FUNCTION__: IT = PredefinedExpr::Function; break;
case tok::kw_L__FUNCTION__: IT = PredefinedExpr::LFunction; break;
case tok::kw___PRETTY_FUNCTION__: IT = PredefinedExpr::PrettyFunction; break;
}
@ -2484,7 +2485,10 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length();
llvm::APInt LengthI(32, Length + 1);
ResTy = Context.CharTy.withConst();
if (Kind == tok::kw_L__FUNCTION__)
ResTy = Context.WCharTy.withConst();
else
ResTy = Context.CharTy.withConst();
ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
}
return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT));