Skip to content

Commit d614874

Browse files
committed
[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
1 parent e2485f3 commit d614874

36 files changed

+666
-198
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3377,10 +3377,9 @@ as the first argument to the intrinsic.
33773377
Source location builtins
33783378
------------------------
33793379
3380-
Clang provides experimental builtins to support C++ standard library implementation
3381-
of ``std::experimental::source_location`` as specified in http://wg21.link/N4600.
3382-
With the exception of ``__builtin_COLUMN``, these builtins are also implemented by
3383-
GCC.
3380+
Clang provides builtins to support C++ standard library implementation
3381+
of ``std::source_location`` as specified in C++20. With the exception
3382+
of ``__builtin_COLUMN``, these builtins are also implemented by GCC.
33843383
33853384
**Syntax**:
33863385
@@ -3390,6 +3389,7 @@ GCC.
33903389
const char *__builtin_FUNCTION();
33913390
unsigned __builtin_LINE();
33923391
unsigned __builtin_COLUMN(); // Clang only
3392+
const std::source_location::__impl *__builtin_source_location();
33933393
33943394
**Example of use**:
33953395
@@ -3416,9 +3416,11 @@ GCC.
34163416
34173417
**Description**:
34183418
3419-
The builtins ``__builtin_LINE``, ``__builtin_FUNCTION``, and ``__builtin_FILE`` return
3420-
the values, at the "invocation point", for ``__LINE__``, ``__FUNCTION__``, and
3421-
``__FILE__`` respectively. These builtins are constant expressions.
3419+
The builtins ``__builtin_LINE``, ``__builtin_FUNCTION``, and ``__builtin_FILE``
3420+
return the values, at the "invocation point", for ``__LINE__``,
3421+
``__FUNCTION__``, and ``__FILE__`` respectively. ``__builtin_COLUMN`` similarly
3422+
returns the column, though there is no corresponding macro. These builtins are
3423+
constant expressions.
34223424
34233425
When the builtins appear as part of a default function argument the invocation
34243426
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.
34293431
When the invocation point of ``__builtin_FUNCTION`` is not a function scope the
34303432
empty string is returned.
34313433
3434+
The builtin ``__builtin_source_location`` returns a pointer to constant static
3435+
data of type ``std::source_location::__impl``. This type must have already been
3436+
defined, and must contain exactly four fields: ``const char *_M_file_name``,
3437+
``const char *_M_function_name``, ``<any-integral-type> _M_line``, and
3438+
``<any-integral-type> _M_column``. The fields will be populated in the same
3439+
manner as the above four builtins, except that ``_M_function_name`` is populated
3440+
with ``__PRETTY_FUNCTION__`` rather than ``__FUNCTION__``.
3441+
3442+
34323443
Alignment builtins
34333444
------------------
34343445
Clang provides builtins to support checking and adjusting alignment of

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ C++20 Feature Support
193193
it is called through a template instantiation. This fixes
194194
`Issue 54578 <https://github.com/llvm/llvm-project/issues/54578>`_.
195195

196+
- Implemented `__builtin_source_location()` which enables library support for std::source_location.
197+
196198
C++2b Feature Support
197199
^^^^^^^^^^^^^^^^^^^^^
198200

clang/include/clang/AST/ASTContext.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
314314
/// Mapping from GUIDs to the corresponding MSGuidDecl.
315315
mutable llvm::FoldingSet<MSGuidDecl> MSGuidDecls;
316316

317+
/// Mapping from APValues to the corresponding UnnamedGlobalConstantDecl.
318+
mutable llvm::FoldingSet<UnnamedGlobalConstantDecl>
319+
UnnamedGlobalConstantDecls;
320+
317321
/// Mapping from APValues to the corresponding TemplateParamObjects.
318322
mutable llvm::FoldingSet<TemplateParamObjectDecl> TemplateParamObjectDecls;
319323

@@ -3064,6 +3068,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
30643068
/// GUID value.
30653069
MSGuidDecl *getMSGuidDecl(MSGuidDeclParts Parts) const;
30663070

3071+
/// Return a declaration for a uniquified anonymous global constant
3072+
/// corresponding to a given APValue.
3073+
UnnamedGlobalConstantDecl *
3074+
getUnnamedGlobalConstantDecl(QualType Ty, const APValue &Value) const;
3075+
30673076
/// Return the template parameter object of the given type with the given
30683077
/// value.
30693078
TemplateParamObjectDecl *getTemplateParamObjectDecl(QualType T,

clang/include/clang/AST/DeclCXX.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4206,6 +4206,53 @@ class MSGuidDecl : public ValueDecl,
42064206
static bool classofKind(Kind K) { return K == Decl::MSGuid; }
42074207
};
42084208

4209+
/// An artificial decl, representing a global anonymous constant value which is
4210+
/// uniquified by value within a translation unit.
4211+
///
4212+
/// These is currently only used to back the LValue returned by
4213+
/// __builtin_source_location, but could potentially be used for other similar
4214+
/// situations in the future.
4215+
class UnnamedGlobalConstantDecl : public ValueDecl,
4216+
public Mergeable<UnnamedGlobalConstantDecl>,
4217+
public llvm::FoldingSetNode {
4218+
4219+
// The constant value of this global.
4220+
APValue Value;
4221+
4222+
void anchor() override;
4223+
4224+
UnnamedGlobalConstantDecl(DeclContext *DC, QualType T, const APValue &Val);
4225+
4226+
static UnnamedGlobalConstantDecl *Create(const ASTContext &C, QualType T,
4227+
const APValue &APVal);
4228+
static UnnamedGlobalConstantDecl *CreateDeserialized(ASTContext &C,
4229+
unsigned ID);
4230+
4231+
// Only ASTContext::getUnnamedGlobalConstantDecl and deserialization create
4232+
// these.
4233+
friend class ASTContext;
4234+
friend class ASTReader;
4235+
friend class ASTDeclReader;
4236+
4237+
public:
4238+
/// Print this in a human-readable format.
4239+
void printName(llvm::raw_ostream &OS) const override;
4240+
4241+
const APValue &getValue() const { return Value; }
4242+
4243+
static void Profile(llvm::FoldingSetNodeID &ID, QualType Ty,
4244+
const APValue &APVal) {
4245+
Ty.Profile(ID);
4246+
APVal.Profile(ID);
4247+
}
4248+
void Profile(llvm::FoldingSetNodeID &ID) {
4249+
Profile(ID, getType(), getValue());
4250+
}
4251+
4252+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
4253+
static bool classofKind(Kind K) { return K == Decl::UnnamedGlobalConstant; }
4254+
};
4255+
42094256
/// Insertion operator for diagnostics. This allows sending an AccessSpecifier
42104257
/// into a diagnostic with <<.
42114258
const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,

clang/include/clang/AST/Expr.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4680,16 +4680,17 @@ class VAArgExpr : public Expr {
46804680
};
46814681

46824682
/// Represents a function call to one of __builtin_LINE(), __builtin_COLUMN(),
4683-
/// __builtin_FUNCTION(), or __builtin_FILE().
4683+
/// __builtin_FUNCTION(), __builtin_FILE(), or __builtin_source_location().
46844684
class SourceLocExpr final : public Expr {
46854685
SourceLocation BuiltinLoc, RParenLoc;
46864686
DeclContext *ParentContext;
46874687

46884688
public:
4689-
enum IdentKind { Function, File, Line, Column };
4689+
enum IdentKind { Function, File, Line, Column, SourceLocStruct };
46904690

4691-
SourceLocExpr(const ASTContext &Ctx, IdentKind Type, SourceLocation BLoc,
4692-
SourceLocation RParenLoc, DeclContext *Context);
4691+
SourceLocExpr(const ASTContext &Ctx, IdentKind Type, QualType ResultTy,
4692+
SourceLocation BLoc, SourceLocation RParenLoc,
4693+
DeclContext *Context);
46934694

46944695
/// Build an empty call expression.
46954696
explicit SourceLocExpr(EmptyShell Empty) : Expr(SourceLocExprClass, Empty) {}
@@ -4706,18 +4707,18 @@ class SourceLocExpr final : public Expr {
47064707
return static_cast<IdentKind>(SourceLocExprBits.Kind);
47074708
}
47084709

4709-
bool isStringType() const {
4710+
bool isIntType() const {
47104711
switch (getIdentKind()) {
47114712
case File:
47124713
case Function:
4713-
return true;
4714+
case SourceLocStruct:
4715+
return false;
47144716
case Line:
47154717
case Column:
4716-
return false;
4718+
return true;
47174719
}
47184720
llvm_unreachable("unknown source location expression kind");
47194721
}
4720-
bool isIntType() const LLVM_READONLY { return !isStringType(); }
47214722

47224723
/// If the SourceLocExpr has been resolved return the subexpression
47234724
/// representing the resolved value. Otherwise return null.

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,6 +2039,7 @@ DEF_TRAVERSE_DECL(BindingDecl, {
20392039
DEF_TRAVERSE_DECL(MSPropertyDecl, { TRY_TO(TraverseDeclaratorHelper(D)); })
20402040

20412041
DEF_TRAVERSE_DECL(MSGuidDecl, {})
2042+
DEF_TRAVERSE_DECL(UnnamedGlobalConstantDecl, {})
20422043

20432044
DEF_TRAVERSE_DECL(TemplateParamObjectDecl, {})
20442045

clang/include/clang/AST/Stmt.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ class alignas(void *) Stmt {
595595

596596
/// The kind of source location builtin represented by the SourceLocExpr.
597597
/// Ex. __builtin_LINE, __builtin_FUNCTION, ect.
598-
unsigned Kind : 2;
598+
unsigned Kind : 3;
599599
};
600600

601601
class StmtExprBitfields {

clang/include/clang/Basic/DeclNodes.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def Named : DeclNode<Decl, "named declarations", 1>;
4141
def OMPDeclareReduction : DeclNode<Value>, DeclContext;
4242
def OMPDeclareMapper : DeclNode<Value>, DeclContext;
4343
def MSGuid : DeclNode<Value>;
44+
def UnnamedGlobalConstant : DeclNode<Value>;
4445
def TemplateParamObject : DeclNode<Value>;
4546
def Declarator : DeclNode<Value, "declarators", 1>;
4647
def Field : DeclNode<Declarator, "non-static data members">;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11556,4 +11556,9 @@ def err_riscv_builtin_requires_extension : Error<
1155611556
"builtin requires at least one of the following extensions support to be enabled : %0">;
1155711557
def err_riscv_builtin_invalid_lmul : Error<
1155811558
"LMUL argument must be in the range [0,3] or [5,7]">;
11559+
11560+
def err_std_source_location_impl_not_found : Error<
11561+
"'std::source_location::__impl' was not found; it must be defined before '__builtin_source_location' is called">;
11562+
def err_std_source_location_impl_malformed : Error<
11563+
"'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'">;
1155911564
} // end of sema component.

clang/include/clang/Basic/TokenKinds.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ KEYWORD(__builtin_FILE , KEYALL)
432432
KEYWORD(__builtin_FUNCTION , KEYALL)
433433
KEYWORD(__builtin_LINE , KEYALL)
434434
KEYWORD(__builtin_COLUMN , KEYALL)
435+
KEYWORD(__builtin_source_location , KEYCXX)
435436

436437
// __builtin_types_compatible_p is a GNU C extension that we handle like a C++
437438
// type trait.

clang/include/clang/Sema/Sema.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,10 @@ class Sema final {
11441144
/// The MSVC "_GUID" struct, which is defined in MSVC header files.
11451145
RecordDecl *MSVCGuidDecl;
11461146

1147+
/// The C++ "std::source_location::__impl" struct, defined in
1148+
/// \<source_location>.
1149+
RecordDecl *StdSourceLocationImplDecl;
1150+
11471151
/// Caches identifiers/selectors for NSFoundation APIs.
11481152
std::unique_ptr<NSAPI> NSAPIObj;
11491153

@@ -5684,14 +5688,15 @@ class Sema final {
56845688
TypeSourceInfo *TInfo, SourceLocation RPLoc);
56855689

56865690
// __builtin_LINE(), __builtin_FUNCTION(), __builtin_FILE(),
5687-
// __builtin_COLUMN()
5691+
// __builtin_COLUMN(), __builtin_source_location()
56885692
ExprResult ActOnSourceLocExpr(SourceLocExpr::IdentKind Kind,
56895693
SourceLocation BuiltinLoc,
56905694
SourceLocation RPLoc);
56915695

56925696
// Build a potentially resolved SourceLocExpr.
56935697
ExprResult BuildSourceLocExpr(SourceLocExpr::IdentKind Kind,
5694-
SourceLocation BuiltinLoc, SourceLocation RPLoc,
5698+
QualType ResultTy, SourceLocation BuiltinLoc,
5699+
SourceLocation RPLoc,
56955700
DeclContext *ParentContext);
56965701

56975702
// __null

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ namespace serialization {
4141
/// Version 4 of AST files also requires that the version control branch and
4242
/// revision match exactly, since there is no backward compatibility of
4343
/// AST files at this time.
44-
const unsigned VERSION_MAJOR = 16;
44+
const unsigned VERSION_MAJOR = 17;
4545

4646
/// AST file minor version number supported by this version of
4747
/// Clang.
@@ -1504,7 +1504,10 @@ enum DeclCode {
15041504
/// An OMPDeclareReductionDecl record.
15051505
DECL_OMP_DECLARE_REDUCTION,
15061506

1507-
DECL_LAST = DECL_OMP_DECLARE_REDUCTION
1507+
/// A UnnamedGlobalConstantDecl record.
1508+
DECL_UNNAMED_GLOBAL_CONSTANT,
1509+
1510+
DECL_LAST = DECL_UNNAMED_GLOBAL_CONSTANT
15081511
};
15091512

15101513
/// Record codes for each kind of statement or expression.

clang/lib/AST/ASTContext.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11875,6 +11875,23 @@ ASTContext::getMSGuidDecl(MSGuidDecl::Parts Parts) const {
1187511875
return New;
1187611876
}
1187711877

11878+
UnnamedGlobalConstantDecl *
11879+
ASTContext::getUnnamedGlobalConstantDecl(QualType Ty,
11880+
const APValue &APVal) const {
11881+
llvm::FoldingSetNodeID ID;
11882+
UnnamedGlobalConstantDecl::Profile(ID, Ty, APVal);
11883+
11884+
void *InsertPos;
11885+
if (UnnamedGlobalConstantDecl *Existing =
11886+
UnnamedGlobalConstantDecls.FindNodeOrInsertPos(ID, InsertPos))
11887+
return Existing;
11888+
11889+
UnnamedGlobalConstantDecl *New =
11890+
UnnamedGlobalConstantDecl::Create(*this, Ty, APVal);
11891+
UnnamedGlobalConstantDecls.InsertNode(New, InsertPos);
11892+
return New;
11893+
}
11894+
1187811895
TemplateParamObjectDecl *
1187911896
ASTContext::getTemplateParamObjectDecl(QualType T, const APValue &V) const {
1188011897
assert(T->isRecordType() && "template param object of unexpected type");

clang/lib/AST/ASTImporter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6669,6 +6669,7 @@ ExpectedStmt ASTNodeImporter::VisitExpr(Expr *E) {
66696669

66706670
ExpectedStmt ASTNodeImporter::VisitSourceLocExpr(SourceLocExpr *E) {
66716671
Error Err = Error::success();
6672+
auto ToType = importChecked(Err, E->getType());
66726673
auto BLoc = importChecked(Err, E->getBeginLoc());
66736674
auto RParenLoc = importChecked(Err, E->getEndLoc());
66746675
if (Err)
@@ -6678,8 +6679,8 @@ ExpectedStmt ASTNodeImporter::VisitSourceLocExpr(SourceLocExpr *E) {
66786679
return ParentContextOrErr.takeError();
66796680

66806681
return new (Importer.getToContext())
6681-
SourceLocExpr(Importer.getToContext(), E->getIdentKind(), BLoc, RParenLoc,
6682-
*ParentContextOrErr);
6682+
SourceLocExpr(Importer.getToContext(), E->getIdentKind(), ToType, BLoc,
6683+
RParenLoc, *ParentContextOrErr);
66836684
}
66846685

66856686
ExpectedStmt ASTNodeImporter::VisitVAArgExpr(VAArgExpr *E) {

clang/lib/AST/DeclBase.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
838838
case ExternCContext:
839839
case Decomposition:
840840
case MSGuid:
841+
case UnnamedGlobalConstant:
841842
case TemplateParamObject:
842843

843844
case UsingDirective:

clang/lib/AST/DeclCXX.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3363,6 +3363,31 @@ APValue &MSGuidDecl::getAsAPValue() const {
33633363
return APVal;
33643364
}
33653365

3366+
void UnnamedGlobalConstantDecl::anchor() {}
3367+
3368+
UnnamedGlobalConstantDecl::UnnamedGlobalConstantDecl(DeclContext *DC,
3369+
QualType Ty,
3370+
const APValue &Value)
3371+
: ValueDecl(Decl::UnnamedGlobalConstant, DC, SourceLocation(),
3372+
DeclarationName(), Ty),
3373+
Value(Value) {}
3374+
3375+
UnnamedGlobalConstantDecl *
3376+
UnnamedGlobalConstantDecl::Create(const ASTContext &C, QualType T,
3377+
const APValue &Value) {
3378+
DeclContext *DC = C.getTranslationUnitDecl();
3379+
return new (C, DC) UnnamedGlobalConstantDecl(DC, T, Value);
3380+
}
3381+
3382+
UnnamedGlobalConstantDecl *
3383+
UnnamedGlobalConstantDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
3384+
return new (C, ID) UnnamedGlobalConstantDecl(nullptr, QualType(), APValue());
3385+
}
3386+
3387+
void UnnamedGlobalConstantDecl::printName(llvm::raw_ostream &OS) const {
3388+
OS << "unnamed-global-constant";
3389+
}
3390+
33663391
static const char *getAccessName(AccessSpecifier AS) {
33673392
switch (AS) {
33683393
case AS_none:

0 commit comments

Comments
 (0)