Assertion failed: "Computed __func__ length differs from type!"
Reworked PredefinedExpr representation with internal StringLiteral field for function declaration.
Differential Revision: http://reviews.llvm.org/D5365

llvm-svn: 219393
This commit is contained in:
Alexey Bataev 2014-10-09 08:45:04 +00:00
parent a9ee5c06f4
commit ec4747802a
16 changed files with 230 additions and 148 deletions

View File

@ -45,6 +45,7 @@ namespace clang {
class ObjCPropertyRefExpr;
class OpaqueValueExpr;
class ParmVarDecl;
class StringLiteral;
class TargetInfo;
class ValueDecl;
@ -1161,7 +1162,7 @@ public:
friend class ASTStmtWriter;
};
/// PredefinedExpr - [C99 6.4.2.2] - A predefined identifier such as __func__.
/// \brief [C99 6.4.2.2] - A predefined identifier such as __func__.
class PredefinedExpr : public Expr {
public:
enum IdentType {
@ -1171,7 +1172,7 @@ public:
FuncDName,
FuncSig,
PrettyFunction,
/// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the
/// \brief The same as PrettyFunction, except that the
/// 'virtual' keyword is omitted for virtual member functions.
PrettyFunctionNoVirtual
};
@ -1179,24 +1180,27 @@ public:
private:
SourceLocation Loc;
IdentType Type;
Stmt *FnName;
public:
PredefinedExpr(SourceLocation l, QualType type, IdentType IT)
: Expr(PredefinedExprClass, type, VK_LValue, OK_Ordinary,
type->isDependentType(), type->isDependentType(),
type->isInstantiationDependentType(),
/*ContainsUnexpandedParameterPack=*/false),
Loc(l), Type(IT) {}
PredefinedExpr(SourceLocation L, QualType FNTy, IdentType IT,
StringLiteral *SL);
/// \brief Construct an empty predefined expression.
explicit PredefinedExpr(EmptyShell Empty)
: Expr(PredefinedExprClass, Empty) { }
: Expr(PredefinedExprClass, Empty), Loc(), Type(Func), FnName(nullptr) {}
IdentType getIdentType() const { return Type; }
void setIdentType(IdentType IT) { Type = IT; }
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
StringLiteral *getFunctionName();
const StringLiteral *getFunctionName() const {
return const_cast<PredefinedExpr *>(this)->getFunctionName();
}
static StringRef getIdentTypeName(IdentType IT);
static std::string ComputeName(IdentType IT, const Decl *CurrentDecl);
SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
@ -1207,7 +1211,9 @@ public:
}
// Iterators
child_range children() { return child_range(); }
child_range children() { return child_range(&FnName, &FnName + 1); }
friend class ASTStmtReader;
};
/// \brief Used by IntegerLiteral/FloatingLiteral to store the numeric without

View File

@ -1714,15 +1714,7 @@ void ASTDumper::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node) {
void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) {
VisitExpr(Node);
switch (Node->getIdentType()) {
default: llvm_unreachable("unknown case");
case PredefinedExpr::Func: OS << " __func__"; break;
case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
case PredefinedExpr::FuncDName: OS << " __FUNCDNAME__"; break;
case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
case PredefinedExpr::FuncSig: OS << " __FUNCSIG__"; break;
}
OS << " " << PredefinedExpr::getIdentTypeName(Node->getIdentType());
}
void ASTDumper::VisitCharacterLiteral(const CharacterLiteral *Node) {

View File

@ -448,6 +448,38 @@ SourceLocation DeclRefExpr::getLocEnd() const {
return getNameInfo().getLocEnd();
}
PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentType IT,
StringLiteral *SL)
: Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary,
FNTy->isDependentType(), FNTy->isDependentType(),
FNTy->isInstantiationDependentType(),
/*ContainsUnexpandedParameterPack=*/false),
Loc(L), Type(IT), FnName(SL) {}
StringLiteral *PredefinedExpr::getFunctionName() {
return cast<StringLiteral>(FnName);
}
StringRef PredefinedExpr::getIdentTypeName(PredefinedExpr::IdentType IT) {
switch (IT) {
case Func:
return "__func__";
case Function:
return "__FUNCTION__";
case FuncDName:
return "__FUNCDNAME__";
case LFunction:
return "L__FUNCTION__";
case PrettyFunction:
return "__PRETTY_FUNCTION__";
case FuncSig:
return "__FUNCSIG__";
case PrettyFunctionNoVirtual:
break;
}
llvm_unreachable("Unknown ident type for PredefinedExpr");
}
// FIXME: Maybe this should use DeclPrinter with a special "print predefined
// expr" policy instead.
std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
@ -477,6 +509,22 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
}
return "";
}
if (auto *BD = dyn_cast<BlockDecl>(CurrentDecl)) {
std::unique_ptr<MangleContext> MC;
MC.reset(Context.createMangleContext());
SmallString<256> Buffer;
llvm::raw_svector_ostream Out(Buffer);
auto DC = CurrentDecl->getDeclContext();
if (DC->isFileContext())
MC->mangleGlobalBlock(BD, /*ID*/ nullptr, Out);
else if (const auto *CD = dyn_cast<CXXConstructorDecl>(DC))
MC->mangleCtorBlock(CD, /*CT*/ Ctor_Complete, BD, Out);
else if (const auto *DD = dyn_cast<CXXDestructorDecl>(DC))
MC->mangleDtorBlock(DD, /*DT*/ Dtor_Complete, BD, Out);
else
MC->mangleBlock(DC, BD, Out);
return Out.str();
}
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual && IT != FuncSig)
return FD->getNameAsString();
@ -600,9 +648,8 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
// type deduction and lambdas. For trailing return types resolve the
// decltype expression. Otherwise print the real type when this is
// not a constructor or destructor.
if ((isa<CXXMethodDecl>(FD) &&
cast<CXXMethodDecl>(FD)->getParent()->isLambda()) ||
(FT && FT->getReturnType()->getAs<AutoType>()))
if (isa<CXXMethodDecl>(FD) &&
cast<CXXMethodDecl>(FD)->getParent()->isLambda())
Proto = "auto " + Proto;
else if (FT && FT->getReturnType()->getAs<DecltypeType>())
FT->getReturnType()

View File

@ -2021,7 +2021,9 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived,
/// Extract the value of a character from a string literal.
static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
uint64_t Index) {
// FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant
// FIXME: Support ObjCEncodeExpr, MakeStringConstant
if (auto PE = dyn_cast<PredefinedExpr>(Lit))
Lit = PE->getFunctionName();
const StringLiteral *S = cast<StringLiteral>(Lit);
const ConstantArrayType *CAT =
Info.Ctx.getAsConstantArrayType(S->getType());
@ -2715,10 +2717,10 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
return false;
CompleteObject LitObj(&Lit, Base->getType());
return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal);
} else if (isa<StringLiteral>(Base)) {
} else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) {
// We represent a string literal array as an lvalue pointing at the
// corresponding expression, rather than building an array of chars.
// FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant
// FIXME: Support ObjCEncodeExpr, MakeStringConstant
APValue Str(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0);
CompleteObject StrObj(&Str, Base->getType());
return extractSubobject(Info, Conv, StrObj, LVal.Designator, RVal);

View File

@ -1004,28 +1004,7 @@ void StmtPrinter::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node) {
}
void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
switch (Node->getIdentType()) {
default:
llvm_unreachable("unknown case");
case PredefinedExpr::Func:
OS << "__func__";
break;
case PredefinedExpr::Function:
OS << "__FUNCTION__";
break;
case PredefinedExpr::FuncDName:
OS << "__FUNCDNAME__";
break;
case PredefinedExpr::FuncSig:
OS << "__FUNCSIG__";
break;
case PredefinedExpr::LFunction:
OS << "L__FUNCTION__";
break;
case PredefinedExpr::PrettyFunction:
OS << "__PRETTY_FUNCTION__";
break;
}
OS << PredefinedExpr::getIdentTypeName(Node->getIdentType());
}
void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {

View File

@ -24,6 +24,7 @@
#include "clang/AST/Attr.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
@ -2069,86 +2070,18 @@ LValue CodeGenFunction::EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E) {
E->getType());
}
static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source,
SmallString<32>& Target) {
Target.resize(CharByteWidth * (Source.size() + 1));
char *ResultPtr = &Target[0];
const UTF8 *ErrorPtr;
bool success = ConvertUTF8toWide(CharByteWidth, Source, ResultPtr, ErrorPtr);
(void)success;
assert(success);
Target.resize(ResultPtr - &Target[0]);
}
LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
switch (E->getIdentType()) {
default:
return EmitUnsupportedLValue(E, "predefined expression");
auto SL = E->getFunctionName();
assert(SL != nullptr && "No StringLiteral name in PredefinedExpr");
StringRef FnName = CurFn->getName();
if (FnName.startswith("\01"))
FnName = FnName.substr(1);
StringRef NameItems[] = {
PredefinedExpr::getIdentTypeName(E->getIdentType()), FnName};
std::string GVName = llvm::join(NameItems, NameItems + 2, ".");
case PredefinedExpr::Func:
case PredefinedExpr::Function:
case PredefinedExpr::LFunction:
case PredefinedExpr::FuncDName:
case PredefinedExpr::FuncSig:
case PredefinedExpr::PrettyFunction: {
PredefinedExpr::IdentType IdentType = E->getIdentType();
std::string GVName;
// FIXME: We should use the string literal mangling for the Microsoft C++
// ABI so that strings get merged.
switch (IdentType) {
default: llvm_unreachable("Invalid type");
case PredefinedExpr::Func: GVName = "__func__."; break;
case PredefinedExpr::Function: GVName = "__FUNCTION__."; break;
case PredefinedExpr::FuncDName: GVName = "__FUNCDNAME__."; break;
case PredefinedExpr::FuncSig: GVName = "__FUNCSIG__."; break;
case PredefinedExpr::LFunction: GVName = "L__FUNCTION__."; break;
case PredefinedExpr::PrettyFunction: GVName = "__PRETTY_FUNCTION__."; break;
}
StringRef FnName = CurFn->getName();
if (FnName.startswith("\01"))
FnName = FnName.substr(1);
GVName += FnName;
// If this is outside of a function use the top level decl.
const Decl *CurDecl = CurCodeDecl;
if (!CurDecl || isa<VarDecl>(CurDecl))
CurDecl = getContext().getTranslationUnitDecl();
const Type *ElemType = E->getType()->getArrayElementTypeNoTypeQual();
std::string FunctionName;
if (isa<BlockDecl>(CurDecl)) {
// Blocks use the mangled function name.
// FIXME: ComputeName should handle blocks.
FunctionName = FnName.str();
} else if (isa<CapturedDecl>(CurDecl)) {
// For a captured statement, the function name is its enclosing
// function name not the one compiler generated.
FunctionName = PredefinedExpr::ComputeName(IdentType, CurDecl);
} else {
FunctionName = PredefinedExpr::ComputeName(IdentType, CurDecl);
assert(cast<ConstantArrayType>(E->getType())->getSize() - 1 ==
FunctionName.size() &&
"Computed __func__ length differs from type!");
}
llvm::Constant *C;
if (ElemType->isWideCharType()) {
SmallString<32> RawChars;
ConvertUTF8ToWideString(
getContext().getTypeSizeInChars(ElemType).getQuantity(), FunctionName,
RawChars);
StringLiteral *SL = StringLiteral::Create(
getContext(), RawChars, StringLiteral::Wide,
/*Pascal = */ false, E->getType(), E->getLocation());
C = CGM.GetAddrOfConstantStringFromLiteral(SL);
} else {
C = CGM.GetAddrOfConstantCString(FunctionName, GVName.c_str(), 1);
}
return MakeAddrLValue(C, E->getType());
}
}
auto C = CGM.GetAddrOfConstantStringFromLiteral(SL, GVName);
return MakeAddrLValue(C, E->getType());
}
/// Emit a type description suitable for use by a runtime sanitizer library. The

View File

@ -2729,7 +2729,8 @@ GenerateStringLiteral(llvm::Constant *C, llvm::GlobalValue::LinkageTypes LT,
/// GetAddrOfConstantStringFromLiteral - Return a pointer to a
/// constant array for the given string literal.
llvm::GlobalVariable *
CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) {
CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
StringRef Name) {
auto Alignment =
getContext().getAlignOfGlobalVarInChars(S->getType()).getQuantity();
@ -2761,7 +2762,7 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) {
GlobalVariableName = MangledNameBuffer;
} else {
LT = llvm::GlobalValue::PrivateLinkage;
GlobalVariableName = ".str";
GlobalVariableName = Name;
}
auto GV = GenerateStringLiteral(C, LT, *this, GlobalVariableName, Alignment);

View File

@ -785,7 +785,8 @@ public:
/// Return a pointer to a constant array for the given string literal.
llvm::GlobalVariable *
GetAddrOfConstantStringFromLiteral(const StringLiteral *S);
GetAddrOfConstantStringFromLiteral(const StringLiteral *S,
StringRef Name = ".str");
/// Return a pointer to a constant array for the given ObjCEncodeExpr node.
llvm::GlobalVariable *

View File

@ -42,6 +42,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaFixItUtils.h"
#include "clang/Sema/Template.h"
#include "llvm/Support/ConvertUTF.h"
using namespace clang;
using namespace sema;
@ -2905,6 +2906,17 @@ ExprResult Sema::BuildDeclarationNameExpr(
}
}
static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source,
SmallString<32> &Target) {
Target.resize(CharByteWidth * (Source.size() + 1));
char *ResultPtr = &Target[0];
const UTF8 *ErrorPtr;
bool success = ConvertUTF8toWide(CharByteWidth, Source, ResultPtr, ErrorPtr);
(void)success;
assert(success);
Target.resize(ResultPtr - &Target[0]);
}
ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
PredefinedExpr::IdentType IT) {
// Pick the current block, lambda, captured statement or function.
@ -2924,22 +2936,35 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
}
QualType ResTy;
StringLiteral *SL = nullptr;
if (cast<DeclContext>(currentDecl)->isDependentContext())
ResTy = Context.DependentTy;
else {
// Pre-defined identifiers are of type char[x], where x is the length of
// the string.
unsigned Length = PredefinedExpr::ComputeName(IT, currentDecl).length();
auto Str = PredefinedExpr::ComputeName(IT, currentDecl);
unsigned Length = Str.length();
llvm::APInt LengthI(32, Length + 1);
if (IT == PredefinedExpr::LFunction)
if (IT == PredefinedExpr::LFunction) {
ResTy = Context.WideCharTy.withConst();
else
SmallString<32> RawChars;
ConvertUTF8ToWideString(Context.getTypeSizeInChars(ResTy).getQuantity(),
Str, RawChars);
ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal,
/*IndexTypeQuals*/ 0);
SL = StringLiteral::Create(Context, RawChars, StringLiteral::Wide,
/*Pascal*/ false, ResTy, Loc);
} else {
ResTy = Context.CharTy.withConst();
ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal, 0);
ResTy = Context.getConstantArrayType(ResTy, LengthI, ArrayType::Normal,
/*IndexTypeQuals*/ 0);
SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii,
/*Pascal*/ false, ResTy, Loc);
}
}
return new (Context) PredefinedExpr(Loc, ResTy, IT);
return new (Context) PredefinedExpr(Loc, ResTy, IT, SL);
}
ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {

View File

@ -1677,6 +1677,15 @@ public:
return getSema().ActOnSEHFinallyBlock(Loc, Block);
}
/// \brief Build a new predefined expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildPredefinedExpr(SourceLocation Loc,
PredefinedExpr::IdentType IT) {
return getSema().BuildPredefinedExpr(Loc, IT);
}
/// \brief Build a new expression that references a declaration.
///
/// By default, performs semantic analysis to build the new expression.
@ -7016,7 +7025,11 @@ OMPClause *TreeTransform<Derived>::TransformOMPFlushClause(OMPFlushClause *C) {
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) {
return E;
if (!E->isTypeDependent())
return E;
return getDerived().RebuildPredefinedExpr(E->getLocation(),
E->getIdentType());
}
template<typename Derived>

View File

@ -422,7 +422,8 @@ void ASTStmtReader::VisitExpr(Expr *E) {
void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) {
VisitExpr(E);
E->setLocation(ReadSourceLocation(Record, Idx));
E->setIdentType((PredefinedExpr::IdentType)Record[Idx++]);
E->Type = (PredefinedExpr::IdentType)Record[Idx++];
E->FnName = cast<StringLiteral>(Reader.ReadSubExpr());
}
void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {

View File

@ -333,6 +333,7 @@ void ASTStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) {
VisitExpr(E);
Writer.AddSourceLocation(E->getLocation(), Record);
Record.push_back(E->getIdentType()); // FIXME: stable encoding
Writer.AddStmt(E->getFunctionName());
Code = serialization::EXPR_PREDEFINED;
}

View File

@ -868,7 +868,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::ObjCProtocolExprClass:
case Stmt::ObjCSelectorExprClass:
case Stmt::ParenListExprClass:
case Stmt::PredefinedExprClass:
case Stmt::ShuffleVectorExprClass:
case Stmt::ConvertVectorExprClass:
case Stmt::VAArgExprClass:
@ -880,6 +879,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// Cases we intentionally don't evaluate, since they don't need
// to be explicitly evaluated.
case Stmt::PredefinedExprClass:
case Stmt::AddrLabelExprClass:
case Stmt::AttributedStmtClass:
case Stmt::IntegerLiteralClass:

View File

@ -8,7 +8,7 @@ extern "C" int printf(const char *, ...);
void freeFunc(int *, char) {
printf("__FUNCSIG__ %s\n\n", __FUNCSIG__);
}
// CHECK: private unnamed_addr constant [{{.*}} x i8] c"void __cdecl freeFunc(int *, char)\00"
// CHECK: @"\01??_C@_0CD@KLGMNNL@void?5__cdecl?5freeFunc?$CIint?5?$CK?0?5cha@" = linkonce_odr unnamed_addr constant [{{.*}} x i8] c"void __cdecl freeFunc(int *, char)\00"
struct TopLevelClass {
void topLevelMethod(int *, char);
@ -16,7 +16,7 @@ struct TopLevelClass {
void TopLevelClass::topLevelMethod(int *, char) {
printf("__FUNCSIG__ %s\n\n", __FUNCSIG__);
}
// CHECK: private unnamed_addr constant [{{.*}} x i8] c"void __thiscall TopLevelClass::topLevelMethod(int *, char)\00"
// CHECK: @"\01??_C@_0DL@OBHNMDP@void?5__thiscall?5TopLevelClass?3?3t@" = linkonce_odr unnamed_addr constant [{{.*}} x i8] c"void __thiscall TopLevelClass::topLevelMethod(int *, char)\00"
namespace NS {
struct NamespacedClass {
@ -25,5 +25,5 @@ struct NamespacedClass {
void NamespacedClass::namespacedMethod(int *, char) {
printf("__FUNCSIG__ %s\n\n", __FUNCSIG__);
}
// CHECK: private unnamed_addr constant [{{.*}} x i8] c"void __thiscall NS::NamespacedClass::namespacedMethod(int *, char)\00"
// CHECK: @"\01??_C@_0ED@PFDKIEBA@void?5__thiscall?5NS?3?3NamespacedCl@" = linkonce_odr unnamed_addr constant [{{.*}} x i8] c"void __thiscall NS::NamespacedClass::namespacedMethod(int *, char)\00"
}

View File

@ -0,0 +1,83 @@
// RUN: %clang_cc1 -std=c++14 %s -triple %itanium_abi_triple -fblocks -emit-llvm -o - | FileCheck %s
// CHECK-DAG: @__func__._ZN13ClassTemplateIiE21classTemplateFunctionERi = private unnamed_addr constant [22 x i8] c"classTemplateFunction\00"
// CHECK-DAG: @__PRETTY_FUNCTION__._ZN13ClassTemplateIiE21classTemplateFunctionERi = private unnamed_addr constant [69 x i8] c"const auto &ClassTemplate<int>::classTemplateFunction(T &) [T = int]\00"
// CHECK-DAG: @__func__._ZN24ClassInTopLevelNamespace16functionTemplateIiEERDaRT_ = private unnamed_addr constant [17 x i8] c"functionTemplate\00"
// CHECK-DAG: @__PRETTY_FUNCTION__._ZN24ClassInTopLevelNamespace16functionTemplateIiEERDaRT_ = private unnamed_addr constant [64 x i8] c"auto &ClassInTopLevelNamespace::functionTemplate(T &) [T = int]\00"
// CHECK-DAG: @__func__._ZN24ClassInTopLevelNamespace16variadicFunctionEPiz = private unnamed_addr constant [17 x i8] c"variadicFunction\00"
// CHECK-DAG: @__PRETTY_FUNCTION__._ZN24ClassInTopLevelNamespace16variadicFunctionEPiz = private unnamed_addr constant [70 x i8] c"decltype(auto) ClassInTopLevelNamespace::variadicFunction(int *, ...)\00"
// CHECK-DAG: @__func__._ZN24ClassInTopLevelNamespace25topLevelNamespaceFunctionEv = private unnamed_addr constant [26 x i8] c"topLevelNamespaceFunction\00"
// CHECK-DAG: @__PRETTY_FUNCTION__._ZN24ClassInTopLevelNamespace25topLevelNamespaceFunctionEv = private unnamed_addr constant [60 x i8] c"auto *ClassInTopLevelNamespace::topLevelNamespaceFunction()\00"
// CHECK-DAG: @__func__.___ZN16ClassBlockConstrD2Ev_block_invoke = private unnamed_addr constant [41 x i8] c"___ZN16ClassBlockConstrD1Ev_block_invoke\00"
// CHECK-DAG: @__func__.___ZN16ClassBlockConstrC2Ev_block_invoke = private unnamed_addr constant [41 x i8] c"___ZN16ClassBlockConstrC1Ev_block_invoke\00"
int printf(const char * _Format, ...);
class ClassInTopLevelNamespace {
public:
auto *topLevelNamespaceFunction() {
printf("__func__ %s\n", __func__);
printf("__FUNCTION__ %s\n", __FUNCTION__);
printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
return static_cast<int *>(nullptr);
}
decltype(auto) variadicFunction(int *a, ...) {
printf("__func__ %s\n", __func__);
printf("__FUNCTION__ %s\n", __FUNCTION__);
printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
return a;
}
template<typename T>
auto &functionTemplate(T &t) {
printf("__func__ %s\n", __func__);
printf("__FUNCTION__ %s\n", __FUNCTION__);
printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
return t;
}
};
template<typename T>
class ClassTemplate {
public:
const auto &classTemplateFunction(T &t) {
printf("__func__ %s\n", __func__);
printf("__FUNCTION__ %s\n", __FUNCTION__);
printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
return t;
}
};
struct ClassBlockConstr {
const char *s;
ClassBlockConstr() {
const char * (^b)() = ^() {
return __func__;
};
s = b();
}
~ClassBlockConstr() {
const char * (^b)() = ^() {
return __func__;
};
s = b();
}
};
int main() {
int a;
ClassInTopLevelNamespace topLevelNamespace;
ClassBlockConstr classBlockConstr;
topLevelNamespace.topLevelNamespaceFunction();
topLevelNamespace.variadicFunction(&a);
topLevelNamespace.functionTemplate(a);
ClassTemplate<int> t;
t.classTemplateFunction(a);
return 0;
}

View File

@ -33,10 +33,9 @@ int baz() {
();
^{
// FIXME: This is obviously wrong.
static_assert(sizeof(__func__) == 1, "__baz_block_invoke");
static_assert(sizeof(__FUNCTION__) == 1, "__baz_block_invoke");
static_assert(sizeof(__PRETTY_FUNCTION__) == 1, "__baz_block_invoke");
static_assert(sizeof(__func__) == 27, "___Z3bazIiEiv_block_invoke");
static_assert(sizeof(__FUNCTION__) == 27, "___Z3bazIiEiv_block_invoke");
static_assert(sizeof(__PRETTY_FUNCTION__) == 27, "___Z3bazIiEiv_block_invoke");
}
();
@ -65,10 +64,9 @@ int main() {
();
^{
// FIXME: This is obviously wrong.
static_assert(sizeof(__func__) == 1, "__main_block_invoke");
static_assert(sizeof(__FUNCTION__) == 1, "__main_block_invoke");
static_assert(sizeof(__PRETTY_FUNCTION__) == 1, "__main_block_invoke");
static_assert(sizeof(__func__) == 20, "__main_block_invoke");
static_assert(sizeof(__FUNCTION__) == 20, "__main_block_invoke");
static_assert(sizeof(__PRETTY_FUNCTION__) == 20, "__main_block_invoke");
}
();