forked from OSchip/llvm-project
Fix for bug http://llvm.org/PR17427.
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:
parent
a9ee5c06f4
commit
ec4747802a
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
();
|
||||
|
||||
|
|
Loading…
Reference in New Issue