Add new 'preferred_name' attribute.
This attribute permits a typedef to be associated with a class template specialization as a preferred way of naming that class template specialization. This permits us to specify that (for example) the preferred way to express 'std::basic_string<char>' is as 'std::string'. The attribute is applied to the various class templates in libc++ that have corresponding well-known typedef names. Differential Revision: https://reviews.llvm.org/D91311
This commit is contained in:
parent
2ac4d0f45a
commit
98f76adf4e
|
@ -126,6 +126,9 @@ def FunctionTmpl
|
||||||
FunctionDecl::TK_FunctionTemplate}],
|
FunctionDecl::TK_FunctionTemplate}],
|
||||||
"function templates">;
|
"function templates">;
|
||||||
|
|
||||||
|
def ClassTmpl : SubsetSubject<CXXRecord, [{S->getDescribedClassTemplate()}],
|
||||||
|
"class templates">;
|
||||||
|
|
||||||
// FIXME: this hack is needed because DeclNodes.td defines the base Decl node
|
// FIXME: this hack is needed because DeclNodes.td defines the base Decl node
|
||||||
// type to be a class, not a definition. This makes it impossible to create an
|
// type to be a class, not a definition. This makes it impossible to create an
|
||||||
// attribute subject which accepts a Decl. Normally, this is not a problem,
|
// attribute subject which accepts a Decl. Normally, this is not a problem,
|
||||||
|
@ -2376,6 +2379,16 @@ def Pascal : DeclOrTypeAttr {
|
||||||
let Documentation = [Undocumented];
|
let Documentation = [Undocumented];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def PreferredName : InheritableAttr {
|
||||||
|
let Spellings = [Clang<"preferred_name", /*AllowInC*/0>];
|
||||||
|
let Subjects = SubjectList<[ClassTmpl]>;
|
||||||
|
let Args = [TypeArgument<"TypedefType">];
|
||||||
|
let Documentation = [PreferredNameDocs];
|
||||||
|
let InheritEvenIfAlreadyPresent = 1;
|
||||||
|
let MeaningfulToClassTemplateDefinition = 1;
|
||||||
|
let TemplateDependent = 1;
|
||||||
|
}
|
||||||
|
|
||||||
def PreserveMost : DeclOrTypeAttr {
|
def PreserveMost : DeclOrTypeAttr {
|
||||||
let Spellings = [Clang<"preserve_most">];
|
let Spellings = [Clang<"preserve_most">];
|
||||||
let Documentation = [PreserveMostDocs];
|
let Documentation = [PreserveMostDocs];
|
||||||
|
|
|
@ -4417,6 +4417,30 @@ the old mangled name and the new code will use the new mangled name with tags.
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def PreferredNameDocs : Documentation {
|
||||||
|
let Category = DocCatDecl;
|
||||||
|
let Content = [{
|
||||||
|
The ``preferred_name`` attribute can be applied to a class template, and
|
||||||
|
specifies a preferred way of naming a specialization of the template. The
|
||||||
|
preferred name will be used whenever the corresponding template specialization
|
||||||
|
would otherwise be printed in a diagnostic or similar context.
|
||||||
|
|
||||||
|
The preferred name must be a typedef or type alias declaration that refers to a
|
||||||
|
specialization of the class template (not including any type qualifiers). In
|
||||||
|
general this requires the template to be declared at least twice. For example:
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
template<typename T> struct basic_string;
|
||||||
|
using string = basic_string<char>;
|
||||||
|
using wstring = basic_string<wchar_t>;
|
||||||
|
template<typename T> struct [[clang::preferred_name(string),
|
||||||
|
clang::preferred_name(wstring)]] basic_string {
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
def PreserveMostDocs : Documentation {
|
def PreserveMostDocs : Documentation {
|
||||||
let Category = DocCatCallingConvs;
|
let Category = DocCatCallingConvs;
|
||||||
let Content = [{
|
let Content = [{
|
||||||
|
|
|
@ -3941,6 +3941,9 @@ def note_protocol_decl : Note<
|
||||||
"protocol is declared here">;
|
"protocol is declared here">;
|
||||||
def note_protocol_decl_undefined : Note<
|
def note_protocol_decl_undefined : Note<
|
||||||
"protocol %0 has no definition">;
|
"protocol %0 has no definition">;
|
||||||
|
def err_attribute_preferred_name_arg_invalid : Error<
|
||||||
|
"argument %0 to 'preferred_name' attribute is not a typedef for "
|
||||||
|
"a specialization of %1">;
|
||||||
|
|
||||||
// objc_designated_initializer attribute diagnostics.
|
// objc_designated_initializer attribute diagnostics.
|
||||||
def warn_objc_designated_init_missing_super_call : Warning<
|
def warn_objc_designated_init_missing_super_call : Warning<
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "clang/AST/PrettyPrinter.h"
|
|
||||||
#include "clang/AST/ASTContext.h"
|
#include "clang/AST/ASTContext.h"
|
||||||
|
#include "clang/AST/Attr.h"
|
||||||
#include "clang/AST/Decl.h"
|
#include "clang/AST/Decl.h"
|
||||||
#include "clang/AST/DeclBase.h"
|
#include "clang/AST/DeclBase.h"
|
||||||
#include "clang/AST/DeclCXX.h"
|
#include "clang/AST/DeclCXX.h"
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
#include "clang/AST/DeclTemplate.h"
|
#include "clang/AST/DeclTemplate.h"
|
||||||
#include "clang/AST/Expr.h"
|
#include "clang/AST/Expr.h"
|
||||||
#include "clang/AST/NestedNameSpecifier.h"
|
#include "clang/AST/NestedNameSpecifier.h"
|
||||||
|
#include "clang/AST/PrettyPrinter.h"
|
||||||
#include "clang/AST/TemplateBase.h"
|
#include "clang/AST/TemplateBase.h"
|
||||||
#include "clang/AST/TemplateName.h"
|
#include "clang/AST/TemplateName.h"
|
||||||
#include "clang/AST/Type.h"
|
#include "clang/AST/Type.h"
|
||||||
|
@ -1348,6 +1349,14 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) {
|
void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) {
|
||||||
|
// Print the preferred name if we have one for this type.
|
||||||
|
for (const auto *PNA : T->getDecl()->specific_attrs<PreferredNameAttr>()) {
|
||||||
|
if (declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(),
|
||||||
|
T->getDecl()))
|
||||||
|
return printTypeSpec(
|
||||||
|
PNA->getTypedefType()->castAs<TypedefType>()->getDecl(), OS);
|
||||||
|
}
|
||||||
|
|
||||||
printTag(T->getDecl(), OS);
|
printTag(T->getDecl(), OS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1380,6 +1380,43 @@ static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||||
S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL;
|
S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handlePreferredName(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||||
|
auto *RD = cast<CXXRecordDecl>(D);
|
||||||
|
ClassTemplateDecl *CTD = RD->getDescribedClassTemplate();
|
||||||
|
assert(CTD && "attribute does not appertain to this declaration");
|
||||||
|
|
||||||
|
ParsedType PT = AL.getTypeArg();
|
||||||
|
TypeSourceInfo *TSI = nullptr;
|
||||||
|
QualType T = S.GetTypeFromParser(PT, &TSI);
|
||||||
|
if (!TSI)
|
||||||
|
TSI = S.Context.getTrivialTypeSourceInfo(T, AL.getLoc());
|
||||||
|
|
||||||
|
if (!T.hasQualifiers() && T->getAs<TypedefType>()) {
|
||||||
|
// Find the template name, if this type names a template specialization.
|
||||||
|
const TemplateDecl *Template = nullptr;
|
||||||
|
if (const auto *CTSD = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
|
||||||
|
T->getAsCXXRecordDecl())) {
|
||||||
|
Template = CTSD->getSpecializedTemplate();
|
||||||
|
} else if (const auto *TST = T->getAs<TemplateSpecializationType>()) {
|
||||||
|
while (TST && TST->isTypeAlias())
|
||||||
|
TST = TST->getAliasedType()->getAs<TemplateSpecializationType>();
|
||||||
|
if (TST)
|
||||||
|
Template = TST->getTemplateName().getAsTemplateDecl();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Template && declaresSameEntity(Template, CTD)) {
|
||||||
|
D->addAttr(::new (S.Context) PreferredNameAttr(S.Context, AL, TSI));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
S.Diag(AL.getLoc(), diag::err_attribute_preferred_name_arg_invalid)
|
||||||
|
<< T << CTD;
|
||||||
|
if (const auto *TT = T->getAs<TypedefType>())
|
||||||
|
S.Diag(TT->getDecl()->getLocation(), diag::note_entity_declared_at)
|
||||||
|
<< TT->getDecl();
|
||||||
|
}
|
||||||
|
|
||||||
static bool checkIBOutletCommon(Sema &S, Decl *D, const ParsedAttr &AL) {
|
static bool checkIBOutletCommon(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||||
// The IBOutlet/IBOutletCollection attributes only apply to instance
|
// The IBOutlet/IBOutletCollection attributes only apply to instance
|
||||||
// variables or properties of Objective-C classes. The outlet must also
|
// variables or properties of Objective-C classes. The outlet must also
|
||||||
|
@ -7728,6 +7765,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
||||||
case ParsedAttr::AT_Packed:
|
case ParsedAttr::AT_Packed:
|
||||||
handlePackedAttr(S, D, AL);
|
handlePackedAttr(S, D, AL);
|
||||||
break;
|
break;
|
||||||
|
case ParsedAttr::AT_PreferredName:
|
||||||
|
handlePreferredName(S, D, AL);
|
||||||
|
break;
|
||||||
case ParsedAttr::AT_Section:
|
case ParsedAttr::AT_Section:
|
||||||
handleSectionAttr(S, D, AL);
|
handleSectionAttr(S, D, AL);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -3792,11 +3792,15 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
|
||||||
Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
|
Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Decl->getSpecializationKind() == TSK_Undeclared) {
|
if (Decl->getSpecializationKind() == TSK_Undeclared &&
|
||||||
MultiLevelTemplateArgumentList TemplateArgLists;
|
ClassTemplate->getTemplatedDecl()->hasAttrs()) {
|
||||||
TemplateArgLists.addOuterTemplateArguments(Converted);
|
InstantiatingTemplate Inst(*this, TemplateLoc, Decl);
|
||||||
InstantiateAttrsForDecl(TemplateArgLists, ClassTemplate->getTemplatedDecl(),
|
if (!Inst.isInvalid()) {
|
||||||
Decl);
|
MultiLevelTemplateArgumentList TemplateArgLists;
|
||||||
|
TemplateArgLists.addOuterTemplateArguments(Converted);
|
||||||
|
InstantiateAttrsForDecl(TemplateArgLists,
|
||||||
|
ClassTemplate->getTemplatedDecl(), Decl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diagnose uses of this specialization.
|
// Diagnose uses of this specialization.
|
||||||
|
|
|
@ -548,12 +548,40 @@ static void instantiateDependentAMDGPUWavesPerEUAttr(
|
||||||
S.addAMDGPUWavesPerEUAttr(New, Attr, MinExpr, MaxExpr);
|
S.addAMDGPUWavesPerEUAttr(New, Attr, MinExpr, MaxExpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determine whether the attribute A might be relevent to the declaration D.
|
||||||
|
/// If not, we can skip instantiating it. The attribute may or may not have
|
||||||
|
/// been instantiated yet.
|
||||||
|
static bool isRelevantAttr(Sema &S, const Decl *D, const Attr *A) {
|
||||||
|
// 'preferred_name' is only relevant to the matching specialization of the
|
||||||
|
// template.
|
||||||
|
if (const auto *PNA = dyn_cast<PreferredNameAttr>(A)) {
|
||||||
|
QualType T = PNA->getTypedefType();
|
||||||
|
const auto *RD = cast<CXXRecordDecl>(D);
|
||||||
|
if (!T->isDependentType() && !RD->isDependentContext() &&
|
||||||
|
!declaresSameEntity(T->getAsCXXRecordDecl(), RD))
|
||||||
|
return false;
|
||||||
|
for (const auto *ExistingPNA : D->specific_attrs<PreferredNameAttr>())
|
||||||
|
if (S.Context.hasSameType(ExistingPNA->getTypedefType(),
|
||||||
|
PNA->getTypedefType()))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Sema::InstantiateAttrsForDecl(
|
void Sema::InstantiateAttrsForDecl(
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl,
|
const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl,
|
||||||
Decl *New, LateInstantiatedAttrVec *LateAttrs,
|
Decl *New, LateInstantiatedAttrVec *LateAttrs,
|
||||||
LocalInstantiationScope *OuterMostScope) {
|
LocalInstantiationScope *OuterMostScope) {
|
||||||
if (NamedDecl *ND = dyn_cast<NamedDecl>(New)) {
|
if (NamedDecl *ND = dyn_cast<NamedDecl>(New)) {
|
||||||
|
// FIXME: This function is called multiple times for the same template
|
||||||
|
// specialization. We should only instantiate attributes that were added
|
||||||
|
// since the previous instantiation.
|
||||||
for (const auto *TmplAttr : Tmpl->attrs()) {
|
for (const auto *TmplAttr : Tmpl->attrs()) {
|
||||||
|
if (!isRelevantAttr(*this, New, TmplAttr))
|
||||||
|
continue;
|
||||||
|
|
||||||
// FIXME: If any of the special case versions from InstantiateAttrs become
|
// FIXME: If any of the special case versions from InstantiateAttrs become
|
||||||
// applicable to template declaration, we'll need to add them here.
|
// applicable to template declaration, we'll need to add them here.
|
||||||
CXXThisScopeRAII ThisScope(
|
CXXThisScopeRAII ThisScope(
|
||||||
|
@ -562,7 +590,7 @@ void Sema::InstantiateAttrsForDecl(
|
||||||
|
|
||||||
Attr *NewAttr = sema::instantiateTemplateAttributeForDecl(
|
Attr *NewAttr = sema::instantiateTemplateAttributeForDecl(
|
||||||
TmplAttr, Context, *this, TemplateArgs);
|
TmplAttr, Context, *this, TemplateArgs);
|
||||||
if (NewAttr)
|
if (NewAttr && isRelevantAttr(*this, New, NewAttr))
|
||||||
New->addAttr(NewAttr);
|
New->addAttr(NewAttr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -587,6 +615,9 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||||
LateInstantiatedAttrVec *LateAttrs,
|
LateInstantiatedAttrVec *LateAttrs,
|
||||||
LocalInstantiationScope *OuterMostScope) {
|
LocalInstantiationScope *OuterMostScope) {
|
||||||
for (const auto *TmplAttr : Tmpl->attrs()) {
|
for (const auto *TmplAttr : Tmpl->attrs()) {
|
||||||
|
if (!isRelevantAttr(*this, New, TmplAttr))
|
||||||
|
continue;
|
||||||
|
|
||||||
// FIXME: This should be generalized to more than just the AlignedAttr.
|
// FIXME: This should be generalized to more than just the AlignedAttr.
|
||||||
const AlignedAttr *Aligned = dyn_cast<AlignedAttr>(TmplAttr);
|
const AlignedAttr *Aligned = dyn_cast<AlignedAttr>(TmplAttr);
|
||||||
if (Aligned && Aligned->isAlignmentDependent()) {
|
if (Aligned && Aligned->isAlignmentDependent()) {
|
||||||
|
@ -709,7 +740,7 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||||
|
|
||||||
Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context,
|
Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context,
|
||||||
*this, TemplateArgs);
|
*this, TemplateArgs);
|
||||||
if (NewAttr)
|
if (NewAttr && isRelevantAttr(*this, New, TmplAttr))
|
||||||
New->addAttr(NewAttr);
|
New->addAttr(NewAttr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,3 +63,67 @@ namespace PR9049 {
|
||||||
// CHECK: AnnotateAttr {{.*}} "ANNOTATE_BAR"
|
// CHECK: AnnotateAttr {{.*}} "ANNOTATE_BAR"
|
||||||
template<typename T> [[clang::annotate("ANNOTATE_FOO"), clang::annotate("ANNOTATE_BAR")]] void HasAnnotations();
|
template<typename T> [[clang::annotate("ANNOTATE_FOO"), clang::annotate("ANNOTATE_BAR")]] void HasAnnotations();
|
||||||
void UseAnnotations() { HasAnnotations<int>(); }
|
void UseAnnotations() { HasAnnotations<int>(); }
|
||||||
|
|
||||||
|
namespace preferred_name {
|
||||||
|
int x [[clang::preferred_name("frank")]]; // expected-error {{expected a type}}
|
||||||
|
int y [[clang::preferred_name(int)]]; // expected-warning {{'preferred_name' attribute only applies to class templates}}
|
||||||
|
struct [[clang::preferred_name(int)]] A; // expected-warning {{'preferred_name' attribute only applies to class templates}}
|
||||||
|
template<typename T> struct [[clang::preferred_name(int)]] B; // expected-error {{argument 'int' to 'preferred_name' attribute is not a typedef for a specialization of 'B'}}
|
||||||
|
template<typename T> struct C;
|
||||||
|
using X = C<int>; // expected-note {{'X' declared here}}
|
||||||
|
typedef C<float> Y;
|
||||||
|
using Z = const C<double>; // expected-note {{'Z' declared here}}
|
||||||
|
template<typename T> struct [[clang::preferred_name(C<int>)]] C; // expected-error {{argument 'C<int>' to 'preferred_name' attribute is not a typedef for a specialization of 'C'}}
|
||||||
|
template<typename T> struct [[clang::preferred_name(X), clang::preferred_name(Y)]] C;
|
||||||
|
template<typename T> struct [[clang::preferred_name(const X)]] C; // expected-error {{argument 'const preferred_name::X'}}
|
||||||
|
template<typename T> struct [[clang::preferred_name(Z)]] C; // expected-error {{argument 'preferred_name::Z' (aka 'const C<double>')}}
|
||||||
|
template<typename T> struct C {};
|
||||||
|
|
||||||
|
// CHECK: ClassTemplateDecl {{.*}} <line:[[@LINE-10]]:{{.*}} C
|
||||||
|
// CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition
|
||||||
|
// CHECK: TemplateArgument type 'int'
|
||||||
|
// CHECK-NOT: PreferredNameAttr
|
||||||
|
// CHECK: PreferredNameAttr {{.*}} preferred_name::X
|
||||||
|
// CHECK-NOT: PreferredNameAttr
|
||||||
|
// CHECK: CXXRecordDecl
|
||||||
|
// CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition
|
||||||
|
// CHECK: TemplateArgument type 'float'
|
||||||
|
// CHECK-NOT: PreferredNameAttr
|
||||||
|
// CHECK: PreferredNameAttr {{.*}} preferred_name::Y
|
||||||
|
// CHECK-NOT: PreferredNameAttr
|
||||||
|
// CHECK: CXXRecordDecl
|
||||||
|
// CHECK: ClassTemplateSpecializationDecl {{.*}} struct C definition
|
||||||
|
// CHECK: TemplateArgument type 'double'
|
||||||
|
// CHECK-NOT: PreferredNameAttr
|
||||||
|
// CHECK: CXXRecordDecl
|
||||||
|
|
||||||
|
// Check this doesn't cause us to instantiate the same attribute multiple times.
|
||||||
|
C<float> *cf1;
|
||||||
|
C<float> *cf2;
|
||||||
|
|
||||||
|
void f(C<int> a, C<float> b, C<double> c) {
|
||||||
|
auto p = a;
|
||||||
|
auto q = b;
|
||||||
|
auto r = c;
|
||||||
|
p.f(); // expected-error {{no member named 'f' in 'preferred_name::X'}}
|
||||||
|
q.f(); // expected-error {{no member named 'f' in 'preferred_name::Y'}}
|
||||||
|
r.f(); // expected-error {{no member named 'f' in 'preferred_name::C<double>'}}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> struct D;
|
||||||
|
using DInt = D<int>;
|
||||||
|
template<typename T> struct __attribute__((__preferred_name__(DInt))) D {};
|
||||||
|
template struct D<int>;
|
||||||
|
int use_dint = D<int>().get(); // expected-error {{no member named 'get' in 'preferred_name::DInt'}}
|
||||||
|
|
||||||
|
template<typename T> struct MemberTemplate {
|
||||||
|
template<typename U> struct Iter;
|
||||||
|
using iterator = Iter<T>;
|
||||||
|
using const_iterator = Iter<const T>;
|
||||||
|
template<typename U>
|
||||||
|
struct [[clang::preferred_name(iterator),
|
||||||
|
clang::preferred_name(const_iterator)]] Iter {};
|
||||||
|
};
|
||||||
|
auto it = MemberTemplate<int>::Iter<const int>();
|
||||||
|
int n = it; // expected-error {{no viable conversion from 'preferred_name::MemberTemplate<int>::const_iterator' to 'int'}}
|
||||||
|
}
|
||||||
|
|
|
@ -1149,8 +1149,9 @@ namespace {
|
||||||
<< "Unevaluated(S, Sema::ExpressionEvaluationContext::Unevaluated);\n";
|
<< "Unevaluated(S, Sema::ExpressionEvaluationContext::Unevaluated);\n";
|
||||||
OS << " ExprResult " << "Result = S.SubstExpr("
|
OS << " ExprResult " << "Result = S.SubstExpr("
|
||||||
<< "A->get" << getUpperName() << "(), TemplateArgs);\n";
|
<< "A->get" << getUpperName() << "(), TemplateArgs);\n";
|
||||||
OS << " tempInst" << getUpperName() << " = "
|
OS << " if (Result.isInvalid())\n";
|
||||||
<< "Result.getAs<Expr>();\n";
|
OS << " return nullptr;\n";
|
||||||
|
OS << " tempInst" << getUpperName() << " = Result.get();\n";
|
||||||
OS << " }\n";
|
OS << " }\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1202,7 +1203,9 @@ namespace {
|
||||||
<< "_end();\n";
|
<< "_end();\n";
|
||||||
OS << " for (; I != E; ++I, ++TI) {\n";
|
OS << " for (; I != E; ++I, ++TI) {\n";
|
||||||
OS << " ExprResult Result = S.SubstExpr(*I, TemplateArgs);\n";
|
OS << " ExprResult Result = S.SubstExpr(*I, TemplateArgs);\n";
|
||||||
OS << " *TI = Result.getAs<Expr>();\n";
|
OS << " if (Result.isInvalid())\n";
|
||||||
|
OS << " return nullptr;\n";
|
||||||
|
OS << " *TI = Result.get();\n";
|
||||||
OS << " }\n";
|
OS << " }\n";
|
||||||
OS << " }\n";
|
OS << " }\n";
|
||||||
}
|
}
|
||||||
|
@ -1273,8 +1276,16 @@ namespace {
|
||||||
OS << " return false;\n";
|
OS << " return false;\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void writeTemplateInstantiation(raw_ostream &OS) const override {
|
||||||
|
OS << " " << getType() << " tempInst" << getUpperName() << " =\n";
|
||||||
|
OS << " S.SubstType(A->get" << getUpperName() << "Loc(), "
|
||||||
|
<< "TemplateArgs, A->getLoc(), A->getAttrName());\n";
|
||||||
|
OS << " if (!tempInst" << getUpperName() << ")\n";
|
||||||
|
OS << " return nullptr;\n";
|
||||||
|
}
|
||||||
|
|
||||||
void writeTemplateInstantiationArgs(raw_ostream &OS) const override {
|
void writeTemplateInstantiationArgs(raw_ostream &OS) const override {
|
||||||
OS << "A->get" << getUpperName() << "Loc()";
|
OS << "tempInst" << getUpperName();
|
||||||
}
|
}
|
||||||
|
|
||||||
void writePCHWrite(raw_ostream &OS) const override {
|
void writePCHWrite(raw_ostream &OS) const override {
|
||||||
|
|
|
@ -1318,6 +1318,12 @@ _LIBCPP_FUNC_VIS extern "C" void __sanitizer_annotate_contiguous_container(
|
||||||
#endif
|
#endif
|
||||||
#endif // !defined(_LIBCPP_NODEBUG_TYPE)
|
#endif // !defined(_LIBCPP_NODEBUG_TYPE)
|
||||||
|
|
||||||
|
#if __has_attribute(__preferred_name__)
|
||||||
|
#define _LIBCPP_PREFERRED_NAME(x) __attribute__((__preferred_name__(x)))
|
||||||
|
#else
|
||||||
|
#define _LIBCPP_PREFERRED_NAME(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(_LIBCPP_ABI_MICROSOFT) && \
|
#if defined(_LIBCPP_ABI_MICROSOFT) && \
|
||||||
(defined(_LIBCPP_COMPILER_MSVC) || __has_declspec_attribute(empty_bases))
|
(defined(_LIBCPP_COMPILER_MSVC) || __has_declspec_attribute(empty_bases))
|
||||||
# define _LIBCPP_DECLSPEC_EMPTY_BASES __declspec(empty_bases)
|
# define _LIBCPP_DECLSPEC_EMPTY_BASES __declspec(empty_bases)
|
||||||
|
|
|
@ -185,6 +185,36 @@ typedef basic_ifstream<wchar_t> wifstream;
|
||||||
typedef basic_ofstream<wchar_t> wofstream;
|
typedef basic_ofstream<wchar_t> wofstream;
|
||||||
typedef basic_fstream<wchar_t> wfstream;
|
typedef basic_fstream<wchar_t> wfstream;
|
||||||
|
|
||||||
|
template <class _CharT, class _Traits>
|
||||||
|
class _LIBCPP_PREFERRED_NAME(ios) _LIBCPP_PREFERRED_NAME(wios) basic_ios;
|
||||||
|
|
||||||
|
template <class _CharT, class _Traits>
|
||||||
|
class _LIBCPP_PREFERRED_NAME(streambuf) _LIBCPP_PREFERRED_NAME(wstreambuf) basic_streambuf;
|
||||||
|
template <class _CharT, class _Traits>
|
||||||
|
class _LIBCPP_PREFERRED_NAME(istream) _LIBCPP_PREFERRED_NAME(wistream) basic_istream;
|
||||||
|
template <class _CharT, class _Traits>
|
||||||
|
class _LIBCPP_PREFERRED_NAME(ostream) _LIBCPP_PREFERRED_NAME(wostream) basic_ostream;
|
||||||
|
template <class _CharT, class _Traits>
|
||||||
|
class _LIBCPP_PREFERRED_NAME(iostream) _LIBCPP_PREFERRED_NAME(wiostream) basic_iostream;
|
||||||
|
|
||||||
|
template <class _CharT, class _Traits, class _Allocator>
|
||||||
|
class _LIBCPP_PREFERRED_NAME(stringbuf) _LIBCPP_PREFERRED_NAME(wstringbuf) basic_stringbuf;
|
||||||
|
template <class _CharT, class _Traits, class _Allocator>
|
||||||
|
class _LIBCPP_PREFERRED_NAME(istringstream) _LIBCPP_PREFERRED_NAME(wistringstream) basic_istringstream;
|
||||||
|
template <class _CharT, class _Traits, class _Allocator>
|
||||||
|
class _LIBCPP_PREFERRED_NAME(ostringstream) _LIBCPP_PREFERRED_NAME(wostringstream) basic_ostringstream;
|
||||||
|
template <class _CharT, class _Traits, class _Allocator>
|
||||||
|
class _LIBCPP_PREFERRED_NAME(stringstream) _LIBCPP_PREFERRED_NAME(wstringstream) basic_stringstream;
|
||||||
|
|
||||||
|
template <class _CharT, class _Traits>
|
||||||
|
class _LIBCPP_PREFERRED_NAME(filebuf) _LIBCPP_PREFERRED_NAME(wfilebuf) basic_filebuf;
|
||||||
|
template <class _CharT, class _Traits>
|
||||||
|
class _LIBCPP_PREFERRED_NAME(ifstream) _LIBCPP_PREFERRED_NAME(wifstream) basic_ifstream;
|
||||||
|
template <class _CharT, class _Traits>
|
||||||
|
class _LIBCPP_PREFERRED_NAME(ofstream) _LIBCPP_PREFERRED_NAME(wofstream) basic_ofstream;
|
||||||
|
template <class _CharT, class _Traits>
|
||||||
|
class _LIBCPP_PREFERRED_NAME(fstream) _LIBCPP_PREFERRED_NAME(wfstream) basic_fstream;
|
||||||
|
|
||||||
template <class _State> class _LIBCPP_TEMPLATE_VIS fpos;
|
template <class _State> class _LIBCPP_TEMPLATE_VIS fpos;
|
||||||
typedef fpos<mbstate_t> streampos;
|
typedef fpos<mbstate_t> streampos;
|
||||||
typedef fpos<mbstate_t> wstreampos;
|
typedef fpos<mbstate_t> wstreampos;
|
||||||
|
@ -210,6 +240,8 @@ template <class _CharT, // for <stdexcept>
|
||||||
typedef basic_string<char, char_traits<char>, allocator<char> > string;
|
typedef basic_string<char, char_traits<char>, allocator<char> > string;
|
||||||
typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> > wstring;
|
typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> > wstring;
|
||||||
|
|
||||||
|
template <class _CharT, class _Traits, class _Allocator>
|
||||||
|
class _LIBCPP_PREFERRED_NAME(string) _LIBCPP_PREFERRED_NAME(wstring) basic_string;
|
||||||
|
|
||||||
// Include other forward declarations here
|
// Include other forward declarations here
|
||||||
template <class _Tp, class _Alloc = allocator<_Tp> >
|
template <class _Tp, class _Alloc = allocator<_Tp> >
|
||||||
|
|
|
@ -2534,7 +2534,17 @@ __exit:
|
||||||
template <class _CharT, class _Traits> class __lookahead;
|
template <class _CharT, class _Traits> class __lookahead;
|
||||||
|
|
||||||
template <class _CharT, class _Traits = regex_traits<_CharT> >
|
template <class _CharT, class _Traits = regex_traits<_CharT> >
|
||||||
class _LIBCPP_TEMPLATE_VIS basic_regex
|
class _LIBCPP_TEMPLATE_VIS basic_regex;
|
||||||
|
|
||||||
|
typedef basic_regex<char> regex;
|
||||||
|
typedef basic_regex<wchar_t> wregex;
|
||||||
|
|
||||||
|
template <class _CharT, class _Traits>
|
||||||
|
class
|
||||||
|
_LIBCPP_TEMPLATE_VIS
|
||||||
|
_LIBCPP_PREFERRED_NAME(regex)
|
||||||
|
_LIBCPP_PREFERRED_NAME(wregex)
|
||||||
|
basic_regex
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// types:
|
// types:
|
||||||
|
@ -4879,13 +4889,21 @@ basic_regex<_CharT, _Traits>::__push_lookahead(const basic_regex& __exp,
|
||||||
__end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
|
__end_ = static_cast<__owns_one_state<_CharT>*>(__end_->first());
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef basic_regex<char> regex;
|
|
||||||
typedef basic_regex<wchar_t> wregex;
|
|
||||||
|
|
||||||
// sub_match
|
// sub_match
|
||||||
|
|
||||||
|
typedef sub_match<const char*> csub_match;
|
||||||
|
typedef sub_match<const wchar_t*> wcsub_match;
|
||||||
|
typedef sub_match<string::const_iterator> ssub_match;
|
||||||
|
typedef sub_match<wstring::const_iterator> wssub_match;
|
||||||
|
|
||||||
template <class _BidirectionalIterator>
|
template <class _BidirectionalIterator>
|
||||||
class _LIBCPP_TEMPLATE_VIS sub_match
|
class
|
||||||
|
_LIBCPP_TEMPLATE_VIS
|
||||||
|
_LIBCPP_PREFERRED_NAME(csub_match)
|
||||||
|
_LIBCPP_PREFERRED_NAME(wcsub_match)
|
||||||
|
_LIBCPP_PREFERRED_NAME(ssub_match)
|
||||||
|
_LIBCPP_PREFERRED_NAME(wssub_match)
|
||||||
|
sub_match
|
||||||
: public pair<_BidirectionalIterator, _BidirectionalIterator>
|
: public pair<_BidirectionalIterator, _BidirectionalIterator>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -4920,11 +4938,6 @@ public:
|
||||||
{return str().compare(__s);}
|
{return str().compare(__s);}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef sub_match<const char*> csub_match;
|
|
||||||
typedef sub_match<const wchar_t*> wcsub_match;
|
|
||||||
typedef sub_match<string::const_iterator> ssub_match;
|
|
||||||
typedef sub_match<wstring::const_iterator> wssub_match;
|
|
||||||
|
|
||||||
template <class _BiIter>
|
template <class _BiIter>
|
||||||
inline _LIBCPP_INLINE_VISIBILITY
|
inline _LIBCPP_INLINE_VISIBILITY
|
||||||
bool
|
bool
|
||||||
|
@ -5307,8 +5320,19 @@ operator<<(basic_ostream<_CharT, _ST>& __os, const sub_match<_BiIter>& __m)
|
||||||
return __os << __m.str();
|
return __os << __m.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef match_results<const char*> cmatch;
|
||||||
|
typedef match_results<const wchar_t*> wcmatch;
|
||||||
|
typedef match_results<string::const_iterator> smatch;
|
||||||
|
typedef match_results<wstring::const_iterator> wsmatch;
|
||||||
|
|
||||||
template <class _BidirectionalIterator, class _Allocator>
|
template <class _BidirectionalIterator, class _Allocator>
|
||||||
class _LIBCPP_TEMPLATE_VIS match_results
|
class
|
||||||
|
_LIBCPP_TEMPLATE_VIS
|
||||||
|
_LIBCPP_PREFERRED_NAME(cmatch)
|
||||||
|
_LIBCPP_PREFERRED_NAME(wcmatch)
|
||||||
|
_LIBCPP_PREFERRED_NAME(smatch)
|
||||||
|
_LIBCPP_PREFERRED_NAME(wsmatch)
|
||||||
|
match_results
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef _Allocator allocator_type;
|
typedef _Allocator allocator_type;
|
||||||
|
@ -5628,11 +5652,6 @@ match_results<_BidirectionalIterator, _Allocator>::swap(match_results& __m)
|
||||||
swap(__ready_, __m.__ready_);
|
swap(__ready_, __m.__ready_);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef match_results<const char*> cmatch;
|
|
||||||
typedef match_results<const wchar_t*> wcmatch;
|
|
||||||
typedef match_results<string::const_iterator> smatch;
|
|
||||||
typedef match_results<wstring::const_iterator> wsmatch;
|
|
||||||
|
|
||||||
template <class _BidirectionalIterator, class _Allocator>
|
template <class _BidirectionalIterator, class _Allocator>
|
||||||
bool
|
bool
|
||||||
operator==(const match_results<_BidirectionalIterator, _Allocator>& __x,
|
operator==(const match_results<_BidirectionalIterator, _Allocator>& __x,
|
||||||
|
@ -6216,7 +6235,21 @@ regex_match(const basic_string<_CharT, _ST, _SA>& __s,
|
||||||
template <class _BidirectionalIterator,
|
template <class _BidirectionalIterator,
|
||||||
class _CharT = typename iterator_traits<_BidirectionalIterator>::value_type,
|
class _CharT = typename iterator_traits<_BidirectionalIterator>::value_type,
|
||||||
class _Traits = regex_traits<_CharT> >
|
class _Traits = regex_traits<_CharT> >
|
||||||
class _LIBCPP_TEMPLATE_VIS regex_iterator
|
class _LIBCPP_TEMPLATE_VIS regex_iterator;
|
||||||
|
|
||||||
|
typedef regex_iterator<const char*> cregex_iterator;
|
||||||
|
typedef regex_iterator<const wchar_t*> wcregex_iterator;
|
||||||
|
typedef regex_iterator<string::const_iterator> sregex_iterator;
|
||||||
|
typedef regex_iterator<wstring::const_iterator> wsregex_iterator;
|
||||||
|
|
||||||
|
template <class _BidirectionalIterator, class _CharT, class _Traits>
|
||||||
|
class
|
||||||
|
_LIBCPP_TEMPLATE_VIS
|
||||||
|
_LIBCPP_PREFERRED_NAME(cregex_iterator)
|
||||||
|
_LIBCPP_PREFERRED_NAME(wcregex_iterator)
|
||||||
|
_LIBCPP_PREFERRED_NAME(sregex_iterator)
|
||||||
|
_LIBCPP_PREFERRED_NAME(wsregex_iterator)
|
||||||
|
regex_iterator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef basic_regex<_CharT, _Traits> regex_type;
|
typedef basic_regex<_CharT, _Traits> regex_type;
|
||||||
|
@ -6325,17 +6358,26 @@ regex_iterator<_BidirectionalIterator, _CharT, _Traits>::operator++()
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef regex_iterator<const char*> cregex_iterator;
|
|
||||||
typedef regex_iterator<const wchar_t*> wcregex_iterator;
|
|
||||||
typedef regex_iterator<string::const_iterator> sregex_iterator;
|
|
||||||
typedef regex_iterator<wstring::const_iterator> wsregex_iterator;
|
|
||||||
|
|
||||||
// regex_token_iterator
|
// regex_token_iterator
|
||||||
|
|
||||||
template <class _BidirectionalIterator,
|
template <class _BidirectionalIterator,
|
||||||
class _CharT = typename iterator_traits<_BidirectionalIterator>::value_type,
|
class _CharT = typename iterator_traits<_BidirectionalIterator>::value_type,
|
||||||
class _Traits = regex_traits<_CharT> >
|
class _Traits = regex_traits<_CharT> >
|
||||||
class _LIBCPP_TEMPLATE_VIS regex_token_iterator
|
class _LIBCPP_TEMPLATE_VIS regex_token_iterator;
|
||||||
|
|
||||||
|
typedef regex_token_iterator<const char*> cregex_token_iterator;
|
||||||
|
typedef regex_token_iterator<const wchar_t*> wcregex_token_iterator;
|
||||||
|
typedef regex_token_iterator<string::const_iterator> sregex_token_iterator;
|
||||||
|
typedef regex_token_iterator<wstring::const_iterator> wsregex_token_iterator;
|
||||||
|
|
||||||
|
template <class _BidirectionalIterator, class _CharT, class _Traits>
|
||||||
|
class
|
||||||
|
_LIBCPP_TEMPLATE_VIS
|
||||||
|
_LIBCPP_PREFERRED_NAME(cregex_token_iterator)
|
||||||
|
_LIBCPP_PREFERRED_NAME(wcregex_token_iterator)
|
||||||
|
_LIBCPP_PREFERRED_NAME(sregex_token_iterator)
|
||||||
|
_LIBCPP_PREFERRED_NAME(wsregex_token_iterator)
|
||||||
|
regex_token_iterator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef basic_regex<_CharT, _Traits> regex_type;
|
typedef basic_regex<_CharT, _Traits> regex_type;
|
||||||
|
@ -6613,11 +6655,6 @@ regex_token_iterator<_BidirectionalIterator, _CharT, _Traits>::operator++()
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef regex_token_iterator<const char*> cregex_token_iterator;
|
|
||||||
typedef regex_token_iterator<const wchar_t*> wcregex_token_iterator;
|
|
||||||
typedef regex_token_iterator<string::const_iterator> sregex_token_iterator;
|
|
||||||
typedef regex_token_iterator<wstring::const_iterator> wsregex_token_iterator;
|
|
||||||
|
|
||||||
// regex_replace
|
// regex_replace
|
||||||
|
|
||||||
template <class _OutputIterator, class _BidirectionalIterator,
|
template <class _OutputIterator, class _BidirectionalIterator,
|
||||||
|
|
|
@ -666,8 +666,26 @@ struct __padding<_CharT, 1>
|
||||||
|
|
||||||
#endif // _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT
|
#endif // _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT
|
||||||
|
|
||||||
|
#ifndef _LIBCPP_NO_HAS_CHAR8_T
|
||||||
|
typedef basic_string<char8_t> u8string;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
|
||||||
|
typedef basic_string<char16_t> u16string;
|
||||||
|
typedef basic_string<char32_t> u32string;
|
||||||
|
#endif // _LIBCPP_HAS_NO_UNICODE_CHARS
|
||||||
|
|
||||||
template<class _CharT, class _Traits, class _Allocator>
|
template<class _CharT, class _Traits, class _Allocator>
|
||||||
class _LIBCPP_TEMPLATE_VIS basic_string
|
class
|
||||||
|
_LIBCPP_TEMPLATE_VIS
|
||||||
|
#ifndef _LIBCPP_NO_HAS_CHAR8_T
|
||||||
|
_LIBCPP_PREFERRED_NAME(u8string)
|
||||||
|
#endif
|
||||||
|
#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
|
||||||
|
_LIBCPP_PREFERRED_NAME(u16string)
|
||||||
|
_LIBCPP_PREFERRED_NAME(u32string)
|
||||||
|
#endif
|
||||||
|
basic_string
|
||||||
: private __basic_string_common<true>
|
: private __basic_string_common<true>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -4327,15 +4345,6 @@ swap(basic_string<_CharT, _Traits, _Allocator>& __lhs,
|
||||||
__lhs.swap(__rhs);
|
__lhs.swap(__rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _LIBCPP_NO_HAS_CHAR8_T
|
|
||||||
typedef basic_string<char8_t> u8string;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _LIBCPP_HAS_NO_UNICODE_CHARS
|
|
||||||
typedef basic_string<char16_t> u16string;
|
|
||||||
typedef basic_string<char32_t> u32string;
|
|
||||||
#endif // _LIBCPP_HAS_NO_UNICODE_CHARS
|
|
||||||
|
|
||||||
_LIBCPP_FUNC_VIS int stoi (const string& __str, size_t* __idx = nullptr, int __base = 10);
|
_LIBCPP_FUNC_VIS int stoi (const string& __str, size_t* __idx = nullptr, int __base = 10);
|
||||||
_LIBCPP_FUNC_VIS long stol (const string& __str, size_t* __idx = nullptr, int __base = 10);
|
_LIBCPP_FUNC_VIS long stol (const string& __str, size_t* __idx = nullptr, int __base = 10);
|
||||||
_LIBCPP_FUNC_VIS unsigned long stoul (const string& __str, size_t* __idx = nullptr, int __base = 10);
|
_LIBCPP_FUNC_VIS unsigned long stoul (const string& __str, size_t* __idx = nullptr, int __base = 10);
|
||||||
|
|
|
@ -192,7 +192,26 @@ _LIBCPP_PUSH_MACROS
|
||||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||||
|
|
||||||
template<class _CharT, class _Traits = char_traits<_CharT> >
|
template<class _CharT, class _Traits = char_traits<_CharT> >
|
||||||
class _LIBCPP_TEMPLATE_VIS basic_string_view {
|
class _LIBCPP_TEMPLATE_VIS basic_string_view;
|
||||||
|
|
||||||
|
typedef basic_string_view<char> string_view;
|
||||||
|
#ifndef _LIBCPP_NO_HAS_CHAR8_T
|
||||||
|
typedef basic_string_view<char8_t> u8string_view;
|
||||||
|
#endif
|
||||||
|
typedef basic_string_view<char16_t> u16string_view;
|
||||||
|
typedef basic_string_view<char32_t> u32string_view;
|
||||||
|
typedef basic_string_view<wchar_t> wstring_view;
|
||||||
|
|
||||||
|
template<class _CharT, class _Traits>
|
||||||
|
class
|
||||||
|
_LIBCPP_PREFERRED_NAME(string_view)
|
||||||
|
#ifndef _LIBCPP_NO_HAS_CHAR8_T
|
||||||
|
_LIBCPP_PREFERRED_NAME(u8string_view)
|
||||||
|
#endif
|
||||||
|
_LIBCPP_PREFERRED_NAME(u16string_view)
|
||||||
|
_LIBCPP_PREFERRED_NAME(u32string_view)
|
||||||
|
_LIBCPP_PREFERRED_NAME(wstring_view)
|
||||||
|
basic_string_view {
|
||||||
public:
|
public:
|
||||||
// types
|
// types
|
||||||
typedef _Traits traits_type;
|
typedef _Traits traits_type;
|
||||||
|
@ -776,14 +795,6 @@ basic_ostream<_CharT, _Traits>&
|
||||||
operator<<(basic_ostream<_CharT, _Traits>& __os,
|
operator<<(basic_ostream<_CharT, _Traits>& __os,
|
||||||
basic_string_view<_CharT, _Traits> __str);
|
basic_string_view<_CharT, _Traits> __str);
|
||||||
|
|
||||||
typedef basic_string_view<char> string_view;
|
|
||||||
#ifndef _LIBCPP_NO_HAS_CHAR8_T
|
|
||||||
typedef basic_string_view<char8_t> u8string_view;
|
|
||||||
#endif
|
|
||||||
typedef basic_string_view<char16_t> u16string_view;
|
|
||||||
typedef basic_string_view<char32_t> u32string_view;
|
|
||||||
typedef basic_string_view<wchar_t> wstring_view;
|
|
||||||
|
|
||||||
// [string.view.hash]
|
// [string.view.hash]
|
||||||
template<class _CharT>
|
template<class _CharT>
|
||||||
struct _LIBCPP_TEMPLATE_VIS hash<basic_string_view<_CharT, char_traits<_CharT> > >
|
struct _LIBCPP_TEMPLATE_VIS hash<basic_string_view<_CharT, char_traits<_CharT> > >
|
||||||
|
|
Loading…
Reference in New Issue