forked from OSchip/llvm-project
[Clang] Implement __builtin_source_location.
This builtin returns the address of a global instance of the `std::source_location::__impl` type, which must be defined (with an appropriate shape) before calling the builtin. It will be used to implement std::source_location in libc++ in a future change. The builtin is compatible with GCC's implementation, and libstdc++'s usage. An intentional divergence is that GCC declares the builtin's return type to be `const void*` (for ease-of-implementation reasons), while Clang uses the actual type, `const std::source_location::__impl*`. In order to support this new functionality, I've also added a new 'UnnamedGlobalConstantDecl'. This artificial Decl is modeled after MSGuidDecl, and is used to represent a generic concept of an lvalue constant with global scope, deduplicated by its value. It's possible that MSGuidDecl itself, or some of the other similar sorts of things in Clang might be able to be refactored onto this more-generic concept, but there's enough special-case weirdness in MSGuidDecl that I gave up attempting to share code there, at least for now. Finally, for compatibility with libstdc++'s <source_location> header, I've added a second exception to the "cannot cast from void* to T* in constant evaluation" rule. This seems a bit distasteful, but feels like the best available option. Reviewers: aaron.ballman, erichkeane Differential Revision: https://reviews.llvm.org/D120159
This commit is contained in:
parent
e2485f3c59
commit
d614874900
|
@ -3377,10 +3377,9 @@ as the first argument to the intrinsic.
|
|||
Source location builtins
|
||||
------------------------
|
||||
|
||||
Clang provides experimental builtins to support C++ standard library implementation
|
||||
of ``std::experimental::source_location`` as specified in http://wg21.link/N4600.
|
||||
With the exception of ``__builtin_COLUMN``, these builtins are also implemented by
|
||||
GCC.
|
||||
Clang provides builtins to support C++ standard library implementation
|
||||
of ``std::source_location`` as specified in C++20. With the exception
|
||||
of ``__builtin_COLUMN``, these builtins are also implemented by GCC.
|
||||
|
||||
**Syntax**:
|
||||
|
||||
|
@ -3390,6 +3389,7 @@ GCC.
|
|||
const char *__builtin_FUNCTION();
|
||||
unsigned __builtin_LINE();
|
||||
unsigned __builtin_COLUMN(); // Clang only
|
||||
const std::source_location::__impl *__builtin_source_location();
|
||||
|
||||
**Example of use**:
|
||||
|
||||
|
@ -3416,9 +3416,11 @@ GCC.
|
|||
|
||||
**Description**:
|
||||
|
||||
The builtins ``__builtin_LINE``, ``__builtin_FUNCTION``, and ``__builtin_FILE`` return
|
||||
the values, at the "invocation point", for ``__LINE__``, ``__FUNCTION__``, and
|
||||
``__FILE__`` respectively. These builtins are constant expressions.
|
||||
The builtins ``__builtin_LINE``, ``__builtin_FUNCTION``, and ``__builtin_FILE``
|
||||
return the values, at the "invocation point", for ``__LINE__``,
|
||||
``__FUNCTION__``, and ``__FILE__`` respectively. ``__builtin_COLUMN`` similarly
|
||||
returns the column, though there is no corresponding macro. These builtins are
|
||||
constant expressions.
|
||||
|
||||
When the builtins appear as part of a default function argument the invocation
|
||||
point is the location of the caller. When the builtins appear as part of a
|
||||
|
@ -3429,6 +3431,15 @@ the invocation point is the same as the location of the builtin.
|
|||
When the invocation point of ``__builtin_FUNCTION`` is not a function scope the
|
||||
empty string is returned.
|
||||
|
||||
The builtin ``__builtin_source_location`` returns a pointer to constant static
|
||||
data of type ``std::source_location::__impl``. This type must have already been
|
||||
defined, and must contain exactly four fields: ``const char *_M_file_name``,
|
||||
``const char *_M_function_name``, ``<any-integral-type> _M_line``, and
|
||||
``<any-integral-type> _M_column``. The fields will be populated in the same
|
||||
manner as the above four builtins, except that ``_M_function_name`` is populated
|
||||
with ``__PRETTY_FUNCTION__`` rather than ``__FUNCTION__``.
|
||||
|
||||
|
||||
Alignment builtins
|
||||
------------------
|
||||
Clang provides builtins to support checking and adjusting alignment of
|
||||
|
|
|
@ -193,6 +193,8 @@ C++20 Feature Support
|
|||
it is called through a template instantiation. This fixes
|
||||
`Issue 54578 <https://github.com/llvm/llvm-project/issues/54578>`_.
|
||||
|
||||
- Implemented `__builtin_source_location()` which enables library support for std::source_location.
|
||||
|
||||
C++2b Feature Support
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -314,6 +314,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||
/// Mapping from GUIDs to the corresponding MSGuidDecl.
|
||||
mutable llvm::FoldingSet<MSGuidDecl> MSGuidDecls;
|
||||
|
||||
/// Mapping from APValues to the corresponding UnnamedGlobalConstantDecl.
|
||||
mutable llvm::FoldingSet<UnnamedGlobalConstantDecl>
|
||||
UnnamedGlobalConstantDecls;
|
||||
|
||||
/// Mapping from APValues to the corresponding TemplateParamObjects.
|
||||
mutable llvm::FoldingSet<TemplateParamObjectDecl> TemplateParamObjectDecls;
|
||||
|
||||
|
@ -3064,6 +3068,11 @@ public:
|
|||
/// GUID value.
|
||||
MSGuidDecl *getMSGuidDecl(MSGuidDeclParts Parts) const;
|
||||
|
||||
/// Return a declaration for a uniquified anonymous global constant
|
||||
/// corresponding to a given APValue.
|
||||
UnnamedGlobalConstantDecl *
|
||||
getUnnamedGlobalConstantDecl(QualType Ty, const APValue &Value) const;
|
||||
|
||||
/// Return the template parameter object of the given type with the given
|
||||
/// value.
|
||||
TemplateParamObjectDecl *getTemplateParamObjectDecl(QualType T,
|
||||
|
|
|
@ -4206,6 +4206,53 @@ public:
|
|||
static bool classofKind(Kind K) { return K == Decl::MSGuid; }
|
||||
};
|
||||
|
||||
/// An artificial decl, representing a global anonymous constant value which is
|
||||
/// uniquified by value within a translation unit.
|
||||
///
|
||||
/// These is currently only used to back the LValue returned by
|
||||
/// __builtin_source_location, but could potentially be used for other similar
|
||||
/// situations in the future.
|
||||
class UnnamedGlobalConstantDecl : public ValueDecl,
|
||||
public Mergeable<UnnamedGlobalConstantDecl>,
|
||||
public llvm::FoldingSetNode {
|
||||
|
||||
// The constant value of this global.
|
||||
APValue Value;
|
||||
|
||||
void anchor() override;
|
||||
|
||||
UnnamedGlobalConstantDecl(DeclContext *DC, QualType T, const APValue &Val);
|
||||
|
||||
static UnnamedGlobalConstantDecl *Create(const ASTContext &C, QualType T,
|
||||
const APValue &APVal);
|
||||
static UnnamedGlobalConstantDecl *CreateDeserialized(ASTContext &C,
|
||||
unsigned ID);
|
||||
|
||||
// Only ASTContext::getUnnamedGlobalConstantDecl and deserialization create
|
||||
// these.
|
||||
friend class ASTContext;
|
||||
friend class ASTReader;
|
||||
friend class ASTDeclReader;
|
||||
|
||||
public:
|
||||
/// Print this in a human-readable format.
|
||||
void printName(llvm::raw_ostream &OS) const override;
|
||||
|
||||
const APValue &getValue() const { return Value; }
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType Ty,
|
||||
const APValue &APVal) {
|
||||
Ty.Profile(ID);
|
||||
APVal.Profile(ID);
|
||||
}
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getType(), getValue());
|
||||
}
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == Decl::UnnamedGlobalConstant; }
|
||||
};
|
||||
|
||||
/// Insertion operator for diagnostics. This allows sending an AccessSpecifier
|
||||
/// into a diagnostic with <<.
|
||||
const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
|
||||
|
|
|
@ -4680,16 +4680,17 @@ public:
|
|||
};
|
||||
|
||||
/// Represents a function call to one of __builtin_LINE(), __builtin_COLUMN(),
|
||||
/// __builtin_FUNCTION(), or __builtin_FILE().
|
||||
/// __builtin_FUNCTION(), __builtin_FILE(), or __builtin_source_location().
|
||||
class SourceLocExpr final : public Expr {
|
||||
SourceLocation BuiltinLoc, RParenLoc;
|
||||
DeclContext *ParentContext;
|
||||
|
||||
public:
|
||||
enum IdentKind { Function, File, Line, Column };
|
||||
enum IdentKind { Function, File, Line, Column, SourceLocStruct };
|
||||
|
||||
SourceLocExpr(const ASTContext &Ctx, IdentKind Type, SourceLocation BLoc,
|
||||
SourceLocation RParenLoc, DeclContext *Context);
|
||||
SourceLocExpr(const ASTContext &Ctx, IdentKind Type, QualType ResultTy,
|
||||
SourceLocation BLoc, SourceLocation RParenLoc,
|
||||
DeclContext *Context);
|
||||
|
||||
/// Build an empty call expression.
|
||||
explicit SourceLocExpr(EmptyShell Empty) : Expr(SourceLocExprClass, Empty) {}
|
||||
|
@ -4706,18 +4707,18 @@ public:
|
|||
return static_cast<IdentKind>(SourceLocExprBits.Kind);
|
||||
}
|
||||
|
||||
bool isStringType() const {
|
||||
bool isIntType() const {
|
||||
switch (getIdentKind()) {
|
||||
case File:
|
||||
case Function:
|
||||
return true;
|
||||
case SourceLocStruct:
|
||||
return false;
|
||||
case Line:
|
||||
case Column:
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
llvm_unreachable("unknown source location expression kind");
|
||||
}
|
||||
bool isIntType() const LLVM_READONLY { return !isStringType(); }
|
||||
|
||||
/// If the SourceLocExpr has been resolved return the subexpression
|
||||
/// representing the resolved value. Otherwise return null.
|
||||
|
|
|
@ -2039,6 +2039,7 @@ DEF_TRAVERSE_DECL(BindingDecl, {
|
|||
DEF_TRAVERSE_DECL(MSPropertyDecl, { TRY_TO(TraverseDeclaratorHelper(D)); })
|
||||
|
||||
DEF_TRAVERSE_DECL(MSGuidDecl, {})
|
||||
DEF_TRAVERSE_DECL(UnnamedGlobalConstantDecl, {})
|
||||
|
||||
DEF_TRAVERSE_DECL(TemplateParamObjectDecl, {})
|
||||
|
||||
|
|
|
@ -595,7 +595,7 @@ protected:
|
|||
|
||||
/// The kind of source location builtin represented by the SourceLocExpr.
|
||||
/// Ex. __builtin_LINE, __builtin_FUNCTION, ect.
|
||||
unsigned Kind : 2;
|
||||
unsigned Kind : 3;
|
||||
};
|
||||
|
||||
class StmtExprBitfields {
|
||||
|
|
|
@ -41,6 +41,7 @@ def Named : DeclNode<Decl, "named declarations", 1>;
|
|||
def OMPDeclareReduction : DeclNode<Value>, DeclContext;
|
||||
def OMPDeclareMapper : DeclNode<Value>, DeclContext;
|
||||
def MSGuid : DeclNode<Value>;
|
||||
def UnnamedGlobalConstant : DeclNode<Value>;
|
||||
def TemplateParamObject : DeclNode<Value>;
|
||||
def Declarator : DeclNode<Value, "declarators", 1>;
|
||||
def Field : DeclNode<Declarator, "non-static data members">;
|
||||
|
|
|
@ -11556,4 +11556,9 @@ def err_riscv_builtin_requires_extension : Error<
|
|||
"builtin requires at least one of the following extensions support to be enabled : %0">;
|
||||
def err_riscv_builtin_invalid_lmul : Error<
|
||||
"LMUL argument must be in the range [0,3] or [5,7]">;
|
||||
|
||||
def err_std_source_location_impl_not_found : Error<
|
||||
"'std::source_location::__impl' was not found; it must be defined before '__builtin_source_location' is called">;
|
||||
def err_std_source_location_impl_malformed : Error<
|
||||
"'std::source_location::__impl' must be standard-layout and have only two 'const char *' fields '_M_file_name' and '_M_function_name', and two integral fields '_M_line' and '_M_column'">;
|
||||
} // end of sema component.
|
||||
|
|
|
@ -432,6 +432,7 @@ KEYWORD(__builtin_FILE , KEYALL)
|
|||
KEYWORD(__builtin_FUNCTION , KEYALL)
|
||||
KEYWORD(__builtin_LINE , KEYALL)
|
||||
KEYWORD(__builtin_COLUMN , KEYALL)
|
||||
KEYWORD(__builtin_source_location , KEYCXX)
|
||||
|
||||
// __builtin_types_compatible_p is a GNU C extension that we handle like a C++
|
||||
// type trait.
|
||||
|
|
|
@ -1144,6 +1144,10 @@ public:
|
|||
/// The MSVC "_GUID" struct, which is defined in MSVC header files.
|
||||
RecordDecl *MSVCGuidDecl;
|
||||
|
||||
/// The C++ "std::source_location::__impl" struct, defined in
|
||||
/// \<source_location>.
|
||||
RecordDecl *StdSourceLocationImplDecl;
|
||||
|
||||
/// Caches identifiers/selectors for NSFoundation APIs.
|
||||
std::unique_ptr<NSAPI> NSAPIObj;
|
||||
|
||||
|
@ -5684,14 +5688,15 @@ public:
|
|||
TypeSourceInfo *TInfo, SourceLocation RPLoc);
|
||||
|
||||
// __builtin_LINE(), __builtin_FUNCTION(), __builtin_FILE(),
|
||||
// __builtin_COLUMN()
|
||||
// __builtin_COLUMN(), __builtin_source_location()
|
||||
ExprResult ActOnSourceLocExpr(SourceLocExpr::IdentKind Kind,
|
||||
SourceLocation BuiltinLoc,
|
||||
SourceLocation RPLoc);
|
||||
|
||||
// Build a potentially resolved SourceLocExpr.
|
||||
ExprResult BuildSourceLocExpr(SourceLocExpr::IdentKind Kind,
|
||||
SourceLocation BuiltinLoc, SourceLocation RPLoc,
|
||||
QualType ResultTy, SourceLocation BuiltinLoc,
|
||||
SourceLocation RPLoc,
|
||||
DeclContext *ParentContext);
|
||||
|
||||
// __null
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace serialization {
|
|||
/// Version 4 of AST files also requires that the version control branch and
|
||||
/// revision match exactly, since there is no backward compatibility of
|
||||
/// AST files at this time.
|
||||
const unsigned VERSION_MAJOR = 16;
|
||||
const unsigned VERSION_MAJOR = 17;
|
||||
|
||||
/// AST file minor version number supported by this version of
|
||||
/// Clang.
|
||||
|
@ -1504,7 +1504,10 @@ enum DeclCode {
|
|||
/// An OMPDeclareReductionDecl record.
|
||||
DECL_OMP_DECLARE_REDUCTION,
|
||||
|
||||
DECL_LAST = DECL_OMP_DECLARE_REDUCTION
|
||||
/// A UnnamedGlobalConstantDecl record.
|
||||
DECL_UNNAMED_GLOBAL_CONSTANT,
|
||||
|
||||
DECL_LAST = DECL_UNNAMED_GLOBAL_CONSTANT
|
||||
};
|
||||
|
||||
/// Record codes for each kind of statement or expression.
|
||||
|
|
|
@ -11875,6 +11875,23 @@ ASTContext::getMSGuidDecl(MSGuidDecl::Parts Parts) const {
|
|||
return New;
|
||||
}
|
||||
|
||||
UnnamedGlobalConstantDecl *
|
||||
ASTContext::getUnnamedGlobalConstantDecl(QualType Ty,
|
||||
const APValue &APVal) const {
|
||||
llvm::FoldingSetNodeID ID;
|
||||
UnnamedGlobalConstantDecl::Profile(ID, Ty, APVal);
|
||||
|
||||
void *InsertPos;
|
||||
if (UnnamedGlobalConstantDecl *Existing =
|
||||
UnnamedGlobalConstantDecls.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return Existing;
|
||||
|
||||
UnnamedGlobalConstantDecl *New =
|
||||
UnnamedGlobalConstantDecl::Create(*this, Ty, APVal);
|
||||
UnnamedGlobalConstantDecls.InsertNode(New, InsertPos);
|
||||
return New;
|
||||
}
|
||||
|
||||
TemplateParamObjectDecl *
|
||||
ASTContext::getTemplateParamObjectDecl(QualType T, const APValue &V) const {
|
||||
assert(T->isRecordType() && "template param object of unexpected type");
|
||||
|
|
|
@ -6669,6 +6669,7 @@ ExpectedStmt ASTNodeImporter::VisitExpr(Expr *E) {
|
|||
|
||||
ExpectedStmt ASTNodeImporter::VisitSourceLocExpr(SourceLocExpr *E) {
|
||||
Error Err = Error::success();
|
||||
auto ToType = importChecked(Err, E->getType());
|
||||
auto BLoc = importChecked(Err, E->getBeginLoc());
|
||||
auto RParenLoc = importChecked(Err, E->getEndLoc());
|
||||
if (Err)
|
||||
|
@ -6678,8 +6679,8 @@ ExpectedStmt ASTNodeImporter::VisitSourceLocExpr(SourceLocExpr *E) {
|
|||
return ParentContextOrErr.takeError();
|
||||
|
||||
return new (Importer.getToContext())
|
||||
SourceLocExpr(Importer.getToContext(), E->getIdentKind(), BLoc, RParenLoc,
|
||||
*ParentContextOrErr);
|
||||
SourceLocExpr(Importer.getToContext(), E->getIdentKind(), ToType, BLoc,
|
||||
RParenLoc, *ParentContextOrErr);
|
||||
}
|
||||
|
||||
ExpectedStmt ASTNodeImporter::VisitVAArgExpr(VAArgExpr *E) {
|
||||
|
|
|
@ -838,6 +838,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
|
|||
case ExternCContext:
|
||||
case Decomposition:
|
||||
case MSGuid:
|
||||
case UnnamedGlobalConstant:
|
||||
case TemplateParamObject:
|
||||
|
||||
case UsingDirective:
|
||||
|
|
|
@ -3363,6 +3363,31 @@ APValue &MSGuidDecl::getAsAPValue() const {
|
|||
return APVal;
|
||||
}
|
||||
|
||||
void UnnamedGlobalConstantDecl::anchor() {}
|
||||
|
||||
UnnamedGlobalConstantDecl::UnnamedGlobalConstantDecl(DeclContext *DC,
|
||||
QualType Ty,
|
||||
const APValue &Value)
|
||||
: ValueDecl(Decl::UnnamedGlobalConstant, DC, SourceLocation(),
|
||||
DeclarationName(), Ty),
|
||||
Value(Value) {}
|
||||
|
||||
UnnamedGlobalConstantDecl *
|
||||
UnnamedGlobalConstantDecl::Create(const ASTContext &C, QualType T,
|
||||
const APValue &Value) {
|
||||
DeclContext *DC = C.getTranslationUnitDecl();
|
||||
return new (C, DC) UnnamedGlobalConstantDecl(DC, T, Value);
|
||||
}
|
||||
|
||||
UnnamedGlobalConstantDecl *
|
||||
UnnamedGlobalConstantDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
||||
return new (C, ID) UnnamedGlobalConstantDecl(nullptr, QualType(), APValue());
|
||||
}
|
||||
|
||||
void UnnamedGlobalConstantDecl::printName(llvm::raw_ostream &OS) const {
|
||||
OS << "unnamed-global-constant";
|
||||
}
|
||||
|
||||
static const char *getAccessName(AccessSpecifier AS) {
|
||||
switch (AS) {
|
||||
case AS_none:
|
||||
|
|
|
@ -2136,26 +2136,11 @@ bool BinaryOperator::isNullPointerArithmeticExtension(ASTContext &Ctx,
|
|||
return true;
|
||||
}
|
||||
|
||||
static QualType getDecayedSourceLocExprType(const ASTContext &Ctx,
|
||||
SourceLocExpr::IdentKind Kind) {
|
||||
switch (Kind) {
|
||||
case SourceLocExpr::File:
|
||||
case SourceLocExpr::Function: {
|
||||
QualType ArrTy = Ctx.getStringLiteralArrayType(Ctx.CharTy, 0);
|
||||
return Ctx.getPointerType(ArrTy->getAsArrayTypeUnsafe()->getElementType());
|
||||
}
|
||||
case SourceLocExpr::Line:
|
||||
case SourceLocExpr::Column:
|
||||
return Ctx.UnsignedIntTy;
|
||||
}
|
||||
llvm_unreachable("unhandled case");
|
||||
}
|
||||
|
||||
SourceLocExpr::SourceLocExpr(const ASTContext &Ctx, IdentKind Kind,
|
||||
SourceLocation BLoc, SourceLocation RParenLoc,
|
||||
QualType ResultTy, SourceLocation BLoc,
|
||||
SourceLocation RParenLoc,
|
||||
DeclContext *ParentContext)
|
||||
: Expr(SourceLocExprClass, getDecayedSourceLocExprType(Ctx, Kind),
|
||||
VK_PRValue, OK_Ordinary),
|
||||
: Expr(SourceLocExprClass, ResultTy, VK_PRValue, OK_Ordinary),
|
||||
BuiltinLoc(BLoc), RParenLoc(RParenLoc), ParentContext(ParentContext) {
|
||||
SourceLocExprBits.Kind = Kind;
|
||||
setDependence(ExprDependence::None);
|
||||
|
@ -2171,6 +2156,8 @@ StringRef SourceLocExpr::getBuiltinStr() const {
|
|||
return "__builtin_LINE";
|
||||
case Column:
|
||||
return "__builtin_COLUMN";
|
||||
case SourceLocStruct:
|
||||
return "__builtin_source_location";
|
||||
}
|
||||
llvm_unreachable("unexpected IdentKind!");
|
||||
}
|
||||
|
@ -2207,7 +2194,7 @@ APValue SourceLocExpr::EvaluateInContext(const ASTContext &Ctx,
|
|||
return MakeStringLiteral(Path);
|
||||
}
|
||||
case SourceLocExpr::Function: {
|
||||
const Decl *CurDecl = dyn_cast_or_null<Decl>(Context);
|
||||
const auto *CurDecl = dyn_cast<Decl>(Context);
|
||||
return MakeStringLiteral(
|
||||
CurDecl ? PredefinedExpr::ComputeName(PredefinedExpr::Function, CurDecl)
|
||||
: std::string(""));
|
||||
|
@ -2220,6 +2207,54 @@ APValue SourceLocExpr::EvaluateInContext(const ASTContext &Ctx,
|
|||
: PLoc.getColumn();
|
||||
return APValue(IntVal);
|
||||
}
|
||||
case SourceLocExpr::SourceLocStruct: {
|
||||
// Fill in a std::source_location::__impl structure, by creating an
|
||||
// artificial file-scoped CompoundLiteralExpr, and returning a pointer to
|
||||
// that.
|
||||
const CXXRecordDecl *ImplDecl = getType()->getPointeeCXXRecordDecl();
|
||||
assert(ImplDecl);
|
||||
|
||||
// Construct an APValue for the __impl struct, and get or create a Decl
|
||||
// corresponding to that. Note that we've already verified that the shape of
|
||||
// the ImplDecl type is as expected.
|
||||
|
||||
APValue Value(APValue::UninitStruct(), 0, 4);
|
||||
for (FieldDecl *F : ImplDecl->fields()) {
|
||||
StringRef Name = F->getName();
|
||||
if (Name == "_M_file_name") {
|
||||
SmallString<256> Path(PLoc.getFilename());
|
||||
Ctx.getLangOpts().remapPathPrefix(Path);
|
||||
Value.getStructField(F->getFieldIndex()) = MakeStringLiteral(Path);
|
||||
} else if (Name == "_M_function_name") {
|
||||
// Note: this emits the PrettyFunction name -- different than what
|
||||
// __builtin_FUNCTION() above returns!
|
||||
const auto *CurDecl = dyn_cast<Decl>(Context);
|
||||
Value.getStructField(F->getFieldIndex()) = MakeStringLiteral(
|
||||
CurDecl && !isa<TranslationUnitDecl>(CurDecl)
|
||||
? StringRef(PredefinedExpr::ComputeName(
|
||||
PredefinedExpr::PrettyFunction, CurDecl))
|
||||
: "");
|
||||
} else if (Name == "_M_line") {
|
||||
QualType Ty = F->getType();
|
||||
llvm::APSInt IntVal(Ctx.getIntWidth(Ty),
|
||||
Ty->hasUnsignedIntegerRepresentation());
|
||||
IntVal = PLoc.getLine();
|
||||
Value.getStructField(F->getFieldIndex()) = APValue(IntVal);
|
||||
} else if (Name == "_M_column") {
|
||||
QualType Ty = F->getType();
|
||||
llvm::APSInt IntVal(Ctx.getIntWidth(Ty),
|
||||
Ty->hasUnsignedIntegerRepresentation());
|
||||
IntVal = PLoc.getColumn();
|
||||
Value.getStructField(F->getFieldIndex()) = APValue(IntVal);
|
||||
}
|
||||
}
|
||||
|
||||
UnnamedGlobalConstantDecl *GV =
|
||||
Ctx.getUnnamedGlobalConstantDecl(getType()->getPointeeType(), Value);
|
||||
|
||||
return APValue(GV, CharUnits::Zero(), ArrayRef<APValue::LValuePathEntry>{},
|
||||
false);
|
||||
}
|
||||
}
|
||||
llvm_unreachable("unhandled case");
|
||||
}
|
||||
|
|
|
@ -465,14 +465,11 @@ static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) {
|
|||
islvalue = NTTParm->getType()->isReferenceType() ||
|
||||
NTTParm->getType()->isRecordType();
|
||||
else
|
||||
islvalue = isa<VarDecl>(D) || isa<FieldDecl>(D) ||
|
||||
isa<IndirectFieldDecl>(D) ||
|
||||
isa<BindingDecl>(D) ||
|
||||
isa<MSGuidDecl>(D) ||
|
||||
isa<TemplateParamObjectDecl>(D) ||
|
||||
(Ctx.getLangOpts().CPlusPlus &&
|
||||
(isa<FunctionDecl>(D) || isa<MSPropertyDecl>(D) ||
|
||||
isa<FunctionTemplateDecl>(D)));
|
||||
islvalue =
|
||||
isa<VarDecl, FieldDecl, IndirectFieldDecl, BindingDecl, MSGuidDecl,
|
||||
UnnamedGlobalConstantDecl, TemplateParamObjectDecl>(D) ||
|
||||
(Ctx.getLangOpts().CPlusPlus &&
|
||||
(isa<FunctionDecl, MSPropertyDecl, FunctionTemplateDecl>(D)));
|
||||
|
||||
return islvalue ? Cl::CL_LValue : Cl::CL_PRValue;
|
||||
}
|
||||
|
|
|
@ -1978,7 +1978,8 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
|
|||
return true;
|
||||
// ... the address of a function,
|
||||
// ... the address of a GUID [MS extension],
|
||||
return isa<FunctionDecl>(D) || isa<MSGuidDecl>(D);
|
||||
// ... the address of an unnamed global constant
|
||||
return isa<FunctionDecl, MSGuidDecl, UnnamedGlobalConstantDecl>(D);
|
||||
}
|
||||
|
||||
if (B.is<TypeInfoLValue>() || B.is<DynamicAllocLValue>())
|
||||
|
@ -2013,6 +2014,10 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
|
|||
// Block variables at global or local static scope.
|
||||
case Expr::BlockExprClass:
|
||||
return !cast<BlockExpr>(E)->getBlockDecl()->hasCaptures();
|
||||
// The APValue generated from a __builtin_source_location will be emitted as a
|
||||
// literal.
|
||||
case Expr::SourceLocExprClass:
|
||||
return true;
|
||||
case Expr::ImplicitValueInitExprClass:
|
||||
// FIXME:
|
||||
// We can never form an lvalue with an implicit value initialization as its
|
||||
|
@ -4024,6 +4029,16 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
|
|||
return CompleteObject(LVal.Base, &V, GD->getType());
|
||||
}
|
||||
|
||||
// Allow reading the APValue from an UnnamedGlobalConstantDecl.
|
||||
if (auto *GCD = dyn_cast<UnnamedGlobalConstantDecl>(D)) {
|
||||
if (isModification(AK)) {
|
||||
Info.FFDiag(E, diag::note_constexpr_modify_global);
|
||||
return CompleteObject();
|
||||
}
|
||||
return CompleteObject(LVal.Base, const_cast<APValue *>(&GCD->getValue()),
|
||||
GCD->getType());
|
||||
}
|
||||
|
||||
// Allow reading from template parameter objects.
|
||||
if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(D)) {
|
||||
if (isModification(AK)) {
|
||||
|
@ -8175,7 +8190,8 @@ static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info,
|
|||
|
||||
bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
|
||||
const NamedDecl *D = E->getDecl();
|
||||
if (isa<FunctionDecl, MSGuidDecl, TemplateParamObjectDecl>(D))
|
||||
if (isa<FunctionDecl, MSGuidDecl, TemplateParamObjectDecl,
|
||||
UnnamedGlobalConstantDecl>(D))
|
||||
return Success(cast<ValueDecl>(D));
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
|
||||
return VisitVarDecl(E, VD);
|
||||
|
@ -8715,7 +8731,7 @@ public:
|
|||
bool VisitCXXNewExpr(const CXXNewExpr *E);
|
||||
|
||||
bool VisitSourceLocExpr(const SourceLocExpr *E) {
|
||||
assert(E->isStringType() && "SourceLocExpr isn't a pointer type?");
|
||||
assert(!E->isIntType() && "SourceLocExpr isn't a pointer type?");
|
||||
APValue LValResult = E->EvaluateInContext(
|
||||
Info.Ctx, Info.CurrentCall->CurSourceLocExprScope.getDefaultExpr());
|
||||
Result.setFrom(Info.Ctx, LValResult);
|
||||
|
@ -8780,6 +8796,22 @@ bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
|
|||
return evaluateLValue(E->getSubExpr(), Result);
|
||||
}
|
||||
|
||||
// Is the provided decl 'std::source_location::current'?
|
||||
static bool IsDeclSourceLocationCurrent(const FunctionDecl *FD) {
|
||||
if (!FD)
|
||||
return false;
|
||||
const IdentifierInfo *FnII = FD->getIdentifier();
|
||||
if (!FnII || !FnII->isStr("current"))
|
||||
return false;
|
||||
|
||||
const auto *RD = dyn_cast<RecordDecl>(FD->getParent());
|
||||
if (!RD)
|
||||
return false;
|
||||
|
||||
const IdentifierInfo *ClassII = RD->getIdentifier();
|
||||
return RD->isInStdNamespace() && ClassII && ClassII->isStr("source_location");
|
||||
}
|
||||
|
||||
bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
||||
const Expr *SubExpr = E->getSubExpr();
|
||||
|
||||
|
@ -8797,14 +8829,23 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
|||
// permitted in constant expressions in C++11. Bitcasts from cv void* are
|
||||
// also static_casts, but we disallow them as a resolution to DR1312.
|
||||
if (!E->getType()->isVoidPointerType()) {
|
||||
if (!Result.InvalidBase && !Result.Designator.Invalid &&
|
||||
// In some circumstances, we permit casting from void* to cv1 T*, when the
|
||||
// actual pointee object is actually a cv2 T.
|
||||
bool VoidPtrCastMaybeOK =
|
||||
!Result.InvalidBase && !Result.Designator.Invalid &&
|
||||
!Result.IsNullPtr &&
|
||||
Info.Ctx.hasSameUnqualifiedType(Result.Designator.getType(Info.Ctx),
|
||||
E->getType()->getPointeeType()) &&
|
||||
Info.getStdAllocatorCaller("allocate")) {
|
||||
// Inside a call to std::allocator::allocate and friends, we permit
|
||||
// casting from void* back to cv1 T* for a pointer that points to a
|
||||
// cv2 T.
|
||||
E->getType()->getPointeeType());
|
||||
// 1. We'll allow it in std::allocator::allocate, and anything which that
|
||||
// calls.
|
||||
// 2. We'll allow it in the body of std::source_location:current. This is
|
||||
// necessary for libstdc++'s <source_location>, which gave its
|
||||
// parameter the type void*, and cast from that back to `const __impl*`
|
||||
// in the body. (Fixed for new versions in gcc.gnu.org/PR104602).
|
||||
if (VoidPtrCastMaybeOK &&
|
||||
(Info.getStdAllocatorCaller("allocate") ||
|
||||
IsDeclSourceLocationCurrent(Info.CurrentCall->Callee))) {
|
||||
// Permitted.
|
||||
} else {
|
||||
Result.Designator.setInvalid();
|
||||
if (SubExpr->getType()->isVoidPointerType())
|
||||
|
|
|
@ -118,6 +118,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
|
|||
case Decl::Label: // __label__ x;
|
||||
case Decl::Import:
|
||||
case Decl::MSGuid: // __declspec(uuid("..."))
|
||||
case Decl::UnnamedGlobalConstant:
|
||||
case Decl::TemplateParamObject:
|
||||
case Decl::OMPThreadPrivate:
|
||||
case Decl::OMPAllocate:
|
||||
|
|
|
@ -1909,6 +1909,9 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
|
|||
if (auto *GD = dyn_cast<MSGuidDecl>(D))
|
||||
return CGM.GetAddrOfMSGuidDecl(GD);
|
||||
|
||||
if (auto *GCD = dyn_cast<UnnamedGlobalConstantDecl>(D))
|
||||
return CGM.GetAddrOfUnnamedGlobalConstantDecl(GCD);
|
||||
|
||||
if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(D))
|
||||
return CGM.GetAddrOfTemplateParamObject(TPO);
|
||||
|
||||
|
|
|
@ -2905,6 +2905,37 @@ ConstantAddress CodeGenModule::GetAddrOfMSGuidDecl(const MSGuidDecl *GD) {
|
|||
return ConstantAddress(Addr, Ty, Alignment);
|
||||
}
|
||||
|
||||
ConstantAddress CodeGenModule::GetAddrOfUnnamedGlobalConstantDecl(
|
||||
const UnnamedGlobalConstantDecl *GCD) {
|
||||
CharUnits Alignment = getContext().getTypeAlignInChars(GCD->getType());
|
||||
|
||||
llvm::GlobalVariable **Entry = nullptr;
|
||||
Entry = &UnnamedGlobalConstantDeclMap[GCD];
|
||||
if (*Entry)
|
||||
return ConstantAddress(*Entry, (*Entry)->getValueType(), Alignment);
|
||||
|
||||
ConstantEmitter Emitter(*this);
|
||||
llvm::Constant *Init;
|
||||
|
||||
const APValue &V = GCD->getValue();
|
||||
|
||||
assert(!V.isAbsent());
|
||||
Init = Emitter.emitForInitializer(V, GCD->getType().getAddressSpace(),
|
||||
GCD->getType());
|
||||
|
||||
auto *GV = new llvm::GlobalVariable(getModule(), Init->getType(),
|
||||
/*isConstant=*/true,
|
||||
llvm::GlobalValue::PrivateLinkage, Init,
|
||||
".constant");
|
||||
GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
|
||||
GV->setAlignment(Alignment.getAsAlign());
|
||||
|
||||
Emitter.finalize(GV);
|
||||
|
||||
*Entry = GV;
|
||||
return ConstantAddress(GV, GV->getValueType(), Alignment);
|
||||
}
|
||||
|
||||
ConstantAddress CodeGenModule::GetAddrOfTemplateParamObject(
|
||||
const TemplateParamObjectDecl *TPO) {
|
||||
StringRef Name = getMangledName(TPO);
|
||||
|
|
|
@ -406,6 +406,8 @@ private:
|
|||
llvm::StringMap<llvm::GlobalVariable *> CFConstantStringMap;
|
||||
|
||||
llvm::DenseMap<llvm::Constant *, llvm::GlobalVariable *> ConstantStringMap;
|
||||
llvm::DenseMap<const UnnamedGlobalConstantDecl *, llvm::GlobalVariable *>
|
||||
UnnamedGlobalConstantDeclMap;
|
||||
llvm::DenseMap<const Decl*, llvm::Constant *> StaticLocalDeclMap;
|
||||
llvm::DenseMap<const Decl*, llvm::GlobalVariable*> StaticLocalDeclGuardMap;
|
||||
llvm::DenseMap<const Expr*, llvm::Constant *> MaterializedGlobalTemporaryMap;
|
||||
|
@ -875,6 +877,10 @@ public:
|
|||
/// Get the address of a GUID.
|
||||
ConstantAddress GetAddrOfMSGuidDecl(const MSGuidDecl *GD);
|
||||
|
||||
/// Get the address of a UnnamedGlobalConstant
|
||||
ConstantAddress
|
||||
GetAddrOfUnnamedGlobalConstantDecl(const UnnamedGlobalConstantDecl *GCD);
|
||||
|
||||
/// Get the address of a template parameter object.
|
||||
ConstantAddress
|
||||
GetAddrOfTemplateParamObject(const TemplateParamObjectDecl *TPO);
|
||||
|
|
|
@ -791,6 +791,7 @@ class CastExpressionIdValidator final : public CorrectionCandidateCallback {
|
|||
/// [GNU] '__builtin_FUNCTION' '(' ')'
|
||||
/// [GNU] '__builtin_LINE' '(' ')'
|
||||
/// [CLANG] '__builtin_COLUMN' '(' ')'
|
||||
/// [GNU] '__builtin_source_location' '(' ')'
|
||||
/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
|
||||
/// [GNU] '__null'
|
||||
/// [OBJC] '[' objc-message-expr ']'
|
||||
|
@ -1303,6 +1304,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
|
|||
case tok::kw___builtin_FILE:
|
||||
case tok::kw___builtin_FUNCTION:
|
||||
case tok::kw___builtin_LINE:
|
||||
case tok::kw___builtin_source_location:
|
||||
if (NotPrimaryExpression)
|
||||
*NotPrimaryExpression = true;
|
||||
// This parses the complete suffix; we can return early.
|
||||
|
@ -2508,6 +2510,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
|
|||
/// [GNU] '__builtin_FUNCTION' '(' ')'
|
||||
/// [GNU] '__builtin_LINE' '(' ')'
|
||||
/// [CLANG] '__builtin_COLUMN' '(' ')'
|
||||
/// [GNU] '__builtin_source_location' '(' ')'
|
||||
/// [OCL] '__builtin_astype' '(' assignment-expression ',' type-name ')'
|
||||
///
|
||||
/// [GNU] offsetof-member-designator:
|
||||
|
@ -2730,7 +2733,8 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
|
|||
case tok::kw___builtin_COLUMN:
|
||||
case tok::kw___builtin_FILE:
|
||||
case tok::kw___builtin_FUNCTION:
|
||||
case tok::kw___builtin_LINE: {
|
||||
case tok::kw___builtin_LINE:
|
||||
case tok::kw___builtin_source_location: {
|
||||
// Attempt to consume the r-paren.
|
||||
if (Tok.isNot(tok::r_paren)) {
|
||||
Diag(Tok, diag::err_expected) << tok::r_paren;
|
||||
|
@ -2747,6 +2751,8 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
|
|||
return SourceLocExpr::Line;
|
||||
case tok::kw___builtin_COLUMN:
|
||||
return SourceLocExpr::Column;
|
||||
case tok::kw___builtin_source_location:
|
||||
return SourceLocExpr::SourceLocStruct;
|
||||
default:
|
||||
llvm_unreachable("invalid keyword");
|
||||
}
|
||||
|
|
|
@ -202,8 +202,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
|
|||
LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp),
|
||||
StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr),
|
||||
StdCoroutineTraitsCache(nullptr), CXXTypeInfoDecl(nullptr),
|
||||
MSVCGuidDecl(nullptr), NSNumberDecl(nullptr), NSValueDecl(nullptr),
|
||||
NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr),
|
||||
MSVCGuidDecl(nullptr), StdSourceLocationImplDecl(nullptr),
|
||||
NSNumberDecl(nullptr), NSValueDecl(nullptr), NSStringDecl(nullptr),
|
||||
StringWithUTF8StringMethod(nullptr),
|
||||
ValueWithBytesObjCTypeMethod(nullptr), NSArrayDecl(nullptr),
|
||||
ArrayWithObjectsMethod(nullptr), NSDictionaryDecl(nullptr),
|
||||
DictionaryWithObjectsMethod(nullptr), GlobalNewDeleteDeclared(false),
|
||||
|
|
|
@ -3439,6 +3439,10 @@ ExprResult Sema::BuildDeclarationNameExpr(
|
|||
valueKind = VK_LValue;
|
||||
break;
|
||||
|
||||
case Decl::UnnamedGlobalConstant:
|
||||
valueKind = VK_LValue;
|
||||
break;
|
||||
|
||||
case Decl::CXXMethod:
|
||||
// If we're referring to a method with an __unknown_anytype
|
||||
// result type, make the entire expression __unknown_anytype.
|
||||
|
@ -14125,8 +14129,8 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
|
|||
return MPTy;
|
||||
}
|
||||
}
|
||||
} else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl) &&
|
||||
!isa<BindingDecl>(dcl) && !isa<MSGuidDecl>(dcl))
|
||||
} else if (!isa<FunctionDecl, NonTypeTemplateParmDecl, BindingDecl,
|
||||
MSGuidDecl, UnnamedGlobalConstantDecl>(dcl))
|
||||
llvm_unreachable("Unknown/unexpected decl type");
|
||||
}
|
||||
|
||||
|
@ -16310,18 +16314,111 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
|
|||
return new (Context) GNUNullExpr(Ty, TokenLoc);
|
||||
}
|
||||
|
||||
static CXXRecordDecl *LookupStdSourceLocationImpl(Sema &S, SourceLocation Loc) {
|
||||
CXXRecordDecl *ImplDecl = nullptr;
|
||||
|
||||
// Fetch the std::source_location::__impl decl.
|
||||
if (NamespaceDecl *Std = S.getStdNamespace()) {
|
||||
LookupResult ResultSL(S, &S.PP.getIdentifierTable().get("source_location"),
|
||||
Loc, Sema::LookupOrdinaryName);
|
||||
if (S.LookupQualifiedName(ResultSL, Std)) {
|
||||
if (auto *SLDecl = ResultSL.getAsSingle<RecordDecl>()) {
|
||||
LookupResult ResultImpl(S, &S.PP.getIdentifierTable().get("__impl"),
|
||||
Loc, Sema::LookupOrdinaryName);
|
||||
if ((SLDecl->isCompleteDefinition() || SLDecl->isBeingDefined()) &&
|
||||
S.LookupQualifiedName(ResultImpl, SLDecl)) {
|
||||
ImplDecl = ResultImpl.getAsSingle<CXXRecordDecl>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ImplDecl || !ImplDecl->isCompleteDefinition()) {
|
||||
S.Diag(Loc, diag::err_std_source_location_impl_not_found);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Verify that __impl is a trivial struct type, with no base classes, and with
|
||||
// only the four expected fields.
|
||||
if (ImplDecl->isUnion() || !ImplDecl->isStandardLayout() ||
|
||||
ImplDecl->getNumBases() != 0) {
|
||||
S.Diag(Loc, diag::err_std_source_location_impl_malformed);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned Count = 0;
|
||||
for (FieldDecl *F : ImplDecl->fields()) {
|
||||
StringRef Name = F->getName();
|
||||
|
||||
if (Name == "_M_file_name") {
|
||||
if (F->getType() !=
|
||||
S.Context.getPointerType(S.Context.CharTy.withConst()))
|
||||
break;
|
||||
Count++;
|
||||
} else if (Name == "_M_function_name") {
|
||||
if (F->getType() !=
|
||||
S.Context.getPointerType(S.Context.CharTy.withConst()))
|
||||
break;
|
||||
Count++;
|
||||
} else if (Name == "_M_line") {
|
||||
if (!F->getType()->isIntegerType())
|
||||
break;
|
||||
Count++;
|
||||
} else if (Name == "_M_column") {
|
||||
if (!F->getType()->isIntegerType())
|
||||
break;
|
||||
Count++;
|
||||
} else {
|
||||
Count = 100; // invalid
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Count != 4) {
|
||||
S.Diag(Loc, diag::err_std_source_location_impl_malformed);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ImplDecl;
|
||||
}
|
||||
|
||||
ExprResult Sema::ActOnSourceLocExpr(SourceLocExpr::IdentKind Kind,
|
||||
SourceLocation BuiltinLoc,
|
||||
SourceLocation RPLoc) {
|
||||
return BuildSourceLocExpr(Kind, BuiltinLoc, RPLoc, CurContext);
|
||||
QualType ResultTy;
|
||||
switch (Kind) {
|
||||
case SourceLocExpr::File:
|
||||
case SourceLocExpr::Function: {
|
||||
QualType ArrTy = Context.getStringLiteralArrayType(Context.CharTy, 0);
|
||||
ResultTy =
|
||||
Context.getPointerType(ArrTy->getAsArrayTypeUnsafe()->getElementType());
|
||||
break;
|
||||
}
|
||||
case SourceLocExpr::Line:
|
||||
case SourceLocExpr::Column:
|
||||
ResultTy = Context.UnsignedIntTy;
|
||||
break;
|
||||
case SourceLocExpr::SourceLocStruct:
|
||||
if (!StdSourceLocationImplDecl) {
|
||||
StdSourceLocationImplDecl =
|
||||
LookupStdSourceLocationImpl(*this, BuiltinLoc);
|
||||
if (!StdSourceLocationImplDecl)
|
||||
return ExprError();
|
||||
}
|
||||
ResultTy = Context.getPointerType(
|
||||
Context.getRecordType(StdSourceLocationImplDecl).withConst());
|
||||
break;
|
||||
}
|
||||
|
||||
return BuildSourceLocExpr(Kind, ResultTy, BuiltinLoc, RPLoc, CurContext);
|
||||
}
|
||||
|
||||
ExprResult Sema::BuildSourceLocExpr(SourceLocExpr::IdentKind Kind,
|
||||
QualType ResultTy,
|
||||
SourceLocation BuiltinLoc,
|
||||
SourceLocation RPLoc,
|
||||
DeclContext *ParentContext) {
|
||||
return new (Context)
|
||||
SourceLocExpr(Context, Kind, BuiltinLoc, RPLoc, ParentContext);
|
||||
SourceLocExpr(Context, Kind, ResultTy, BuiltinLoc, RPLoc, ParentContext);
|
||||
}
|
||||
|
||||
bool Sema::CheckConversionToObjCLiteral(QualType DstType, Expr *&Exp,
|
||||
|
|
|
@ -7009,7 +7009,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
// -- a predefined __func__ variable
|
||||
APValue::LValueBase Base = Value.getLValueBase();
|
||||
auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
|
||||
if (Base && (!VD || isa<LifetimeExtendedTemporaryDecl>(VD))) {
|
||||
if (Base &&
|
||||
(!VD ||
|
||||
isa<LifetimeExtendedTemporaryDecl, UnnamedGlobalConstantDecl>(VD))) {
|
||||
Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref)
|
||||
<< Arg->getSourceRange();
|
||||
return ExprError();
|
||||
|
|
|
@ -867,6 +867,11 @@ Decl *TemplateDeclInstantiator::VisitMSGuidDecl(MSGuidDecl *D) {
|
|||
llvm_unreachable("GUID declaration cannot be instantiated");
|
||||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitUnnamedGlobalConstantDecl(
|
||||
UnnamedGlobalConstantDecl *D) {
|
||||
llvm_unreachable("UnnamedGlobalConstantDecl cannot be instantiated");
|
||||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitTemplateParamObjectDecl(
|
||||
TemplateParamObjectDecl *D) {
|
||||
llvm_unreachable("template parameter objects cannot be instantiated");
|
||||
|
|
|
@ -3386,10 +3386,11 @@ public:
|
|||
/// By default, performs semantic analysis to build the new expression.
|
||||
/// Subclasses may override this routine to provide different behavior.
|
||||
ExprResult RebuildSourceLocExpr(SourceLocExpr::IdentKind Kind,
|
||||
SourceLocation BuiltinLoc,
|
||||
QualType ResultTy, SourceLocation BuiltinLoc,
|
||||
SourceLocation RPLoc,
|
||||
DeclContext *ParentContext) {
|
||||
return getSema().BuildSourceLocExpr(Kind, BuiltinLoc, RPLoc, ParentContext);
|
||||
return getSema().BuildSourceLocExpr(Kind, ResultTy, BuiltinLoc, RPLoc,
|
||||
ParentContext);
|
||||
}
|
||||
|
||||
/// Build a new Objective-C boxed expression.
|
||||
|
@ -11653,8 +11654,8 @@ ExprResult TreeTransform<Derived>::TransformSourceLocExpr(SourceLocExpr *E) {
|
|||
if (!getDerived().AlwaysRebuild() && !NeedRebuildFunc)
|
||||
return E;
|
||||
|
||||
return getDerived().RebuildSourceLocExpr(E->getIdentKind(), E->getBeginLoc(),
|
||||
E->getEndLoc(),
|
||||
return getDerived().RebuildSourceLocExpr(E->getIdentKind(), E->getType(),
|
||||
E->getBeginLoc(), E->getEndLoc(),
|
||||
getSema().CurContext);
|
||||
}
|
||||
|
||||
|
|
|
@ -391,6 +391,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
|
|||
case Decl::Field:
|
||||
case Decl::MSProperty:
|
||||
case Decl::MSGuid:
|
||||
case Decl::UnnamedGlobalConstant:
|
||||
case Decl::TemplateParamObject:
|
||||
case Decl::ObjCIvar:
|
||||
case Decl::ObjCAtDefsField:
|
||||
|
|
|
@ -370,6 +370,7 @@ namespace clang {
|
|||
void VisitFieldDecl(FieldDecl *FD);
|
||||
void VisitMSPropertyDecl(MSPropertyDecl *FD);
|
||||
void VisitMSGuidDecl(MSGuidDecl *D);
|
||||
void VisitUnnamedGlobalConstantDecl(UnnamedGlobalConstantDecl *D);
|
||||
void VisitTemplateParamObjectDecl(TemplateParamObjectDecl *D);
|
||||
void VisitIndirectFieldDecl(IndirectFieldDecl *FD);
|
||||
RedeclarableResult VisitVarDeclImpl(VarDecl *D);
|
||||
|
@ -1428,6 +1429,17 @@ void ASTDeclReader::VisitMSGuidDecl(MSGuidDecl *D) {
|
|||
Reader.getContext().setPrimaryMergedDecl(D, Existing->getCanonicalDecl());
|
||||
}
|
||||
|
||||
void ASTDeclReader::VisitUnnamedGlobalConstantDecl(
|
||||
UnnamedGlobalConstantDecl *D) {
|
||||
VisitValueDecl(D);
|
||||
D->Value = Record.readAPValue();
|
||||
|
||||
// Add this to the AST context's lookup structure, and merge if needed.
|
||||
if (UnnamedGlobalConstantDecl *Existing =
|
||||
Reader.getContext().UnnamedGlobalConstantDecls.GetOrInsertNode(D))
|
||||
Reader.getContext().setPrimaryMergedDecl(D, Existing->getCanonicalDecl());
|
||||
}
|
||||
|
||||
void ASTDeclReader::VisitTemplateParamObjectDecl(TemplateParamObjectDecl *D) {
|
||||
VisitValueDecl(D);
|
||||
D->Value = Record.readAPValue();
|
||||
|
@ -3709,6 +3721,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
|
|||
case DECL_MS_GUID:
|
||||
D = MSGuidDecl::CreateDeserialized(Context, ID);
|
||||
break;
|
||||
case DECL_UNNAMED_GLOBAL_CONSTANT:
|
||||
D = UnnamedGlobalConstantDecl::CreateDeserialized(Context, ID);
|
||||
break;
|
||||
case DECL_TEMPLATE_PARAM_OBJECT:
|
||||
D = TemplateParamObjectDecl::CreateDeserialized(Context, ID);
|
||||
break;
|
||||
|
|
|
@ -96,6 +96,7 @@ namespace clang {
|
|||
void VisitFieldDecl(FieldDecl *D);
|
||||
void VisitMSPropertyDecl(MSPropertyDecl *D);
|
||||
void VisitMSGuidDecl(MSGuidDecl *D);
|
||||
void VisitUnnamedGlobalConstantDecl(UnnamedGlobalConstantDecl *D);
|
||||
void VisitTemplateParamObjectDecl(TemplateParamObjectDecl *D);
|
||||
void VisitIndirectFieldDecl(IndirectFieldDecl *D);
|
||||
void VisitVarDecl(VarDecl *D);
|
||||
|
@ -966,6 +967,13 @@ void ASTDeclWriter::VisitMSGuidDecl(MSGuidDecl *D) {
|
|||
Code = serialization::DECL_MS_GUID;
|
||||
}
|
||||
|
||||
void ASTDeclWriter::VisitUnnamedGlobalConstantDecl(
|
||||
UnnamedGlobalConstantDecl *D) {
|
||||
VisitValueDecl(D);
|
||||
Record.AddAPValue(D->getValue());
|
||||
Code = serialization::DECL_UNNAMED_GLOBAL_CONSTANT;
|
||||
}
|
||||
|
||||
void ASTDeclWriter::VisitTemplateParamObjectDecl(TemplateParamObjectDecl *D) {
|
||||
VisitValueDecl(D);
|
||||
Record.AddAPValue(D->getValue());
|
||||
|
|
|
@ -10,71 +10,63 @@ void testRemap() {
|
|||
|
||||
#line 8 "builtin-source-location.cpp"
|
||||
|
||||
struct source_location {
|
||||
private:
|
||||
unsigned int __m_line = 0;
|
||||
unsigned int __m_col = 0;
|
||||
const char *__m_file = nullptr;
|
||||
const char *__m_func = nullptr;
|
||||
|
||||
namespace std {
|
||||
class source_location {
|
||||
public:
|
||||
constexpr void set(unsigned l, unsigned c, const char *f, const char *func) {
|
||||
__m_line = l;
|
||||
__m_col = c;
|
||||
__m_file = f;
|
||||
__m_func = func;
|
||||
}
|
||||
static constexpr source_location current(
|
||||
unsigned int __line = __builtin_LINE(),
|
||||
unsigned int __col = __builtin_COLUMN(),
|
||||
const char *__file = __builtin_FILE(),
|
||||
const char *__func = __builtin_FUNCTION()) noexcept {
|
||||
static constexpr source_location current(const void *__p = __builtin_source_location()) noexcept {
|
||||
source_location __loc;
|
||||
__loc.set(__line, __col, __file, __func);
|
||||
__loc.__m_impl = static_cast<const __impl *>(__p);
|
||||
return __loc;
|
||||
}
|
||||
static source_location bad_current(
|
||||
unsigned int __line = __builtin_LINE(),
|
||||
unsigned int __col = __builtin_COLUMN(),
|
||||
const char *__file = __builtin_FILE(),
|
||||
const char *__func = __builtin_FUNCTION()) noexcept {
|
||||
source_location __loc;
|
||||
__loc.set(__line, __col, __file, __func);
|
||||
return __loc;
|
||||
static source_location bad_current(const void *__p = __builtin_source_location()) noexcept {
|
||||
return current(__p);
|
||||
}
|
||||
constexpr source_location() = default;
|
||||
constexpr source_location(source_location const &) = default;
|
||||
constexpr unsigned int line() const noexcept { return __m_line; }
|
||||
constexpr unsigned int column() const noexcept { return __m_col; }
|
||||
constexpr const char *file() const noexcept { return __m_file; }
|
||||
constexpr const char *function() const noexcept { return __m_func; }
|
||||
};
|
||||
constexpr unsigned int line() const noexcept { return __m_impl->_M_line; }
|
||||
constexpr unsigned int column() const noexcept { return __m_impl->_M_column; }
|
||||
constexpr const char *file() const noexcept { return __m_impl->_M_file_name; }
|
||||
constexpr const char *function() const noexcept { return __m_impl->_M_function_name; }
|
||||
|
||||
using SL = source_location;
|
||||
private:
|
||||
// Note: The type name "std::source_location::__impl", and its constituent
|
||||
// field-names are required by __builtin_source_location().
|
||||
struct __impl {
|
||||
const char *_M_file_name;
|
||||
const char *_M_function_name;
|
||||
unsigned _M_line;
|
||||
unsigned _M_column;
|
||||
};
|
||||
const __impl *__m_impl = nullptr;
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
using SL = std::source_location;
|
||||
|
||||
extern "C" int sink(...);
|
||||
|
||||
|
||||
// RUN: FileCheck --input-file %t.ll %s --check-prefix=CHECK-GLOBAL-ONE
|
||||
//
|
||||
// CHECK-GLOBAL-ONE-DAG: @[[FILE:.*]] = {{.*}}c"test_const_init.cpp\00"
|
||||
// CHECK-GLOBAL-ONE-DAG: @[[FUNC:.*]] = private unnamed_addr constant [1 x i8] zeroinitializer, align 1
|
||||
//
|
||||
// CHECK-GLOBAL-ONE: @const_init_global ={{.*}} global %struct.source_location { i32 1000, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]]
|
||||
// CHECK-GLOBAL-ONE-DAG: @[[IMPL:.*]] = private unnamed_addr constant %"struct.std::source_location::__impl" { {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], {{.*}} i32 1000, i32 {{[0-9]+}} }, align 8
|
||||
// CHECK-GLOBAL-ONE: @const_init_global ={{.*}} global %"class.std::source_location" { %"struct.std::source_location::__impl"* @[[IMPL]] }, align 8
|
||||
#line 1000 "test_const_init.cpp"
|
||||
SL const_init_global = SL::current();
|
||||
|
||||
// RUN: FileCheck --input-file %t.ll %s --check-prefix=CHECK-GLOBAL-TWO
|
||||
//
|
||||
// CHECK-GLOBAL-TWO-DAG: @runtime_init_global ={{.*}} global %struct.source_location zeroinitializer, align 8
|
||||
// CHECK-GLOBAL-TWO-DAG: @runtime_init_global ={{.*}} global %"class.std::source_location" zeroinitializer, align 8
|
||||
//
|
||||
// CHECK-GLOBAL-TWO-DAG: @[[FILE:.*]] = {{.*}}c"test_runtime_init.cpp\00"
|
||||
// CHECK-GLOBAL-TWO-DAG: @[[FUNC:.*]] = private unnamed_addr constant [1 x i8] zeroinitializer, align 1
|
||||
// CHECK-GLOBAL-TWO-DAG: @[[IMPL:.*]] = private unnamed_addr constant %"struct.std::source_location::__impl" { {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], {{.*}} i32 1100, i32 {{[0-9]+}} }, align 8
|
||||
//
|
||||
// CHECK-GLOBAL-TWO: define internal void @__cxx_global_var_init()
|
||||
// CHECK-GLOBAL-TWO-NOT: ret
|
||||
// CHECK-GLOBAL-TWO: call void @_ZN15source_location11bad_currentEjjPKcS1_(%struct.source_location* sret(%struct.source_location) align 8 @runtime_init_global,
|
||||
// CHECK-GLOBAL-TWO-SAME: i32 noundef 1100, i32 noundef {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]],
|
||||
// CHECK-GLOBAL-TWO: %call = call %"struct.std::source_location::__impl"* @_ZNSt15source_location11bad_currentEPKv({{.*}} @[[IMPL]]
|
||||
// CHECK-GLOBAL-TWO: store %"struct.std::source_location::__impl"* %call, {{.*}} @runtime_init_global
|
||||
|
||||
#line 1100 "test_runtime_init.cpp"
|
||||
SL runtime_init_global = SL::bad_current();
|
||||
|
||||
|
@ -83,11 +75,11 @@ extern "C" void test_function() {
|
|||
// RUN: FileCheck --input-file %t.ll %s --check-prefix=CHECK-LOCAL-ONE
|
||||
//
|
||||
// CHECK-LOCAL-ONE-DAG: @[[FILE:.*]] = {{.*}}c"test_current.cpp\00"
|
||||
// CHECK-LOCAL-ONE-DAG: @[[FUNC:.*]] = {{.*}}c"test_function\00"
|
||||
// CHECK-LOCAL-ONE-DAG: @[[FUNC:.*]] = {{.*}}c"void test_function()\00"
|
||||
// CHECK-LOCAL-ONE-DAG: @[[IMPL:.*]] = private unnamed_addr constant %"struct.std::source_location::__impl" { {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], {{.*}} i32 2100, i32 {{[0-9]+}} }, align 8
|
||||
//
|
||||
// CHECK-LOCAL-ONE: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret(%struct.source_location) align 8 %local,
|
||||
// CHECK-LOCAL-ONE-SAME: i32 noundef 2100, i32 noundef {{[0-9]+}},
|
||||
// CHECK-LOCAL-ONE-SAME: {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]],
|
||||
// CHECK-LOCAL-ONE: define {{.*}} @test_function
|
||||
// CHECK-LOCAL-ONE: call %"struct.std::source_location::__impl"* @_ZNSt15source_location7currentEPKv({{.*}} @[[IMPL]]
|
||||
#line 2100 "test_current.cpp"
|
||||
SL local = SL::current();
|
||||
}
|
||||
|
@ -106,13 +98,14 @@ struct TestInit {
|
|||
// CHECK-CTOR-GLOBAL-DAG: @GlobalInitVal ={{.*}} global %struct.TestInit zeroinitializer, align 8
|
||||
// CHECK-CTOR-GLOBAL-DAG: @[[FILE:.*]] = {{.*}}c"GlobalInitVal.cpp\00"
|
||||
// CHECK-CTOR-GLOBAL-DAG: @[[FUNC:.*]] = private unnamed_addr constant [1 x i8] zeroinitializer, align 1
|
||||
// CHECK-CTOR-GLOBAL-DAG: @[[IMPL:.*]] = private unnamed_addr constant %"struct.std::source_location::__impl" { {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], {{.*}} i32 3400, i32 {{[0-9]+}} }, align 8
|
||||
//
|
||||
// CHECK-CTOR-GLOBAL: define internal void @__cxx_global_var_init.{{[0-9]+}}()
|
||||
// CHECK-CTOR-GLOBAL-NOT: ret
|
||||
//
|
||||
// CHECK-CTOR-GLOBAL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret(%struct.source_location) align 8 %[[TMP_ONE:[^,]*]],
|
||||
// CHECK-CTOR-GLOBAL-SAME: i32 noundef 3400, i32 noundef {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]],
|
||||
// CHECK-CTOR-GLOBAL-NEXT: call void @_ZN8TestInitC1E15source_location(%struct.TestInit* {{[^,]*}} @GlobalInitVal, %struct.source_location* {{.*}}%[[TMP_ONE]])
|
||||
// CHECK-CTOR-GLOBAL: call %"struct.std::source_location::__impl"* @_ZNSt15source_location7currentEPKv({{.*}} @[[IMPL]]
|
||||
// CHECK-CTOR-GLOBAL-NOT: ret
|
||||
// CHECK-CTOR-GLOBAL: call void @_ZN8TestInitC1ESt15source_location(%struct.TestInit* {{[^,]*}} @GlobalInitVal, %"struct.std::source_location::__impl"*
|
||||
#line 3400 "GlobalInitVal.cpp"
|
||||
TestInit GlobalInitVal;
|
||||
|
||||
|
@ -120,14 +113,16 @@ extern "C" void test_init_function() {
|
|||
// RUN: FileCheck --input-file %t.ll %s --check-prefix=CHECK-CTOR-LOCAL
|
||||
//
|
||||
// CHECK-CTOR-LOCAL-DAG: @[[FILE:.*]] = {{.*}}c"LocalInitVal.cpp\00"
|
||||
// CHECK-CTOR-LOCAL-DAG: @[[FUNC:.*]] = {{.*}}c"test_init_function\00"
|
||||
// CHECK-CTOR-LOCAL-DAG: @[[FUNC:.*]] = {{.*}}c"void test_init_function()\00"
|
||||
// CHECK-CTOR-LOCAL-DAG: @[[IMPL:.*]] = private unnamed_addr constant %"struct.std::source_location::__impl" { {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], {{.*}} i32 3500, i32 {{[0-9]+}} }, align 8
|
||||
//
|
||||
// CHECK-CTOR-LOCAL: define{{.*}} void @test_init_function()
|
||||
// CHECK-CTOR-LOCAL-NOT: ret
|
||||
//
|
||||
// CHECK-CTOR-LOCAL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret(%struct.source_location) align 8 %[[TMP:[^,]*]],
|
||||
// CHECK-CTOR-LOCAL-SAME: i32 noundef 3500, i32 noundef {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]],
|
||||
// CHECK-CTOR-LOCAL-NEXT: call void @_ZN8TestInitC1E15source_location(%struct.TestInit* {{[^,]*}} %init_local, %struct.source_location* {{.*}}%[[TMP]])
|
||||
// CHECK-CTOR-LOCAL: call %"struct.std::source_location::__impl"* @_ZNSt15source_location7currentEPKv({{.*}} @[[IMPL]]
|
||||
// CHECK-CTOR-LOCAL-NOT: ret
|
||||
// CHECK-CTOR-LOCAL: call void @_ZN8TestInitC1ESt15source_location(%struct.TestInit* {{[^,]*}} %init_local, %"struct.std::source_location::__impl"*
|
||||
|
||||
#line 3500 "LocalInitVal.cpp"
|
||||
TestInit init_local;
|
||||
sink(init_local);
|
||||
|
@ -144,26 +139,30 @@ struct TestInitConstexpr {
|
|||
// RUN: FileCheck --input-file %t.ll %s --check-prefix=CHECK-CONSTEXPR-T2
|
||||
//
|
||||
// CHECK-CONSTEXPR-T2-DAG: @[[FILE_INIT:.*]] = {{.*}}c"ConstexprCtor.cpp\00"
|
||||
// CHECK-CONSTEXPR-T2-DAG: @[[FUNC_INIT:.*]] = {{.*}}c"TestInitConstexpr\00"
|
||||
// CHECK-CONSTEXPR-T2-DAG: @[[FUNC_INIT:.*]] = {{.*}}c"TestInitConstexpr::TestInitConstexpr(SL)\00"
|
||||
// CHECK-CONSTEXPR-T2-DAG: @[[IMPL_INIT:.*]] = private unnamed_addr constant %"struct.std::source_location::__impl" { {{[^@]*}}@[[FILE_INIT]], {{[^@]*}}@[[FUNC_INIT]], {{.*}} i32 4200, i32 {{[0-9]+}} }, align 8
|
||||
// CHECK-CONSTEXPR-T2-DAG: @[[FILE_ARG:.*]] = {{.*}}c"ConstexprGlobal.cpp\00"
|
||||
// CHECK-CONSTEXPR-T2-DAG: @[[EMPTY:.*]] = private unnamed_addr constant [1 x i8] zeroinitializer, align 1
|
||||
// CHECK-CONSTEXPR-T2-DAG: @[[IMPL_ARG:.*]] = private unnamed_addr constant %"struct.std::source_location::__impl" { {{[^@]*}}@[[FILE_ARG]], {{[^@]*}}@[[EMPTY]], {{.*}} i32 4400, i32 {{[0-9]+}} }, align 8
|
||||
//
|
||||
// CHECK-CONSTEXPR-T2: @ConstexprGlobal ={{.*}} global %struct.TestInitConstexpr {
|
||||
// CHECK-CONSTEXPR-T2-SAME: %struct.source_location { i32 4200, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE_INIT]], {{[^@]*}}@[[FUNC_INIT]],
|
||||
// CHECK-CONSTEXPR-T2-SAME: {{[^%]*}}%struct.source_location { i32 4400, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE_ARG]], {{[^@]*}}@[[EMPTY]]
|
||||
// CHECK-CONSTEXPR-T2-SAME: %"class.std::source_location" { %"struct.std::source_location::__impl"* @[[IMPL_INIT]] },
|
||||
// CHECK-CONSTEXPR-T2-SAME: %"class.std::source_location" { %"struct.std::source_location::__impl"* @[[IMPL_ARG]] }
|
||||
#line 4400 "ConstexprGlobal.cpp"
|
||||
TestInitConstexpr ConstexprGlobal;
|
||||
|
||||
extern "C" void test_init_function_constexpr() {
|
||||
// RUN: FileCheck --input-file %t.ll %s --check-prefix=CHECK-CONSTEXPR-LOCAL
|
||||
//
|
||||
// CHECK-CONSTEXPR-LOCAL-DAG: @[[FUNC:.*]] = {{.*}}c"test_init_function_constexpr\00"
|
||||
// CHECK-CONSTEXPR-LOCAL-DAG: @[[FUNC:.*]] = {{.*}}c"void test_init_function_constexpr()\00"
|
||||
// CHECK-CONSTEXPR-LOCAL-DAG: @[[FILE:.*]] = {{.*}}c"ConstexprLocal.cpp\00"
|
||||
// CHECK-CONSTEXPR-LOCAL-DAG: @[[IMPL:.*]] = private unnamed_addr constant %"struct.std::source_location::__impl" { {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], {{.*}} i32 4600, i32 {{[0-9]+}} }, align 8
|
||||
//
|
||||
// CHECK-CONSTEXPR-LOCAL: define{{.*}} void @test_init_function_constexpr()
|
||||
// CHECK-CONSTEXPR-LOCAL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret(%struct.source_location) align 8 %[[TMP:[^,]*]],
|
||||
// CHECK-CONSTEXPR-LOCAL-SAME: i32 noundef 4600, i32 noundef {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]]
|
||||
// CHECK-CONSTEXPR-LOCAL: call void @_ZN17TestInitConstexprC1E15source_location(%struct.TestInitConstexpr* {{[^,]*}} %local_val, {{.*}}%[[TMP]])
|
||||
// CHECK-CONSTEXPR-LOCAL-NOT: ret
|
||||
// CHECK-CONSTEXPR-LOCAL: call %"struct.std::source_location::__impl"* @_ZNSt15source_location7currentEPKv({{.*}} @[[IMPL]]
|
||||
// CHECK-CONSTEXPR-LOCAL-NOT: ret
|
||||
// CHECK-CONSTEXPR-LOCAL: call void @_ZN17TestInitConstexprC1ESt15source_location(%struct.TestInitConstexpr* {{[^,]*}} %local_val, %"struct.std::source_location::__impl"*
|
||||
#line 4600 "ConstexprLocal.cpp"
|
||||
TestInitConstexpr local_val;
|
||||
}
|
||||
|
@ -180,60 +179,44 @@ struct TestInitAgg {
|
|||
// RUN: FileCheck --input-file %t.ll %s --check-prefix=CHECK-AGG-DEFAULT
|
||||
//
|
||||
// CHECK-AGG-DEFAULT-DAG: @[[FILE:.*]] = {{.*}}c"TestInitAgg.cpp\00"
|
||||
// CHECK-AGG-DEFAULT-DAG: @[[FUNC:.*]] = {{.*}}c"TestInitAgg\00"
|
||||
// CHECK-AGG-DEFAULT-DAG: @[[FUNC:.*]] = {{.*}}c"TestInitAgg::TestInitAgg()\00"
|
||||
// CHECK-AGG-DEFAULT-DAG: @[[IMPL:.*]] = private unnamed_addr constant %"struct.std::source_location::__impl" { {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], {{.*}} i32 5000, i32 {{[0-9]+}} }, align 8
|
||||
//
|
||||
// CHECK-AGG-DEFAULT: @GlobalAggDefault ={{.*}} global %struct.TestInitAgg {
|
||||
// CHECK-AGG-DEFAULT-SAME: %struct.source_location zeroinitializer,
|
||||
// CHECK-AGG-DEFAULT-SAME: %struct.source_location { i32 5000, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]]
|
||||
// CHECK-AGG-DEFAULT-SAME: %"class.std::source_location" zeroinitializer,
|
||||
// CHECK-AGG-DEFAULT-SAME: %"class.std::source_location" { %"struct.std::source_location::__impl"* @[[IMPL]] }
|
||||
#line 5400 "GlobalAggDefault.cpp"
|
||||
TestInitAgg GlobalAggDefault;
|
||||
|
||||
#line 5500 "test_agg_init_test.cpp"
|
||||
extern "C" void test_agg_init() {
|
||||
// RUN: FileCheck --input-file %t.ll %s --check-prefix=CHECK-AGG-BRACE
|
||||
//
|
||||
// CHECK-AGG-BRACE-DAG: @[[FILE:.*]] = {{.*}}c"BraceInitEnd.cpp\00"
|
||||
// CHECK-AGG-BRACE-DAG: @[[FUNC:.*]] = {{.*}}c"test_agg_init\00"
|
||||
//
|
||||
// CHECK-AGG-BRACE: define{{.*}} void @test_agg_init()
|
||||
// CHECK-AGG-BRACE: %[[I2:.*]] = getelementptr inbounds %struct.TestInitAgg, %struct.TestInitAgg* %local_brace_init, i32 0, i32 1
|
||||
// CHECK-AGG-BRACE-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret(%struct.source_location) align 8 %[[I2]],
|
||||
// CHECK-AGG-BRACE-SAME: i32 noundef 5700, i32 noundef {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]]
|
||||
// RUN: FileCheck --input-file %t.ll %s --check-prefix=CHECK-AGG-INIT
|
||||
|
||||
// CHECK-AGG-INIT-DAG: @[[FUNC:.*]] = {{.*}}c"void test_agg_init()\00"
|
||||
|
||||
// CHECK-AGG-INIT-DAG: @[[FILE:.*]] = {{.*}}c"BraceInitEnd.cpp\00"
|
||||
// CHECK-AGG-INIT-DAG: @[[IMPL:.*]] = private unnamed_addr constant %"struct.std::source_location::__impl" { {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], {{.*}} i32 5700, i32 {{[0-9]+}} }, align 8
|
||||
|
||||
#line 5600 "BraceInitStart.cpp"
|
||||
TestInitAgg local_brace_init{
|
||||
#line 5700 "BraceInitEnd.cpp"
|
||||
};
|
||||
|
||||
// RUN: FileCheck --input-file %t.ll %s --check-prefix=CHECK-AGG-EQUAL
|
||||
//
|
||||
// CHECK-AGG-EQUAL-DAG: @[[FILE:.*]] = {{.*}}c"EqualInitEnd.cpp\00"
|
||||
// CHECK-AGG-EQUAL-DAG: @[[FUNC:.*]] = {{.*}}c"test_agg_init\00"
|
||||
//
|
||||
// CHECK-AGG-EQUAL: define{{.*}} void @test_agg_init()
|
||||
// CHECK-AGG-EQUAL: %[[I2:.*]] = getelementptr inbounds %struct.TestInitAgg, %struct.TestInitAgg* %local_equal_init, i32 0, i32 1
|
||||
// CHECK-AGG-EQUAL-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret(%struct.source_location) align 8 %[[I2]],
|
||||
// CHECK-AGG-EQUAL-SAME: i32 noundef 5900, i32 noundef {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]]
|
||||
// CHECK-AGG-INIT-DAG: @[[FILE:.*]] = {{.*}}c"EqualInitEnd.cpp\00"
|
||||
// CHECK-AGG-INIT-DAG: @[[IMPL:.*]] = private unnamed_addr constant %"struct.std::source_location::__impl" { {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], {{.*}} i32 5900, i32 {{[0-9]+}} }, align 8
|
||||
|
||||
#line 5800 "EqualInitStart.cpp"
|
||||
TestInitAgg local_equal_init =
|
||||
{
|
||||
#line 5900 "EqualInitEnd.cpp"
|
||||
};
|
||||
|
||||
// RUN: FileCheck --input-file %t.ll %s --check-prefix=CHECK-AGG-LIST
|
||||
//
|
||||
// CHECK-AGG-LIST-DAG: @[[FILE_DEFAULT:.*]] = {{.*}}c"InitListEnd.cpp\00"
|
||||
// CHECK-AGG-LIST-DAG: @[[FILE_ELEM:.*]] = {{.*}}c"ListElem.cpp\00"
|
||||
// CHECK-AGG-LIST-DAG: @[[FUNC:.*]] = {{.*}}c"test_agg_init\00"
|
||||
//
|
||||
// CHECK-AGG-LIST: define{{.*}} void @test_agg_init()
|
||||
//
|
||||
// CHECK-AGG-LIST: %[[I1:.*]] = getelementptr inbounds %struct.TestInitAgg, %struct.TestInitAgg* %local_list_init, i32 0, i32 0
|
||||
// CHECK-AGG-LIST-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret(%struct.source_location) align 8 %[[I1]],
|
||||
// CHECK-AGG-LIST-SAME: i32 noundef 6100, i32 noundef {{[0-9]+}}, {{[^@]*}}@[[FILE_ELEM]], {{[^@]*}}@[[FUNC]]
|
||||
//
|
||||
// CHECK-AGG-LIST: %[[I2:.*]] = getelementptr inbounds %struct.TestInitAgg, %struct.TestInitAgg* %local_list_init, i32 0, i32 1
|
||||
// CHECK-AGG-LIST-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret(%struct.source_location) align 8 %[[I2]],
|
||||
// CHECK-AGG-LIST-SAME: i32 noundef 6200, i32 noundef {{[0-9]+}}, {{[^@]*}}@[[FILE_DEFAULT]], {{[^@]*}}@[[FUNC]]
|
||||
|
||||
// CHECK-AGG-INIT-DAG: @[[FILE_DEFAULT:.*]] = {{.*}}c"InitListEnd.cpp\00"
|
||||
// CHECK-AGG-INIT-DAG: @[[FILE_ELEM:.*]] = {{.*}}c"ListElem.cpp\00"
|
||||
// CHECK-AGG-INIT-DAG: @[[IMPL_DEFAULT:.*]] = private unnamed_addr constant %"struct.std::source_location::__impl" { {{[^@]*}}@[[FILE_ELEM]], {{[^@]*}}@[[FUNC]], {{.*}} i32 6100, i32 {{[0-9]+}} }, align 8
|
||||
// CHECK-AGG-INIT-DAG: @[[IMPL_ELEM:.*]] = private unnamed_addr constant %"struct.std::source_location::__impl" { {{[^@]*}}@[[FILE_DEFAULT]], {{[^@]*}}@[[FUNC]], {{.*}} i32 6200, i32 {{[0-9]+}} }, align 8
|
||||
|
||||
#line 6000 "InitListStart.cpp"
|
||||
TestInitAgg local_list_init =
|
||||
{
|
||||
|
@ -260,14 +243,8 @@ void test_template() {
|
|||
// RUN: FileCheck --input-file %t.ll %s --check-prefix=CHECK-TEMPL -DINT_ID=1
|
||||
//
|
||||
// CHECK-TEMPL-DAG: @[[FILE:.*]] = {{.*}}c"local_templ.cpp\00"
|
||||
// CHECK-TEMPL-DAG: @[[FUNC:.*]] = {{.*}}c"test_template\00"
|
||||
//
|
||||
// CHECK-TEMPL: define weak_odr void @_Z13test_templateI15source_locationLi[[INT_ID]]EEvv()
|
||||
// CHECK-TEMPL-NEXT: entry:
|
||||
// CHECK-TEMPL-NOT: ret
|
||||
//
|
||||
// CHECK-TEMPL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret(%struct.source_location) align 8 %[[TMP:[^,]*]],
|
||||
// CHECK-TEMPL-SAME: i32 noundef 7300, i32 noundef {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]]
|
||||
// CHECK-TEMPL-DAG: @[[FUNC:.*]] = {{.*}}c"void test_template() [T = std::source_location, V = [[INT_ID]]]\00"
|
||||
// CHECK-TEMPL-DAG: @[[IMPL:.*]] = private unnamed_addr constant %"struct.std::source_location::__impl" { {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], {{.*}} i32 7300, i32 {{[0-9]+}} }, align 8
|
||||
#line 7300 "local_templ.cpp"
|
||||
TestTemplate<T, V> local_templ;
|
||||
}
|
||||
|
|
|
@ -9,37 +9,39 @@ template <unsigned>
|
|||
struct Printer;
|
||||
|
||||
namespace std {
|
||||
namespace experimental {
|
||||
struct source_location {
|
||||
private:
|
||||
unsigned int __m_line = 0;
|
||||
unsigned int __m_col = 0;
|
||||
const char *__m_file = nullptr;
|
||||
const char *__m_func = nullptr;
|
||||
class source_location {
|
||||
struct __impl;
|
||||
|
||||
public:
|
||||
static constexpr source_location current(
|
||||
const char *__file = __builtin_FILE(),
|
||||
const char *__func = __builtin_FUNCTION(),
|
||||
unsigned int __line = __builtin_LINE(),
|
||||
unsigned int __col = __builtin_COLUMN()) noexcept {
|
||||
static constexpr source_location current(const __impl *__p = __builtin_source_location()) noexcept {
|
||||
source_location __loc;
|
||||
__loc.__m_line = __line;
|
||||
__loc.__m_col = __col;
|
||||
__loc.__m_file = __file;
|
||||
__loc.__m_func = __func;
|
||||
__loc.__m_impl = __p;
|
||||
return __loc;
|
||||
}
|
||||
constexpr source_location() = default;
|
||||
constexpr source_location(source_location const &) = default;
|
||||
constexpr unsigned int line() const noexcept { return __m_line; }
|
||||
constexpr unsigned int column() const noexcept { return __m_col; }
|
||||
constexpr const char *file() const noexcept { return __m_file; }
|
||||
constexpr const char *function() const noexcept { return __m_func; }
|
||||
constexpr unsigned int line() const noexcept { return __m_impl ? __m_impl->_M_line : 0; }
|
||||
constexpr unsigned int column() const noexcept { return __m_impl ? __m_impl->_M_column : 0; }
|
||||
constexpr const char *file() const noexcept { return __m_impl ? __m_impl->_M_file_name : ""; }
|
||||
constexpr const char *function() const noexcept { return __m_impl ? __m_impl->_M_function_name : ""; }
|
||||
|
||||
private:
|
||||
// Note: The type name "std::source_location::__impl", and its constituent
|
||||
// field-names are required by __builtin_source_location().
|
||||
struct __impl {
|
||||
const char *_M_file_name;
|
||||
const char *_M_function_name;
|
||||
unsigned _M_line;
|
||||
unsigned _M_column;
|
||||
};
|
||||
const __impl *__m_impl = nullptr;
|
||||
|
||||
public:
|
||||
using public_impl_alias = __impl;
|
||||
};
|
||||
} // namespace experimental
|
||||
} // namespace std
|
||||
|
||||
using SL = std::experimental::source_location;
|
||||
using SL = std::source_location;
|
||||
|
||||
#include "Inputs/source-location-file.h"
|
||||
namespace SLF = source_location_file;
|
||||
|
@ -75,12 +77,14 @@ static_assert(is_same<decltype(__builtin_LINE()), unsigned>);
|
|||
static_assert(is_same<decltype(__builtin_COLUMN()), unsigned>);
|
||||
static_assert(is_same<decltype(__builtin_FILE()), const char *>);
|
||||
static_assert(is_same<decltype(__builtin_FUNCTION()), const char *>);
|
||||
static_assert(is_same<decltype(__builtin_source_location()), const std::source_location::public_impl_alias *>);
|
||||
|
||||
// test noexcept
|
||||
static_assert(noexcept(__builtin_LINE()));
|
||||
static_assert(noexcept(__builtin_COLUMN()));
|
||||
static_assert(noexcept(__builtin_FILE()));
|
||||
static_assert(noexcept(__builtin_FUNCTION()));
|
||||
static_assert(noexcept(__builtin_source_location()));
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// __builtin_LINE()
|
||||
|
@ -354,7 +358,7 @@ static_assert(test_function());
|
|||
|
||||
template <class T, class U = SL>
|
||||
constexpr Pair<U, U> test_func_template(T, U u = U::current()) {
|
||||
static_assert(is_equal(__func__, U::current().function()));
|
||||
static_assert(is_equal(__PRETTY_FUNCTION__, U::current().function()));
|
||||
return {u, U::current()};
|
||||
}
|
||||
template <class T>
|
||||
|
@ -376,10 +380,11 @@ struct TestCtor {
|
|||
void ctor_tests() {
|
||||
constexpr TestCtor<> Default;
|
||||
constexpr TestCtor<> Template{42};
|
||||
static_assert(!is_equal(Default.info.function(), __func__));
|
||||
static_assert(is_equal(Default.info.function(), "TestCtor"));
|
||||
static_assert(is_equal(Template.info.function(), "TestCtor"));
|
||||
static_assert(is_equal(Template.ctor_info.function(), __func__));
|
||||
static const char *XYZZY = Template.info.function();
|
||||
static_assert(is_equal(Default.info.function(), "test_func::TestCtor<>::TestCtor() [T = std::source_location]"));
|
||||
static_assert(is_equal(Default.ctor_info.function(), ""));
|
||||
static_assert(is_equal(Template.info.function(), "test_func::TestCtor<>::TestCtor(int, U) [T = std::source_location, U = std::source_location]"));
|
||||
static_assert(is_equal(Template.ctor_info.function(), __PRETTY_FUNCTION__));
|
||||
}
|
||||
|
||||
constexpr SL global_sl = SL::current();
|
||||
|
@ -521,7 +526,7 @@ constexpr bool test_in_func() {
|
|||
static_assert(is_equal(b.a.info.file(), "test_func_passed.cpp"));
|
||||
static_assert(is_equal(b.a.func, "test_in_func"));
|
||||
static_assert(is_equal(b.a.func2, "test_in_func"));
|
||||
static_assert(is_equal(b.a.info.function(), "test_in_func"));
|
||||
static_assert(is_equal(b.a.info.function(), "bool test_out_of_line_init::test_in_func()"));
|
||||
return true;
|
||||
}
|
||||
static_assert(test_in_func());
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -verify -DTEST=1 %s
|
||||
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -verify -DTEST=2 %s
|
||||
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -verify -DTEST=3 %s
|
||||
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -verify -DTEST=4 %s
|
||||
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -fexceptions -verify -DTEST=5 %s
|
||||
|
||||
#if TEST == 1
|
||||
auto test1a = __builtin_source_location(); // expected-error {{'std::source_location::__impl' was not found}}
|
||||
|
||||
namespace std {
|
||||
inline namespace NS {
|
||||
struct source_location;
|
||||
}
|
||||
}
|
||||
|
||||
auto test1b = __builtin_source_location(); // expected-error {{'std::source_location::__impl' was not found}}
|
||||
|
||||
namespace std {
|
||||
inline namespace NS {
|
||||
struct source_location {
|
||||
struct __impl;
|
||||
};
|
||||
}
|
||||
}
|
||||
auto test1c = __builtin_source_location(); // expected-error {{'std::source_location::__impl' was not found}}
|
||||
|
||||
#elif TEST == 2
|
||||
auto test2a = __builtin_source_location(); // expected-error {{'std::source_location::__impl' was not found}}
|
||||
|
||||
namespace std {
|
||||
inline namespace NS {
|
||||
struct source_location {
|
||||
struct __impl { int x; };
|
||||
};
|
||||
}
|
||||
}
|
||||
auto test2b = __builtin_source_location(); // expected-error {{'std::source_location::__impl' must be standard-layout and have only two 'const char *' fields '_M_file_name' and '_M_function_name', and two integral fields '_M_line' and '_M_column'}}
|
||||
|
||||
#elif TEST == 3
|
||||
namespace std {
|
||||
struct source_location {
|
||||
struct __impl {
|
||||
int other_member;
|
||||
char _M_line;
|
||||
const char *_M_file_name;
|
||||
char _M_column;
|
||||
const char *_M_function_name;
|
||||
};
|
||||
};
|
||||
}
|
||||
auto test3 = __builtin_source_location(); // expected-error {{'std::source_location::__impl' must be standard-layout and have only two 'const char *' fields '_M_file_name' and '_M_function_name', and two integral fields '_M_line' and '_M_column'}}
|
||||
|
||||
#elif TEST == 4
|
||||
namespace std {
|
||||
struct source_location {
|
||||
struct parent {};
|
||||
struct __impl : public parent {
|
||||
char _M_line;
|
||||
const char *_M_file_name;
|
||||
char _M_column;
|
||||
const char *_M_function_name;
|
||||
};
|
||||
};
|
||||
}
|
||||
auto test4 = __builtin_source_location(); // expected-error {{'std::source_location::__impl' must be standard-layout and have only two 'const char *' fields '_M_file_name' and '_M_function_name', and two integral fields '_M_line' and '_M_column'}}
|
||||
|
||||
|
||||
#elif TEST == 5
|
||||
namespace std {
|
||||
struct source_location {
|
||||
struct __impl {
|
||||
signed char _M_line; // odd integral type to choose, but ok!
|
||||
const char *_M_file_name;
|
||||
signed char _M_column;
|
||||
const char *_M_function_name;
|
||||
static int other_member; // static members are OK
|
||||
};
|
||||
using BuiltinT = decltype(__builtin_source_location()); // OK.
|
||||
};
|
||||
}
|
||||
|
||||
// Verify that the address cannot be used as a non-type template argument.
|
||||
template <auto X = __builtin_source_location()>
|
||||
auto fn1() {return X;} // expected-note {{candidate template ignored: substitution failure: non-type template argument does not refer to any declaration}}
|
||||
auto test5a = fn1<>(); // expected-error {{no matching function for call to 'fn1'}}
|
||||
|
||||
// (But using integer subobjects by value is okay.)
|
||||
template <auto X = __builtin_source_location()->_M_column>
|
||||
auto fn2() {return X;}
|
||||
auto test5b = fn2<>();
|
||||
|
||||
// While it's not semantically required, for efficiency, we ensure that two
|
||||
// source-locations with the same content will point to the same object. Given
|
||||
// the odd definition of the struct used here (using 'signed char'), any
|
||||
// line-number modulo 256 will thus have the same content, and be deduplicated.
|
||||
#line 128
|
||||
constexpr auto sl1 = __builtin_source_location();
|
||||
#line 384
|
||||
constexpr auto sl2 = __builtin_source_location();
|
||||
constexpr auto sl3 = __builtin_source_location();
|
||||
static_assert(sl1 == sl2);
|
||||
static_assert(sl1 != sl3);
|
||||
static_assert(sl1->_M_line == -128);
|
||||
|
||||
#endif
|
|
@ -6478,6 +6478,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
|
|||
case Decl::Binding:
|
||||
case Decl::MSProperty:
|
||||
case Decl::MSGuid:
|
||||
case Decl::UnnamedGlobalConstant:
|
||||
case Decl::TemplateParamObject:
|
||||
case Decl::IndirectField:
|
||||
case Decl::ObjCIvar:
|
||||
|
|
Loading…
Reference in New Issue