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**:
const char *__builtin_FUNCTION();
unsigned __builtin_LINE();
unsigned __builtin_COLUMN(); // Clang only
+ const std::source_location::__impl *__builtin_source_location();
**Example of use**:
**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
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
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
^^^^^^^^^^^^^^^^^^^^^
/// 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;
/// 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,
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,
};
/// 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) {}
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.
DEF_TRAVERSE_DECL(MSPropertyDecl, { TRY_TO(TraverseDeclaratorHelper(D)); })
DEF_TRAVERSE_DECL(MSGuidDecl, {})
+DEF_TRAVERSE_DECL(UnnamedGlobalConstantDecl, {})
DEF_TRAVERSE_DECL(TemplateParamObjectDecl, {})
/// The kind of source location builtin represented by the SourceLocExpr.
/// Ex. __builtin_LINE, __builtin_FUNCTION, ect.
- unsigned Kind : 2;
+ unsigned Kind : 3;
};
class StmtExprBitfields {
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">;
"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.
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.
/// 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;
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
/// 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.
/// 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.
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");
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)
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) {
case ExternCContext:
case Decomposition:
case MSGuid:
+ case UnnamedGlobalConstant:
case TemplateParamObject:
case UsingDirective:
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:
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);
return "__builtin_LINE";
case Column:
return "__builtin_COLUMN";
+ case SourceLocStruct:
+ return "__builtin_source_location";
}
llvm_unreachable("unexpected IdentKind!");
}
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(""));
: 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");
}
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;
}
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>())
// 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
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)) {
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);
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);
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();
// 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())
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:
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);
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);
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;
/// 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);
/// [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 ']'
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.
/// [GNU] '__builtin_FUNCTION' '(' ')'
/// [GNU] '__builtin_LINE' '(' ')'
/// [CLANG] '__builtin_COLUMN' '(' ')'
+/// [GNU] '__builtin_source_location' '(' ')'
/// [OCL] '__builtin_astype' '(' assignment-expression ',' type-name ')'
///
/// [GNU] offsetof-member-designator:
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;
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");
}
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),
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.
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");
}
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,
// -- 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();
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");
/// 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.
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);
}
case Decl::Field:
case Decl::MSProperty:
case Decl::MSGuid:
+ case Decl::UnnamedGlobalConstant:
case Decl::TemplateParamObject:
case Decl::ObjCIvar:
case Decl::ObjCAtDefsField:
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);
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();
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;
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);
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());
#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; }
+
+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 = source_location;
+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();
// 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();
}
// 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;
// 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);
// 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;
}
// 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 =
{
// 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;
}
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;
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()
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>
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();
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());
--- /dev/null
+// 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
case Decl::Binding:
case Decl::MSProperty:
case Decl::MSGuid:
+ case Decl::UnnamedGlobalConstant:
case Decl::TemplateParamObject:
case Decl::IndirectField:
case Decl::ObjCIvar: