forked from OSchip/llvm-project
P0091R3: Implement basic parsing support for C++17 deduction-guides.
We model deduction-guides as functions with a new kind of name that identifies the template whose deduction they guide; the bulk of this patch is adding the new name kind. This gives us a clean way to attach an extensible list of guides to a class template in a way that doesn't require any special handling in AST files etc (and we're going to need these functions we come to performing deduction). llvm-svn: 294266
This commit is contained in:
parent
8f844f3960
commit
3584515018
|
@ -1931,6 +1931,12 @@ public:
|
||||||
bool isDeletedAsWritten() const { return IsDeleted && !IsDefaulted; }
|
bool isDeletedAsWritten() const { return IsDeleted && !IsDefaulted; }
|
||||||
void setDeletedAsWritten(bool D = true) { IsDeleted = D; }
|
void setDeletedAsWritten(bool D = true) { IsDeleted = D; }
|
||||||
|
|
||||||
|
/// \brief Determines whether this function is a deduction guide.
|
||||||
|
bool isDeductionGuide() const {
|
||||||
|
return getDeclName().getNameKind() ==
|
||||||
|
DeclarationName::CXXDeductionGuideName;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Determines whether this function is "main", which is the
|
/// \brief Determines whether this function is "main", which is the
|
||||||
/// entry point into an executable program.
|
/// entry point into an executable program.
|
||||||
bool isMain() const;
|
bool isMain() const;
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace llvm {
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
class ASTContext;
|
class ASTContext;
|
||||||
|
class CXXDeductionGuideNameExtra;
|
||||||
class CXXLiteralOperatorIdName;
|
class CXXLiteralOperatorIdName;
|
||||||
class CXXOperatorIdName;
|
class CXXOperatorIdName;
|
||||||
class CXXSpecialName;
|
class CXXSpecialName;
|
||||||
|
@ -32,6 +33,7 @@ namespace clang {
|
||||||
enum OverloadedOperatorKind : int;
|
enum OverloadedOperatorKind : int;
|
||||||
struct PrintingPolicy;
|
struct PrintingPolicy;
|
||||||
class QualType;
|
class QualType;
|
||||||
|
class TemplateDecl;
|
||||||
class Type;
|
class Type;
|
||||||
class TypeSourceInfo;
|
class TypeSourceInfo;
|
||||||
class UsingDirectiveDecl;
|
class UsingDirectiveDecl;
|
||||||
|
@ -56,6 +58,7 @@ public:
|
||||||
CXXConstructorName,
|
CXXConstructorName,
|
||||||
CXXDestructorName,
|
CXXDestructorName,
|
||||||
CXXConversionFunctionName,
|
CXXConversionFunctionName,
|
||||||
|
CXXDeductionGuideName,
|
||||||
CXXOperatorName,
|
CXXOperatorName,
|
||||||
CXXLiteralOperatorName,
|
CXXLiteralOperatorName,
|
||||||
CXXUsingDirective
|
CXXUsingDirective
|
||||||
|
@ -118,42 +121,36 @@ private:
|
||||||
CXXSpecialName *getAsCXXSpecialName() const {
|
CXXSpecialName *getAsCXXSpecialName() const {
|
||||||
NameKind Kind = getNameKind();
|
NameKind Kind = getNameKind();
|
||||||
if (Kind >= CXXConstructorName && Kind <= CXXConversionFunctionName)
|
if (Kind >= CXXConstructorName && Kind <= CXXConversionFunctionName)
|
||||||
return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask);
|
return reinterpret_cast<CXXSpecialName *>(getExtra());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If the stored pointer is actually a CXXDeductionGuideNameExtra, returns a
|
||||||
|
/// pointer to it. Otherwise, returns a NULL pointer.
|
||||||
|
CXXDeductionGuideNameExtra *getAsCXXDeductionGuideNameExtra() const {
|
||||||
|
if (getNameKind() == CXXDeductionGuideName)
|
||||||
|
return reinterpret_cast<CXXDeductionGuideNameExtra *>(getExtra());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// getAsCXXOperatorIdName
|
/// getAsCXXOperatorIdName
|
||||||
CXXOperatorIdName *getAsCXXOperatorIdName() const {
|
CXXOperatorIdName *getAsCXXOperatorIdName() const {
|
||||||
if (getNameKind() == CXXOperatorName)
|
if (getNameKind() == CXXOperatorName)
|
||||||
return reinterpret_cast<CXXOperatorIdName *>(Ptr & ~PtrMask);
|
return reinterpret_cast<CXXOperatorIdName *>(getExtra());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CXXLiteralOperatorIdName *getAsCXXLiteralOperatorIdName() const {
|
CXXLiteralOperatorIdName *getAsCXXLiteralOperatorIdName() const {
|
||||||
if (getNameKind() == CXXLiteralOperatorName)
|
if (getNameKind() == CXXLiteralOperatorName)
|
||||||
return reinterpret_cast<CXXLiteralOperatorIdName *>(Ptr & ~PtrMask);
|
return reinterpret_cast<CXXLiteralOperatorIdName *>(getExtra());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct a declaration name from the name of a C++ constructor,
|
// Construct a declaration name from the name of a C++ constructor,
|
||||||
// destructor, or conversion function.
|
// destructor, or conversion function.
|
||||||
DeclarationName(CXXSpecialName *Name)
|
DeclarationName(DeclarationNameExtra *Name)
|
||||||
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
|
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
|
||||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXSpecialName");
|
assert((Ptr & PtrMask) == 0 && "Improperly aligned DeclarationNameExtra");
|
||||||
Ptr |= StoredDeclarationNameExtra;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct a declaration name from the name of a C++ overloaded
|
|
||||||
// operator.
|
|
||||||
DeclarationName(CXXOperatorIdName *Name)
|
|
||||||
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
|
|
||||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId");
|
|
||||||
Ptr |= StoredDeclarationNameExtra;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeclarationName(CXXLiteralOperatorIdName *Name)
|
|
||||||
: Ptr(reinterpret_cast<uintptr_t>(Name)) {
|
|
||||||
assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXLiteralOperatorId");
|
|
||||||
Ptr |= StoredDeclarationNameExtra;
|
Ptr |= StoredDeclarationNameExtra;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,6 +249,10 @@ public:
|
||||||
/// type associated with that name.
|
/// type associated with that name.
|
||||||
QualType getCXXNameType() const;
|
QualType getCXXNameType() const;
|
||||||
|
|
||||||
|
/// If this name is the name of a C++ deduction guide, return the
|
||||||
|
/// template associated with that name.
|
||||||
|
TemplateDecl *getCXXDeductionGuideTemplate() const;
|
||||||
|
|
||||||
/// getCXXOverloadedOperator - If this name is the name of an
|
/// getCXXOverloadedOperator - If this name is the name of an
|
||||||
/// overloadable operator in C++ (e.g., @c operator+), retrieve the
|
/// overloadable operator in C++ (e.g., @c operator+), retrieve the
|
||||||
/// kind of overloaded operator.
|
/// kind of overloaded operator.
|
||||||
|
@ -346,6 +347,7 @@ class DeclarationNameTable {
|
||||||
void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
|
void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
|
||||||
CXXOperatorIdName *CXXOperatorNames; // Operator names
|
CXXOperatorIdName *CXXOperatorNames; // Operator names
|
||||||
void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName*
|
void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName*
|
||||||
|
void *CXXDeductionGuideNames; // FoldingSet<CXXDeductionGuideNameExtra> *
|
||||||
|
|
||||||
DeclarationNameTable(const DeclarationNameTable&) = delete;
|
DeclarationNameTable(const DeclarationNameTable&) = delete;
|
||||||
void operator=(const DeclarationNameTable&) = delete;
|
void operator=(const DeclarationNameTable&) = delete;
|
||||||
|
@ -368,6 +370,9 @@ public:
|
||||||
/// for the given Type.
|
/// for the given Type.
|
||||||
DeclarationName getCXXDestructorName(CanQualType Ty);
|
DeclarationName getCXXDestructorName(CanQualType Ty);
|
||||||
|
|
||||||
|
/// Returns the name of a C++ deduction guide for the given template.
|
||||||
|
DeclarationName getCXXDeductionGuideName(TemplateDecl *TD);
|
||||||
|
|
||||||
/// getCXXConversionFunctionName - Returns the name of a C++
|
/// getCXXConversionFunctionName - Returns the name of a C++
|
||||||
/// conversion function for the given Type.
|
/// conversion function for the given Type.
|
||||||
DeclarationName getCXXConversionFunctionName(CanQualType Ty);
|
DeclarationName getCXXConversionFunctionName(CanQualType Ty);
|
||||||
|
|
|
@ -774,6 +774,11 @@ bool RecursiveASTVisitor<Derived>::TraverseDeclarationNameInfo(
|
||||||
TRY_TO(TraverseTypeLoc(TSInfo->getTypeLoc()));
|
TRY_TO(TraverseTypeLoc(TSInfo->getTypeLoc()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
|
TRY_TO(TraverseTemplateName(
|
||||||
|
TemplateName(NameInfo.getName().getCXXDeductionGuideTemplate())));
|
||||||
|
break;
|
||||||
|
|
||||||
case DeclarationName::Identifier:
|
case DeclarationName::Identifier:
|
||||||
case DeclarationName::ObjCZeroArgSelector:
|
case DeclarationName::ObjCZeroArgSelector:
|
||||||
case DeclarationName::ObjCOneArgSelector:
|
case DeclarationName::ObjCOneArgSelector:
|
||||||
|
|
|
@ -1207,8 +1207,9 @@ def warn_cxx98_compat_unelaborated_friend_type : Warning<
|
||||||
def err_qualified_friend_not_found : Error<
|
def err_qualified_friend_not_found : Error<
|
||||||
"no function named %0 with type %1 was found in the specified scope">;
|
"no function named %0 with type %1 was found in the specified scope">;
|
||||||
def err_introducing_special_friend : Error<
|
def err_introducing_special_friend : Error<
|
||||||
"must use a qualified name when declaring a %select{constructor|"
|
"%plural{[0,2]:must use a qualified name when declaring|3:cannot declare}0"
|
||||||
"destructor|conversion operator}0 as a friend">;
|
" a %select{constructor|destructor|conversion operator|deduction guide}0 "
|
||||||
|
"as a friend">;
|
||||||
def err_tagless_friend_type_template : Error<
|
def err_tagless_friend_type_template : Error<
|
||||||
"friend type templates must use an elaborated type">;
|
"friend type templates must use an elaborated type">;
|
||||||
def err_no_matching_local_friend : Error<
|
def err_no_matching_local_friend : Error<
|
||||||
|
@ -1960,6 +1961,15 @@ def err_deduced_class_template_compound_type : Error<
|
||||||
"deduced class template specialization type">;
|
"deduced class template specialization type">;
|
||||||
def err_deduced_class_template_not_supported : Error<
|
def err_deduced_class_template_not_supported : Error<
|
||||||
"deduction of template arguments for class templates is not yet supported">;
|
"deduction of template arguments for class templates is not yet supported">;
|
||||||
|
def err_deduction_guide_no_trailing_return_type : Error<
|
||||||
|
"deduction guide declaration without trailing return type">;
|
||||||
|
def err_deduction_guide_with_complex_decl : Error<
|
||||||
|
"cannot specify any part of a return type in the "
|
||||||
|
"declaration of a deduction guide">;
|
||||||
|
def err_deduction_guide_name_not_class_template : Error<
|
||||||
|
"cannot specify deduction guide for "
|
||||||
|
"%select{<error>|function template|variable template|alias template|"
|
||||||
|
"template template parameter|dependent template name}0 %1">;
|
||||||
|
|
||||||
// C++1y deduced return types
|
// C++1y deduced return types
|
||||||
def err_auto_fn_deduction_failure : Error<
|
def err_auto_fn_deduction_failure : Error<
|
||||||
|
|
|
@ -818,6 +818,7 @@ public:
|
||||||
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
|
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
|
||||||
CXXOperator##Name,
|
CXXOperator##Name,
|
||||||
#include "clang/Basic/OperatorKinds.def"
|
#include "clang/Basic/OperatorKinds.def"
|
||||||
|
CXXDeductionGuide,
|
||||||
CXXLiteralOperator,
|
CXXLiteralOperator,
|
||||||
CXXUsingDirective,
|
CXXUsingDirective,
|
||||||
NUM_EXTRA_KINDS
|
NUM_EXTRA_KINDS
|
||||||
|
|
|
@ -1967,7 +1967,7 @@ private:
|
||||||
/// \brief Starting with a scope specifier, identifier, or
|
/// \brief Starting with a scope specifier, identifier, or
|
||||||
/// template-id that refers to the current class, determine whether
|
/// template-id that refers to the current class, determine whether
|
||||||
/// this is a constructor declarator.
|
/// this is a constructor declarator.
|
||||||
bool isConstructorDeclarator(bool Unqualified);
|
bool isConstructorDeclarator(bool Unqualified, bool DeductionGuide = false);
|
||||||
|
|
||||||
/// \brief Specifies the context in which type-id/expression
|
/// \brief Specifies the context in which type-id/expression
|
||||||
/// disambiguation will occur.
|
/// disambiguation will occur.
|
||||||
|
@ -2634,6 +2634,7 @@ public:
|
||||||
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
|
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
|
||||||
bool AllowDestructorName,
|
bool AllowDestructorName,
|
||||||
bool AllowConstructorName,
|
bool AllowConstructorName,
|
||||||
|
bool AllowDeductionGuide,
|
||||||
ParsedType ObjectType,
|
ParsedType ObjectType,
|
||||||
SourceLocation& TemplateKWLoc,
|
SourceLocation& TemplateKWLoc,
|
||||||
UnqualifiedId &Result);
|
UnqualifiedId &Result);
|
||||||
|
|
|
@ -908,7 +908,9 @@ public:
|
||||||
/// \brief A template-id, e.g., f<int>.
|
/// \brief A template-id, e.g., f<int>.
|
||||||
IK_TemplateId,
|
IK_TemplateId,
|
||||||
/// \brief An implicit 'self' parameter
|
/// \brief An implicit 'self' parameter
|
||||||
IK_ImplicitSelfParam
|
IK_ImplicitSelfParam,
|
||||||
|
/// \brief A deduction-guide name (a template-name)
|
||||||
|
IK_DeductionGuideName
|
||||||
} Kind;
|
} Kind;
|
||||||
|
|
||||||
struct OFI {
|
struct OFI {
|
||||||
|
@ -928,8 +930,8 @@ public:
|
||||||
/// \brief Anonymous union that holds extra data associated with the
|
/// \brief Anonymous union that holds extra data associated with the
|
||||||
/// parsed unqualified-id.
|
/// parsed unqualified-id.
|
||||||
union {
|
union {
|
||||||
/// \brief When Kind == IK_Identifier, the parsed identifier, or when Kind
|
/// \brief When Kind == IK_Identifier, the parsed identifier, or when
|
||||||
/// == IK_UserLiteralId, the identifier suffix.
|
/// Kind == IK_UserLiteralId, the identifier suffix.
|
||||||
IdentifierInfo *Identifier;
|
IdentifierInfo *Identifier;
|
||||||
|
|
||||||
/// \brief When Kind == IK_OperatorFunctionId, the overloaded operator
|
/// \brief When Kind == IK_OperatorFunctionId, the overloaded operator
|
||||||
|
@ -947,6 +949,9 @@ public:
|
||||||
/// \brief When Kind == IK_DestructorName, the type referred to by the
|
/// \brief When Kind == IK_DestructorName, the type referred to by the
|
||||||
/// class-name.
|
/// class-name.
|
||||||
UnionParsedType DestructorName;
|
UnionParsedType DestructorName;
|
||||||
|
|
||||||
|
/// \brief When Kind == IK_DeductionGuideName, the parsed template-name.
|
||||||
|
UnionParsedTemplateTy TemplateName;
|
||||||
|
|
||||||
/// \brief When Kind == IK_TemplateId or IK_ConstructorTemplateId,
|
/// \brief When Kind == IK_TemplateId or IK_ConstructorTemplateId,
|
||||||
/// the template-id annotation that contains the template name and
|
/// the template-id annotation that contains the template name and
|
||||||
|
@ -1085,6 +1090,18 @@ public:
|
||||||
/// \p TemplateId and will free it on destruction.
|
/// \p TemplateId and will free it on destruction.
|
||||||
void setTemplateId(TemplateIdAnnotation *TemplateId);
|
void setTemplateId(TemplateIdAnnotation *TemplateId);
|
||||||
|
|
||||||
|
/// \brief Specify that this unqualified-id was parsed as a template-name for
|
||||||
|
/// a deduction-guide.
|
||||||
|
///
|
||||||
|
/// \param Template The parsed template-name.
|
||||||
|
/// \param TemplateLoc The location of the parsed template-name.
|
||||||
|
void setDeductionGuideName(ParsedTemplateTy Template,
|
||||||
|
SourceLocation TemplateLoc) {
|
||||||
|
Kind = IK_DeductionGuideName;
|
||||||
|
TemplateName = Template;
|
||||||
|
StartLocation = EndLocation = TemplateLoc;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Return the source range that covers this unqualified-id.
|
/// \brief Return the source range that covers this unqualified-id.
|
||||||
SourceRange getSourceRange() const LLVM_READONLY {
|
SourceRange getSourceRange() const LLVM_READONLY {
|
||||||
return SourceRange(StartLocation, EndLocation);
|
return SourceRange(StartLocation, EndLocation);
|
||||||
|
@ -2319,6 +2336,16 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Determine whether a trailing return type was written (at any
|
||||||
|
/// level) within this declarator.
|
||||||
|
bool hasTrailingReturnType() const {
|
||||||
|
for (const auto &Chunk : type_objects())
|
||||||
|
if (Chunk.Kind == DeclaratorChunk::Function &&
|
||||||
|
Chunk.Fun.hasTrailingReturnType())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// takeAttributes - Takes attributes from the given parsed-attributes
|
/// takeAttributes - Takes attributes from the given parsed-attributes
|
||||||
/// set and add them to this declarator.
|
/// set and add them to this declarator.
|
||||||
///
|
///
|
||||||
|
|
|
@ -257,6 +257,7 @@ namespace clang {
|
||||||
|
|
||||||
typedef ActionResult<Decl*> DeclResult;
|
typedef ActionResult<Decl*> DeclResult;
|
||||||
typedef OpaquePtr<TemplateName> ParsedTemplateTy;
|
typedef OpaquePtr<TemplateName> ParsedTemplateTy;
|
||||||
|
typedef UnionOpaquePtr<TemplateName> UnionParsedTemplateTy;
|
||||||
|
|
||||||
typedef MutableArrayRef<Expr*> MultiExprArg;
|
typedef MutableArrayRef<Expr*> MultiExprArg;
|
||||||
typedef MutableArrayRef<Stmt*> MultiStmtArg;
|
typedef MutableArrayRef<Stmt*> MultiStmtArg;
|
||||||
|
|
|
@ -5619,6 +5619,8 @@ public:
|
||||||
void CheckConversionDeclarator(Declarator &D, QualType &R,
|
void CheckConversionDeclarator(Declarator &D, QualType &R,
|
||||||
StorageClass& SC);
|
StorageClass& SC);
|
||||||
Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion);
|
Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion);
|
||||||
|
void CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
|
||||||
|
StorageClass &SC);
|
||||||
|
|
||||||
void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD);
|
void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD);
|
||||||
void CheckExplicitlyDefaultedMemberExceptionSpec(CXXMethodDecl *MD,
|
void CheckExplicitlyDefaultedMemberExceptionSpec(CXXMethodDecl *MD,
|
||||||
|
@ -5822,6 +5824,22 @@ public:
|
||||||
TemplateTy &Template,
|
TemplateTy &Template,
|
||||||
bool &MemberOfUnknownSpecialization);
|
bool &MemberOfUnknownSpecialization);
|
||||||
|
|
||||||
|
/// Determine whether a particular identifier might be the name in a C++1z
|
||||||
|
/// deduction-guide declaration.
|
||||||
|
bool isDeductionGuideName(Scope *S, const IdentifierInfo &Name,
|
||||||
|
SourceLocation NameLoc,
|
||||||
|
ParsedTemplateTy *Template = nullptr) {
|
||||||
|
CXXScopeSpec SS;
|
||||||
|
UnqualifiedId Id;
|
||||||
|
Id.setIdentifier(&Name, NameLoc);
|
||||||
|
TemplateTy TemplateFallback;
|
||||||
|
bool MemberOfUnknownSpecialization;
|
||||||
|
// FIXME: Use redeclaration lookup!
|
||||||
|
return isTemplateName(S, SS, false, Id, ParsedType(), false,
|
||||||
|
Template ? *Template : TemplateFallback,
|
||||||
|
MemberOfUnknownSpecialization) == TNK_Type_template;
|
||||||
|
}
|
||||||
|
|
||||||
bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
|
bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
|
||||||
SourceLocation IILoc,
|
SourceLocation IILoc,
|
||||||
Scope *S,
|
Scope *S,
|
||||||
|
|
|
@ -1628,7 +1628,8 @@ namespace clang {
|
||||||
|
|
||||||
IdentifierInfo *getIdentifier() const {
|
IdentifierInfo *getIdentifier() const {
|
||||||
assert(Kind == DeclarationName::Identifier ||
|
assert(Kind == DeclarationName::Identifier ||
|
||||||
Kind == DeclarationName::CXXLiteralOperatorName);
|
Kind == DeclarationName::CXXLiteralOperatorName ||
|
||||||
|
Kind == DeclarationName::CXXDeductionGuideName);
|
||||||
return (IdentifierInfo *)Data;
|
return (IdentifierInfo *)Data;
|
||||||
}
|
}
|
||||||
Selector getSelector() const {
|
Selector getSelector() const {
|
||||||
|
|
|
@ -2264,6 +2264,7 @@ ASTNodeImporter::ImportDeclarationNameLoc(const DeclarationNameInfo &From,
|
||||||
case DeclarationName::ObjCOneArgSelector:
|
case DeclarationName::ObjCOneArgSelector:
|
||||||
case DeclarationName::ObjCMultiArgSelector:
|
case DeclarationName::ObjCMultiArgSelector:
|
||||||
case DeclarationName::CXXUsingDirective:
|
case DeclarationName::CXXUsingDirective:
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case DeclarationName::CXXOperatorName: {
|
case DeclarationName::CXXOperatorName: {
|
||||||
|
@ -7448,6 +7449,14 @@ DeclarationName ASTImporter::Import(DeclarationName FromName) {
|
||||||
ToContext.getCanonicalType(T));
|
ToContext.getCanonicalType(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case DeclarationName::CXXDeductionGuideName: {
|
||||||
|
TemplateDecl *Template = cast_or_null<TemplateDecl>(
|
||||||
|
Import(FromName.getCXXDeductionGuideTemplate()));
|
||||||
|
if (!Template)
|
||||||
|
return DeclarationName();
|
||||||
|
return ToContext.DeclarationNames.getCXXDeductionGuideName(Template);
|
||||||
|
}
|
||||||
|
|
||||||
case DeclarationName::CXXConversionFunctionName: {
|
case DeclarationName::CXXConversionFunctionName: {
|
||||||
QualType T = Import(FromName.getCXXNameType());
|
QualType T = Import(FromName.getCXXNameType());
|
||||||
if (T.isNull())
|
if (T.isNull())
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "clang/AST/DeclarationName.h"
|
#include "clang/AST/DeclarationName.h"
|
||||||
#include "clang/AST/ASTContext.h"
|
#include "clang/AST/ASTContext.h"
|
||||||
#include "clang/AST/DeclCXX.h"
|
#include "clang/AST/DeclCXX.h"
|
||||||
|
#include "clang/AST/DeclTemplate.h"
|
||||||
#include "clang/AST/Type.h"
|
#include "clang/AST/Type.h"
|
||||||
#include "clang/AST/TypeLoc.h"
|
#include "clang/AST/TypeLoc.h"
|
||||||
#include "clang/AST/TypeOrdering.h"
|
#include "clang/AST/TypeOrdering.h"
|
||||||
|
@ -43,6 +44,22 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Contains extra information for the name of a C++ deduction guide.
|
||||||
|
class CXXDeductionGuideNameExtra : public DeclarationNameExtra,
|
||||||
|
public llvm::FoldingSetNode {
|
||||||
|
public:
|
||||||
|
/// The template named by the deduction guide.
|
||||||
|
TemplateDecl *Template;
|
||||||
|
|
||||||
|
/// FETokenInfo - Extra information associated with this operator
|
||||||
|
/// name that can be used by the front end.
|
||||||
|
void *FETokenInfo;
|
||||||
|
|
||||||
|
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||||
|
ID.AddPointer(Template);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// CXXOperatorIdName - Contains extra information for the name of an
|
/// CXXOperatorIdName - Contains extra information for the name of an
|
||||||
/// overloaded operator in C++, such as "operator+.
|
/// overloaded operator in C++, such as "operator+.
|
||||||
class CXXOperatorIdName : public DeclarationNameExtra {
|
class CXXOperatorIdName : public DeclarationNameExtra {
|
||||||
|
@ -122,7 +139,13 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) {
|
||||||
if (QualTypeOrdering()(RHS.getCXXNameType(), LHS.getCXXNameType()))
|
if (QualTypeOrdering()(RHS.getCXXNameType(), LHS.getCXXNameType()))
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
|
// We never want to compare deduction guide names for templates from
|
||||||
|
// different scopes, so just compare the template-name.
|
||||||
|
return compare(LHS.getCXXDeductionGuideTemplate()->getDeclName(),
|
||||||
|
RHS.getCXXDeductionGuideTemplate()->getDeclName());
|
||||||
|
|
||||||
case DeclarationName::CXXOperatorName:
|
case DeclarationName::CXXOperatorName:
|
||||||
return compareInt(LHS.getCXXOverloadedOperator(),
|
return compareInt(LHS.getCXXOverloadedOperator(),
|
||||||
RHS.getCXXOverloadedOperator());
|
RHS.getCXXOverloadedOperator());
|
||||||
|
@ -179,6 +202,9 @@ void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) {
|
||||||
return printCXXConstructorDestructorName(N.getCXXNameType(), OS, Policy);
|
return printCXXConstructorDestructorName(N.getCXXNameType(), OS, Policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
|
return getCXXDeductionGuideTemplate()->getDeclName().print(OS, Policy);
|
||||||
|
|
||||||
case DeclarationName::CXXOperatorName: {
|
case DeclarationName::CXXOperatorName: {
|
||||||
static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = {
|
static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = {
|
||||||
nullptr,
|
nullptr,
|
||||||
|
@ -243,6 +269,9 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
|
||||||
case DeclarationNameExtra::CXXDestructor:
|
case DeclarationNameExtra::CXXDestructor:
|
||||||
return CXXDestructorName;
|
return CXXDestructorName;
|
||||||
|
|
||||||
|
case DeclarationNameExtra::CXXDeductionGuide:
|
||||||
|
return CXXDeductionGuideName;
|
||||||
|
|
||||||
case DeclarationNameExtra::CXXConversionFunction:
|
case DeclarationNameExtra::CXXConversionFunction:
|
||||||
return CXXConversionFunctionName;
|
return CXXConversionFunctionName;
|
||||||
|
|
||||||
|
@ -268,7 +297,15 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
|
||||||
|
|
||||||
bool DeclarationName::isDependentName() const {
|
bool DeclarationName::isDependentName() const {
|
||||||
QualType T = getCXXNameType();
|
QualType T = getCXXNameType();
|
||||||
return !T.isNull() && T->isDependentType();
|
if (!T.isNull() && T->isDependentType())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// A class-scope deduction guide in a dependent context has a dependent name.
|
||||||
|
auto *TD = getCXXDeductionGuideTemplate();
|
||||||
|
if (TD && TD->getDeclContext()->isDependentContext())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DeclarationName::getAsString() const {
|
std::string DeclarationName::getAsString() const {
|
||||||
|
@ -285,6 +322,12 @@ QualType DeclarationName::getCXXNameType() const {
|
||||||
return QualType();
|
return QualType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TemplateDecl *DeclarationName::getCXXDeductionGuideTemplate() const {
|
||||||
|
if (auto *Guide = getAsCXXDeductionGuideNameExtra())
|
||||||
|
return Guide->Template;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
OverloadedOperatorKind DeclarationName::getCXXOverloadedOperator() const {
|
OverloadedOperatorKind DeclarationName::getCXXOverloadedOperator() const {
|
||||||
if (CXXOperatorIdName *CXXOp = getAsCXXOperatorIdName()) {
|
if (CXXOperatorIdName *CXXOp = getAsCXXOperatorIdName()) {
|
||||||
unsigned value
|
unsigned value
|
||||||
|
@ -312,6 +355,9 @@ void *DeclarationName::getFETokenInfoAsVoidSlow() const {
|
||||||
case CXXConversionFunctionName:
|
case CXXConversionFunctionName:
|
||||||
return getAsCXXSpecialName()->FETokenInfo;
|
return getAsCXXSpecialName()->FETokenInfo;
|
||||||
|
|
||||||
|
case CXXDeductionGuideName:
|
||||||
|
return getAsCXXDeductionGuideNameExtra()->FETokenInfo;
|
||||||
|
|
||||||
case CXXOperatorName:
|
case CXXOperatorName:
|
||||||
return getAsCXXOperatorIdName()->FETokenInfo;
|
return getAsCXXOperatorIdName()->FETokenInfo;
|
||||||
|
|
||||||
|
@ -335,6 +381,10 @@ void DeclarationName::setFETokenInfo(void *T) {
|
||||||
getAsCXXSpecialName()->FETokenInfo = T;
|
getAsCXXSpecialName()->FETokenInfo = T;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CXXDeductionGuideName:
|
||||||
|
getAsCXXDeductionGuideNameExtra()->FETokenInfo = T;
|
||||||
|
break;
|
||||||
|
|
||||||
case CXXOperatorName:
|
case CXXOperatorName:
|
||||||
getAsCXXOperatorIdName()->FETokenInfo = T;
|
getAsCXXOperatorIdName()->FETokenInfo = T;
|
||||||
break;
|
break;
|
||||||
|
@ -366,6 +416,7 @@ LLVM_DUMP_METHOD void DeclarationName::dump() const {
|
||||||
DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) {
|
DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) {
|
||||||
CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>;
|
CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>;
|
||||||
CXXLiteralOperatorNames = new llvm::FoldingSet<CXXLiteralOperatorIdName>;
|
CXXLiteralOperatorNames = new llvm::FoldingSet<CXXLiteralOperatorIdName>;
|
||||||
|
CXXDeductionGuideNames = new llvm::FoldingSet<CXXDeductionGuideNameExtra>;
|
||||||
|
|
||||||
// Initialize the overloaded operator names.
|
// Initialize the overloaded operator names.
|
||||||
CXXOperatorNames = new (Ctx) CXXOperatorIdName[NUM_OVERLOADED_OPERATORS];
|
CXXOperatorNames = new (Ctx) CXXOperatorIdName[NUM_OVERLOADED_OPERATORS];
|
||||||
|
@ -377,14 +428,18 @@ DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) {
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclarationNameTable::~DeclarationNameTable() {
|
DeclarationNameTable::~DeclarationNameTable() {
|
||||||
llvm::FoldingSet<CXXSpecialName> *SpecialNames =
|
auto *SpecialNames =
|
||||||
static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl);
|
static_cast<llvm::FoldingSet<CXXSpecialName> *>(CXXSpecialNamesImpl);
|
||||||
llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames
|
auto *LiteralNames =
|
||||||
= static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*>
|
static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName> *>(
|
||||||
(CXXLiteralOperatorNames);
|
CXXLiteralOperatorNames);
|
||||||
|
auto *DeductionGuideNames =
|
||||||
|
static_cast<llvm::FoldingSet<CXXDeductionGuideNameExtra> *>(
|
||||||
|
CXXDeductionGuideNames);
|
||||||
|
|
||||||
delete SpecialNames;
|
delete SpecialNames;
|
||||||
delete LiteralNames;
|
delete LiteralNames;
|
||||||
|
delete DeductionGuideNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclarationName DeclarationNameTable::getCXXConstructorName(CanQualType Ty) {
|
DeclarationName DeclarationNameTable::getCXXConstructorName(CanQualType Ty) {
|
||||||
|
@ -397,6 +452,30 @@ DeclarationName DeclarationNameTable::getCXXDestructorName(CanQualType Ty) {
|
||||||
Ty.getUnqualifiedType());
|
Ty.getUnqualifiedType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeclarationName
|
||||||
|
DeclarationNameTable::getCXXDeductionGuideName(TemplateDecl *Template) {
|
||||||
|
Template = cast<TemplateDecl>(Template->getCanonicalDecl());
|
||||||
|
|
||||||
|
auto *DeductionGuideNames =
|
||||||
|
static_cast<llvm::FoldingSet<CXXDeductionGuideNameExtra> *>(
|
||||||
|
CXXDeductionGuideNames);
|
||||||
|
|
||||||
|
llvm::FoldingSetNodeID ID;
|
||||||
|
ID.AddPointer(Template);
|
||||||
|
|
||||||
|
void *InsertPos = nullptr;
|
||||||
|
if (auto *Name = DeductionGuideNames->FindNodeOrInsertPos(ID, InsertPos))
|
||||||
|
return DeclarationName(Name);
|
||||||
|
|
||||||
|
auto *Name = new (Ctx) CXXDeductionGuideNameExtra;
|
||||||
|
Name->ExtraKindOrNumArgs = DeclarationNameExtra::CXXDeductionGuide;
|
||||||
|
Name->Template = Template;
|
||||||
|
Name->FETokenInfo = nullptr;
|
||||||
|
|
||||||
|
DeductionGuideNames->InsertNode(Name, InsertPos);
|
||||||
|
return DeclarationName(Name);
|
||||||
|
}
|
||||||
|
|
||||||
DeclarationName
|
DeclarationName
|
||||||
DeclarationNameTable::getCXXConversionFunctionName(CanQualType Ty) {
|
DeclarationNameTable::getCXXConversionFunctionName(CanQualType Ty) {
|
||||||
return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty);
|
return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty);
|
||||||
|
@ -477,6 +556,7 @@ DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) {
|
||||||
DeclarationNameLoc::DeclarationNameLoc(DeclarationName Name) {
|
DeclarationNameLoc::DeclarationNameLoc(DeclarationName Name) {
|
||||||
switch (Name.getNameKind()) {
|
switch (Name.getNameKind()) {
|
||||||
case DeclarationName::Identifier:
|
case DeclarationName::Identifier:
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
break;
|
break;
|
||||||
case DeclarationName::CXXConstructorName:
|
case DeclarationName::CXXConstructorName:
|
||||||
case DeclarationName::CXXDestructorName:
|
case DeclarationName::CXXDestructorName:
|
||||||
|
@ -509,6 +589,7 @@ bool DeclarationNameInfo::containsUnexpandedParameterPack() const {
|
||||||
case DeclarationName::CXXOperatorName:
|
case DeclarationName::CXXOperatorName:
|
||||||
case DeclarationName::CXXLiteralOperatorName:
|
case DeclarationName::CXXLiteralOperatorName:
|
||||||
case DeclarationName::CXXUsingDirective:
|
case DeclarationName::CXXUsingDirective:
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case DeclarationName::CXXConstructorName:
|
case DeclarationName::CXXConstructorName:
|
||||||
|
@ -531,6 +612,7 @@ bool DeclarationNameInfo::isInstantiationDependent() const {
|
||||||
case DeclarationName::CXXOperatorName:
|
case DeclarationName::CXXOperatorName:
|
||||||
case DeclarationName::CXXLiteralOperatorName:
|
case DeclarationName::CXXLiteralOperatorName:
|
||||||
case DeclarationName::CXXUsingDirective:
|
case DeclarationName::CXXUsingDirective:
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case DeclarationName::CXXConstructorName:
|
case DeclarationName::CXXConstructorName:
|
||||||
|
@ -560,6 +642,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
|
||||||
case DeclarationName::CXXOperatorName:
|
case DeclarationName::CXXOperatorName:
|
||||||
case DeclarationName::CXXLiteralOperatorName:
|
case DeclarationName::CXXLiteralOperatorName:
|
||||||
case DeclarationName::CXXUsingDirective:
|
case DeclarationName::CXXUsingDirective:
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
OS << Name;
|
OS << Name;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -585,6 +668,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
|
||||||
SourceLocation DeclarationNameInfo::getEndLoc() const {
|
SourceLocation DeclarationNameInfo::getEndLoc() const {
|
||||||
switch (Name.getNameKind()) {
|
switch (Name.getNameKind()) {
|
||||||
case DeclarationName::Identifier:
|
case DeclarationName::Identifier:
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
return NameLoc;
|
return NameLoc;
|
||||||
|
|
||||||
case DeclarationName::CXXOperatorName: {
|
case DeclarationName::CXXOperatorName: {
|
||||||
|
|
|
@ -1190,6 +1190,8 @@ void CXXNameMangler::mangleUnresolvedName(
|
||||||
llvm_unreachable("Can't mangle a constructor name!");
|
llvm_unreachable("Can't mangle a constructor name!");
|
||||||
case DeclarationName::CXXUsingDirective:
|
case DeclarationName::CXXUsingDirective:
|
||||||
llvm_unreachable("Can't mangle a using directive name!");
|
llvm_unreachable("Can't mangle a using directive name!");
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
|
llvm_unreachable("Can't mangle a deduction guide name!");
|
||||||
case DeclarationName::ObjCMultiArgSelector:
|
case DeclarationName::ObjCMultiArgSelector:
|
||||||
case DeclarationName::ObjCOneArgSelector:
|
case DeclarationName::ObjCOneArgSelector:
|
||||||
case DeclarationName::ObjCZeroArgSelector:
|
case DeclarationName::ObjCZeroArgSelector:
|
||||||
|
@ -1419,6 +1421,9 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
|
||||||
writeAbiTags(ND, AdditionalAbiTags);
|
writeAbiTags(ND, AdditionalAbiTags);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
|
llvm_unreachable("Can't mangle a deduction guide name!");
|
||||||
|
|
||||||
case DeclarationName::CXXUsingDirective:
|
case DeclarationName::CXXUsingDirective:
|
||||||
llvm_unreachable("Can't mangle a using directive name!");
|
llvm_unreachable("Can't mangle a using directive name!");
|
||||||
}
|
}
|
||||||
|
@ -1997,6 +2002,7 @@ void CXXNameMangler::mangleOperatorName(DeclarationName Name, unsigned Arity) {
|
||||||
switch (Name.getNameKind()) {
|
switch (Name.getNameKind()) {
|
||||||
case DeclarationName::CXXConstructorName:
|
case DeclarationName::CXXConstructorName:
|
||||||
case DeclarationName::CXXDestructorName:
|
case DeclarationName::CXXDestructorName:
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
case DeclarationName::CXXUsingDirective:
|
case DeclarationName::CXXUsingDirective:
|
||||||
case DeclarationName::Identifier:
|
case DeclarationName::Identifier:
|
||||||
case DeclarationName::ObjCMultiArgSelector:
|
case DeclarationName::ObjCMultiArgSelector:
|
||||||
|
|
|
@ -942,6 +942,9 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
|
llvm_unreachable("Can't mangle a deduction guide name!");
|
||||||
|
|
||||||
case DeclarationName::CXXUsingDirective:
|
case DeclarationName::CXXUsingDirective:
|
||||||
llvm_unreachable("Can't mangle a using directive name!");
|
llvm_unreachable("Can't mangle a using directive name!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -3025,6 +3025,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
||||||
isConstructorDeclarator(/*Unqualified*/true))
|
isConstructorDeclarator(/*Unqualified*/true))
|
||||||
goto DoneWithDeclSpec;
|
goto DoneWithDeclSpec;
|
||||||
|
|
||||||
|
// Likewise, if this is a context where the identifier could be a template
|
||||||
|
// name, check whether this is a deduction guide declaration.
|
||||||
|
if (getLangOpts().CPlusPlus1z &&
|
||||||
|
(DSContext == DSC_class || DSContext == DSC_top_level) &&
|
||||||
|
Actions.isDeductionGuideName(getCurScope(), *Tok.getIdentifierInfo(),
|
||||||
|
Tok.getLocation()) &&
|
||||||
|
isConstructorDeclarator(/*Unqualified*/ true,
|
||||||
|
/*DeductionGuide*/ true))
|
||||||
|
goto DoneWithDeclSpec;
|
||||||
|
|
||||||
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
|
isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
|
||||||
DiagID, TypeRep, Policy);
|
DiagID, TypeRep, Policy);
|
||||||
if (isInvalid)
|
if (isInvalid)
|
||||||
|
@ -4644,7 +4654,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Parser::isConstructorDeclarator(bool IsUnqualified) {
|
bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) {
|
||||||
TentativeParsingAction TPA(*this);
|
TentativeParsingAction TPA(*this);
|
||||||
|
|
||||||
// Parse the C++ scope specifier.
|
// Parse the C++ scope specifier.
|
||||||
|
@ -4732,6 +4742,11 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) {
|
||||||
|
|
||||||
case tok::r_paren:
|
case tok::r_paren:
|
||||||
// C(X )
|
// C(X )
|
||||||
|
if (DeductionGuide) {
|
||||||
|
// C(X) -> ... is a deduction guide.
|
||||||
|
IsConstructor = NextToken().is(tok::arrow);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (NextToken().is(tok::colon) || NextToken().is(tok::kw_try)) {
|
if (NextToken().is(tok::colon) || NextToken().is(tok::kw_try)) {
|
||||||
// Assume these were meant to be constructors:
|
// Assume these were meant to be constructors:
|
||||||
// C(X) : (the name of a bit-field cannot be parenthesized).
|
// C(X) : (the name of a bit-field cannot be parenthesized).
|
||||||
|
@ -4749,7 +4764,7 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) {
|
||||||
//
|
//
|
||||||
// FIXME: We can actually do this whether or not the name is qualified,
|
// FIXME: We can actually do this whether or not the name is qualified,
|
||||||
// because if it is qualified in this context it must be being used as
|
// because if it is qualified in this context it must be being used as
|
||||||
// a constructor name. However, we do not implement that rule correctly
|
// a constructor name.
|
||||||
// currently, so we're somewhat conservative here.
|
// currently, so we're somewhat conservative here.
|
||||||
IsConstructor = IsUnqualified;
|
IsConstructor = IsUnqualified;
|
||||||
}
|
}
|
||||||
|
@ -5280,21 +5295,29 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
|
||||||
// We found something that indicates the start of an unqualified-id.
|
// We found something that indicates the start of an unqualified-id.
|
||||||
// Parse that unqualified-id.
|
// Parse that unqualified-id.
|
||||||
bool AllowConstructorName;
|
bool AllowConstructorName;
|
||||||
if (D.getDeclSpec().hasTypeSpecifier())
|
bool AllowDeductionGuide;
|
||||||
|
if (D.getDeclSpec().hasTypeSpecifier()) {
|
||||||
AllowConstructorName = false;
|
AllowConstructorName = false;
|
||||||
else if (D.getCXXScopeSpec().isSet())
|
AllowDeductionGuide = false;
|
||||||
|
} else if (D.getCXXScopeSpec().isSet()) {
|
||||||
AllowConstructorName =
|
AllowConstructorName =
|
||||||
(D.getContext() == Declarator::FileContext ||
|
(D.getContext() == Declarator::FileContext ||
|
||||||
D.getContext() == Declarator::MemberContext);
|
D.getContext() == Declarator::MemberContext);
|
||||||
else
|
AllowDeductionGuide = false;
|
||||||
|
} else {
|
||||||
AllowConstructorName = (D.getContext() == Declarator::MemberContext);
|
AllowConstructorName = (D.getContext() == Declarator::MemberContext);
|
||||||
|
AllowDeductionGuide =
|
||||||
|
(D.getContext() == Declarator::FileContext ||
|
||||||
|
D.getContext() == Declarator::MemberContext);
|
||||||
|
}
|
||||||
|
|
||||||
SourceLocation TemplateKWLoc;
|
SourceLocation TemplateKWLoc;
|
||||||
bool HadScope = D.getCXXScopeSpec().isValid();
|
bool HadScope = D.getCXXScopeSpec().isValid();
|
||||||
if (ParseUnqualifiedId(D.getCXXScopeSpec(),
|
if (ParseUnqualifiedId(D.getCXXScopeSpec(),
|
||||||
/*EnteringContext=*/true,
|
/*EnteringContext=*/true,
|
||||||
/*AllowDestructorName=*/true, AllowConstructorName,
|
/*AllowDestructorName=*/true, AllowConstructorName,
|
||||||
nullptr, TemplateKWLoc, D.getName()) ||
|
AllowDeductionGuide, nullptr, TemplateKWLoc,
|
||||||
|
D.getName()) ||
|
||||||
// Once we're past the identifier, if the scope was bad, mark the
|
// Once we're past the identifier, if the scope was bad, mark the
|
||||||
// whole declarator bad.
|
// whole declarator bad.
|
||||||
D.getCXXScopeSpec().isInvalid()) {
|
D.getCXXScopeSpec().isInvalid()) {
|
||||||
|
|
|
@ -576,6 +576,7 @@ bool Parser::ParseUsingDeclarator(unsigned Context, UsingDeclarator &D) {
|
||||||
/*AllowDestructorName=*/true,
|
/*AllowDestructorName=*/true,
|
||||||
/*AllowConstructorName=*/!(Tok.is(tok::identifier) &&
|
/*AllowConstructorName=*/!(Tok.is(tok::identifier) &&
|
||||||
NextToken().is(tok::equal)),
|
NextToken().is(tok::equal)),
|
||||||
|
/*AllowDeductionGuide=*/false,
|
||||||
nullptr, D.TemplateKWLoc, D.Name))
|
nullptr, D.TemplateKWLoc, D.Name))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2426,8 +2427,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||||
// Try to parse an unqualified-id.
|
// Try to parse an unqualified-id.
|
||||||
SourceLocation TemplateKWLoc;
|
SourceLocation TemplateKWLoc;
|
||||||
UnqualifiedId Name;
|
UnqualifiedId Name;
|
||||||
if (ParseUnqualifiedId(SS, false, true, true, nullptr, TemplateKWLoc,
|
if (ParseUnqualifiedId(SS, false, true, true, false, nullptr,
|
||||||
Name)) {
|
TemplateKWLoc, Name)) {
|
||||||
SkipUntil(tok::semi);
|
SkipUntil(tok::semi);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1693,6 +1693,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||||
/*AllowDestructorName=*/true,
|
/*AllowDestructorName=*/true,
|
||||||
/*AllowConstructorName=*/
|
/*AllowConstructorName=*/
|
||||||
getLangOpts().MicrosoftExt,
|
getLangOpts().MicrosoftExt,
|
||||||
|
/*AllowDeductionGuide=*/false,
|
||||||
ObjectType, TemplateKWLoc, Name)) {
|
ObjectType, TemplateKWLoc, Name)) {
|
||||||
(void)Actions.CorrectDelayedTyposInExpr(LHS);
|
(void)Actions.CorrectDelayedTyposInExpr(LHS);
|
||||||
LHS = ExprError();
|
LHS = ExprError();
|
||||||
|
|
|
@ -546,6 +546,7 @@ ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOpe
|
||||||
/*EnteringContext=*/false,
|
/*EnteringContext=*/false,
|
||||||
/*AllowDestructorName=*/false,
|
/*AllowDestructorName=*/false,
|
||||||
/*AllowConstructorName=*/false,
|
/*AllowConstructorName=*/false,
|
||||||
|
/*AllowDeductionGuide=*/false,
|
||||||
/*ObjectType=*/nullptr, TemplateKWLoc, Name))
|
/*ObjectType=*/nullptr, TemplateKWLoc, Name))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
|
@ -2429,6 +2430,8 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
|
||||||
///
|
///
|
||||||
/// \param AllowConstructorName whether we allow parsing a constructor name.
|
/// \param AllowConstructorName whether we allow parsing a constructor name.
|
||||||
///
|
///
|
||||||
|
/// \param AllowDeductionGuide whether we allow parsing a deduction guide name.
|
||||||
|
///
|
||||||
/// \param ObjectType if this unqualified-id occurs within a member access
|
/// \param ObjectType if this unqualified-id occurs within a member access
|
||||||
/// expression, the type of the base object whose member is being accessed.
|
/// expression, the type of the base object whose member is being accessed.
|
||||||
///
|
///
|
||||||
|
@ -2438,6 +2441,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
|
||||||
bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
|
bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
|
||||||
bool AllowDestructorName,
|
bool AllowDestructorName,
|
||||||
bool AllowConstructorName,
|
bool AllowConstructorName,
|
||||||
|
bool AllowDeductionGuide,
|
||||||
ParsedType ObjectType,
|
ParsedType ObjectType,
|
||||||
SourceLocation& TemplateKWLoc,
|
SourceLocation& TemplateKWLoc,
|
||||||
UnqualifiedId &Result) {
|
UnqualifiedId &Result) {
|
||||||
|
@ -2466,6 +2470,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParsedTemplateTy TemplateName;
|
||||||
if (AllowConstructorName &&
|
if (AllowConstructorName &&
|
||||||
Actions.isCurrentClassName(*Id, getCurScope(), &SS)) {
|
Actions.isCurrentClassName(*Id, getCurScope(), &SS)) {
|
||||||
// We have parsed a constructor name.
|
// We have parsed a constructor name.
|
||||||
|
@ -2474,6 +2479,12 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
|
||||||
/*IsCtorOrDtorName=*/true,
|
/*IsCtorOrDtorName=*/true,
|
||||||
/*NonTrivialTypeSourceInfo=*/true);
|
/*NonTrivialTypeSourceInfo=*/true);
|
||||||
Result.setConstructorName(Ty, IdLoc, IdLoc);
|
Result.setConstructorName(Ty, IdLoc, IdLoc);
|
||||||
|
} else if (getLangOpts().CPlusPlus1z &&
|
||||||
|
AllowDeductionGuide && SS.isEmpty() &&
|
||||||
|
Actions.isDeductionGuideName(getCurScope(), *Id, IdLoc,
|
||||||
|
&TemplateName)) {
|
||||||
|
// We have parsed a template-name naming a deduction guide.
|
||||||
|
Result.setDeductionGuideName(TemplateName, IdLoc);
|
||||||
} else {
|
} else {
|
||||||
// We have parsed an identifier.
|
// We have parsed an identifier.
|
||||||
Result.setIdentifier(Id, IdLoc);
|
Result.setIdentifier(Id, IdLoc);
|
||||||
|
|
|
@ -1053,7 +1053,7 @@ bool Parser::ParseOpenMPSimpleVarList(
|
||||||
IsCorrect = false;
|
IsCorrect = false;
|
||||||
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
|
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
|
||||||
StopBeforeMatch);
|
StopBeforeMatch);
|
||||||
} else if (ParseUnqualifiedId(SS, false, false, false, nullptr,
|
} else if (ParseUnqualifiedId(SS, false, false, false, false, nullptr,
|
||||||
TemplateKWLoc, Name)) {
|
TemplateKWLoc, Name)) {
|
||||||
IsCorrect = false;
|
IsCorrect = false;
|
||||||
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
|
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
|
||||||
|
@ -1557,8 +1557,9 @@ static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
|
||||||
}
|
}
|
||||||
return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*EnteringContext*/ false,
|
return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*EnteringContext*/ false,
|
||||||
/*AllowDestructorName*/ false,
|
/*AllowDestructorName*/ false,
|
||||||
/*AllowConstructorName*/ false, nullptr,
|
/*AllowConstructorName*/ false,
|
||||||
TemplateKWLoc, ReductionId);
|
/*AllowDeductionGuide*/ false,
|
||||||
|
nullptr, TemplateKWLoc, ReductionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses clauses with list.
|
/// Parses clauses with list.
|
||||||
|
|
|
@ -224,6 +224,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks,
|
||||||
/*EnteringContext=*/false,
|
/*EnteringContext=*/false,
|
||||||
/*AllowDestructorName=*/false,
|
/*AllowDestructorName=*/false,
|
||||||
/*AllowConstructorName=*/false,
|
/*AllowConstructorName=*/false,
|
||||||
|
/*AllowDeductionGuide=*/false,
|
||||||
/*ObjectType=*/nullptr, TemplateKWLoc, Id);
|
/*ObjectType=*/nullptr, TemplateKWLoc, Id);
|
||||||
// Perform the lookup.
|
// Perform the lookup.
|
||||||
Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info,
|
Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info,
|
||||||
|
|
|
@ -1966,8 +1966,10 @@ bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) {
|
||||||
|
|
||||||
// Parse the unqualified-id.
|
// Parse the unqualified-id.
|
||||||
SourceLocation TemplateKWLoc; // FIXME: parsed, but unused.
|
SourceLocation TemplateKWLoc; // FIXME: parsed, but unused.
|
||||||
if (ParseUnqualifiedId(Result.SS, false, true, true, nullptr, TemplateKWLoc,
|
if (ParseUnqualifiedId(
|
||||||
Result.Name)) {
|
Result.SS, /*EnteringContext*/false, /*AllowDestructorName*/true,
|
||||||
|
/*AllowConstructorName*/true, /*AllowDeductionGuide*/false, nullptr,
|
||||||
|
TemplateKWLoc, Result.Name)) {
|
||||||
T.skipToEnd();
|
T.skipToEnd();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2585,6 +2585,7 @@ static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,
|
||||||
Result.getAllocator().CopyString(ND->getNameAsString()));
|
Result.getAllocator().CopyString(ND->getNameAsString()));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
case DeclarationName::CXXUsingDirective:
|
case DeclarationName::CXXUsingDirective:
|
||||||
case DeclarationName::ObjCZeroArgSelector:
|
case DeclarationName::ObjCZeroArgSelector:
|
||||||
case DeclarationName::ObjCOneArgSelector:
|
case DeclarationName::ObjCOneArgSelector:
|
||||||
|
|
|
@ -4675,6 +4675,34 @@ Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) {
|
||||||
NameInfo.setLoc(Name.StartLocation);
|
NameInfo.setLoc(Name.StartLocation);
|
||||||
return NameInfo;
|
return NameInfo;
|
||||||
|
|
||||||
|
case UnqualifiedId::IK_DeductionGuideName: {
|
||||||
|
// C++ [temp.deduct.guide]p3:
|
||||||
|
// The simple-template-id shall name a class template specialization.
|
||||||
|
// The template-name shall be the same identifier as the template-name
|
||||||
|
// of the simple-template-id.
|
||||||
|
// These together intend to imply that the template-name shall name a
|
||||||
|
// class template.
|
||||||
|
// FIXME: template<typename T> struct X {};
|
||||||
|
// template<typename T> using Y = X<T>;
|
||||||
|
// Y(int) -> Y<int>;
|
||||||
|
// satisfies these rules but does not name a class template.
|
||||||
|
TemplateName TN = Name.TemplateName.get().get();
|
||||||
|
auto *Template = TN.getAsTemplateDecl();
|
||||||
|
if (!Template || !isa<ClassTemplateDecl>(Template)) {
|
||||||
|
Diag(Name.StartLocation,
|
||||||
|
diag::err_deduction_guide_name_not_class_template)
|
||||||
|
<< (int)getTemplateNameKindForDiagnostics(TN) << TN;
|
||||||
|
if (Template)
|
||||||
|
Diag(Template->getLocation(), diag::note_template_decl_here);
|
||||||
|
return DeclarationNameInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
NameInfo.setName(
|
||||||
|
Context.DeclarationNames.getCXXDeductionGuideName(Template));
|
||||||
|
NameInfo.setLoc(Name.StartLocation);
|
||||||
|
return NameInfo;
|
||||||
|
}
|
||||||
|
|
||||||
case UnqualifiedId::IK_OperatorFunctionId:
|
case UnqualifiedId::IK_OperatorFunctionId:
|
||||||
NameInfo.setName(Context.DeclarationNames.getCXXOperatorName(
|
NameInfo.setName(Context.DeclarationNames.getCXXOperatorName(
|
||||||
Name.OperatorFunctionId.Operator));
|
Name.OperatorFunctionId.Operator));
|
||||||
|
@ -7621,6 +7649,15 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
|
||||||
R, TInfo, isInline, isExplicit,
|
R, TInfo, isInline, isExplicit,
|
||||||
isConstexpr, SourceLocation());
|
isConstexpr, SourceLocation());
|
||||||
|
|
||||||
|
} else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
|
||||||
|
SemaRef.CheckDeductionGuideDeclarator(D, R, SC);
|
||||||
|
|
||||||
|
// We don't need to store any extra information for a deduction guide, so
|
||||||
|
// just model it as a plain FunctionDecl.
|
||||||
|
return FunctionDecl::Create(SemaRef.Context, DC,
|
||||||
|
D.getLocStart(),
|
||||||
|
NameInfo, R, TInfo, SC, isInline,
|
||||||
|
true/*HasPrototype*/, isConstexpr);
|
||||||
} else if (DC->isRecord()) {
|
} else if (DC->isRecord()) {
|
||||||
// If the name of the function is the same as the name of the record,
|
// If the name of the function is the same as the name of the record,
|
||||||
// then this must be an invalid constructor that has a return type.
|
// then this must be an invalid constructor that has a return type.
|
||||||
|
@ -8109,7 +8146,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
// The explicit specifier shall be used only in the declaration of a
|
// The explicit specifier shall be used only in the declaration of a
|
||||||
// constructor or conversion function within its class definition;
|
// constructor or conversion function within its class definition;
|
||||||
// see 12.3.1 and 12.3.2.
|
// see 12.3.1 and 12.3.2.
|
||||||
if (isExplicit && !NewFD->isInvalidDecl()) {
|
if (isExplicit && !NewFD->isInvalidDecl() && !NewFD->isDeductionGuide()) {
|
||||||
if (!CurContext->isRecord()) {
|
if (!CurContext->isRecord()) {
|
||||||
// 'explicit' was specified outside of the class.
|
// 'explicit' was specified outside of the class.
|
||||||
Diag(D.getDeclSpec().getExplicitSpecLoc(),
|
Diag(D.getDeclSpec().getExplicitSpecLoc(),
|
||||||
|
|
|
@ -8033,6 +8033,15 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
|
||||||
return Conversion;
|
return Conversion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check the validity of a declarator that we parsed for a deduction-guide.
|
||||||
|
/// These aren't actually declarators in the grammar, so we need to check that
|
||||||
|
/// the user didn't specify any pieces that are not part of the deduction-guide
|
||||||
|
/// grammar.
|
||||||
|
void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
|
||||||
|
StorageClass &SC) {
|
||||||
|
// FIXME: Implement
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Namespace Handling
|
// Namespace Handling
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -8613,6 +8622,9 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
|
||||||
Diag(Name.getLocStart(), diag::err_using_decl_template_id)
|
Diag(Name.getLocStart(), diag::err_using_decl_template_id)
|
||||||
<< SourceRange(Name.TemplateId->LAngleLoc, Name.TemplateId->RAngleLoc);
|
<< SourceRange(Name.TemplateId->LAngleLoc, Name.TemplateId->RAngleLoc);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
case UnqualifiedId::IK_DeductionGuideName:
|
||||||
|
llvm_unreachable("cannot parse qualified deduction guide name");
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name);
|
DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name);
|
||||||
|
@ -13747,6 +13759,9 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
|
||||||
case UnqualifiedId::IK_ConversionFunctionId:
|
case UnqualifiedId::IK_ConversionFunctionId:
|
||||||
DiagArg = 2;
|
DiagArg = 2;
|
||||||
break;
|
break;
|
||||||
|
case UnqualifiedId::IK_DeductionGuideName:
|
||||||
|
DiagArg = 3;
|
||||||
|
break;
|
||||||
case UnqualifiedId::IK_Identifier:
|
case UnqualifiedId::IK_Identifier:
|
||||||
case UnqualifiedId::IK_ImplicitSelfParam:
|
case UnqualifiedId::IK_ImplicitSelfParam:
|
||||||
case UnqualifiedId::IK_LiteralOperatorId:
|
case UnqualifiedId::IK_LiteralOperatorId:
|
||||||
|
|
|
@ -321,6 +321,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo,
|
||||||
case DeclarationName::CXXOperatorName:
|
case DeclarationName::CXXOperatorName:
|
||||||
case DeclarationName::CXXLiteralOperatorName:
|
case DeclarationName::CXXLiteralOperatorName:
|
||||||
case DeclarationName::CXXUsingDirective:
|
case DeclarationName::CXXUsingDirective:
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case DeclarationName::CXXConstructorName:
|
case DeclarationName::CXXConstructorName:
|
||||||
|
|
|
@ -2733,6 +2733,17 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
|
||||||
D.getDeclSpec().getAttributes().getList());
|
D.getDeclSpec().getAttributes().getList());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case UnqualifiedId::IK_DeductionGuideName:
|
||||||
|
// Deduction guides have a trailing return type and no type in their
|
||||||
|
// decl-specifier sequence.
|
||||||
|
T = SemaRef.Context.getAutoDeductType();
|
||||||
|
if (!D.hasTrailingReturnType()) {
|
||||||
|
SemaRef.Diag(D.getName().getLocStart(),
|
||||||
|
diag::err_deduction_guide_no_trailing_return_type);
|
||||||
|
D.setInvalidType(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case UnqualifiedId::IK_ConversionFunctionId:
|
case UnqualifiedId::IK_ConversionFunctionId:
|
||||||
// The result type of a conversion function is the type that it
|
// The result type of a conversion function is the type that it
|
||||||
// converts to.
|
// converts to.
|
||||||
|
@ -2884,20 +2895,10 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
|
||||||
// better diagnostics.
|
// better diagnostics.
|
||||||
// We don't support '__auto_type' with trailing return types.
|
// We don't support '__auto_type' with trailing return types.
|
||||||
// FIXME: Should we only do this for 'auto' and not 'decltype(auto)'?
|
// FIXME: Should we only do this for 'auto' and not 'decltype(auto)'?
|
||||||
if (SemaRef.getLangOpts().CPlusPlus11 && IsCXXAutoType) {
|
if (SemaRef.getLangOpts().CPlusPlus11 && IsCXXAutoType &&
|
||||||
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
|
D.hasTrailingReturnType()) {
|
||||||
unsigned chunkIndex = e - i - 1;
|
HaveTrailing = true;
|
||||||
state.setCurrentChunkIndex(chunkIndex);
|
Error = -1;
|
||||||
DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);
|
|
||||||
if (DeclType.Kind == DeclaratorChunk::Function) {
|
|
||||||
const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
|
|
||||||
if (FTI.hasTrailingReturnType()) {
|
|
||||||
HaveTrailing = true;
|
|
||||||
Error = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceRange AutoRange = D.getDeclSpec().getTypeSpecTypeLoc();
|
SourceRange AutoRange = D.getDeclSpec().getTypeSpecTypeLoc();
|
||||||
|
@ -4176,16 +4177,22 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
||||||
} else if (FTI.hasTrailingReturnType()) {
|
} else if (FTI.hasTrailingReturnType()) {
|
||||||
// T must be exactly 'auto' at this point. See CWG issue 681.
|
// T must be exactly 'auto' at this point. See CWG issue 681.
|
||||||
if (isa<ParenType>(T)) {
|
if (isa<ParenType>(T)) {
|
||||||
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
|
S.Diag(D.getLocStart(),
|
||||||
diag::err_trailing_return_in_parens)
|
diag::err_trailing_return_in_parens)
|
||||||
<< T << D.getDeclSpec().getSourceRange();
|
<< T << D.getSourceRange();
|
||||||
D.setInvalidType(true);
|
D.setInvalidType(true);
|
||||||
} else if (D.getContext() != Declarator::LambdaExprContext &&
|
} else if (D.getContext() != Declarator::LambdaExprContext &&
|
||||||
(T.hasQualifiers() || !isa<AutoType>(T) ||
|
(T.hasQualifiers() || !isa<AutoType>(T) ||
|
||||||
cast<AutoType>(T)->getKeyword() != AutoTypeKeyword::Auto)) {
|
cast<AutoType>(T)->getKeyword() !=
|
||||||
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
|
AutoTypeKeyword::Auto)) {
|
||||||
diag::err_trailing_return_without_auto)
|
if (D.getName().getKind() == UnqualifiedId::IK_DeductionGuideName)
|
||||||
<< T << D.getDeclSpec().getSourceRange();
|
S.Diag(D.getDeclSpec().getLocStart(),
|
||||||
|
diag::err_deduction_guide_with_complex_decl)
|
||||||
|
<< D.getSourceRange();
|
||||||
|
else
|
||||||
|
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
|
||||||
|
diag::err_trailing_return_without_auto)
|
||||||
|
<< T << D.getDeclSpec().getSourceRange();
|
||||||
D.setInvalidType(true);
|
D.setInvalidType(true);
|
||||||
}
|
}
|
||||||
T = S.GetTypeFromParser(FTI.getTrailingReturnType(), &TInfo);
|
T = S.GetTypeFromParser(FTI.getTrailingReturnType(), &TInfo);
|
||||||
|
|
|
@ -3617,6 +3617,19 @@ TreeTransform<Derived>
|
||||||
case DeclarationName::CXXUsingDirective:
|
case DeclarationName::CXXUsingDirective:
|
||||||
return NameInfo;
|
return NameInfo;
|
||||||
|
|
||||||
|
case DeclarationName::CXXDeductionGuideName: {
|
||||||
|
TemplateDecl *OldTemplate = Name.getCXXDeductionGuideTemplate();
|
||||||
|
TemplateDecl *NewTemplate = cast_or_null<TemplateDecl>(
|
||||||
|
getDerived().TransformDecl(NameInfo.getLoc(), OldTemplate));
|
||||||
|
if (!NewTemplate)
|
||||||
|
return DeclarationNameInfo();
|
||||||
|
|
||||||
|
DeclarationNameInfo NewNameInfo(NameInfo);
|
||||||
|
NewNameInfo.setName(
|
||||||
|
SemaRef.Context.DeclarationNames.getCXXDeductionGuideName(NewTemplate));
|
||||||
|
return NewNameInfo;
|
||||||
|
}
|
||||||
|
|
||||||
case DeclarationName::CXXConstructorName:
|
case DeclarationName::CXXConstructorName:
|
||||||
case DeclarationName::CXXDestructorName:
|
case DeclarationName::CXXDestructorName:
|
||||||
case DeclarationName::CXXConversionFunctionName: {
|
case DeclarationName::CXXConversionFunctionName: {
|
||||||
|
|
|
@ -944,6 +944,10 @@ DeclarationNameKey::DeclarationNameKey(DeclarationName Name)
|
||||||
case DeclarationName::CXXLiteralOperatorName:
|
case DeclarationName::CXXLiteralOperatorName:
|
||||||
Data = (uint64_t)Name.getCXXLiteralIdentifier();
|
Data = (uint64_t)Name.getCXXLiteralIdentifier();
|
||||||
break;
|
break;
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
|
Data = (uint64_t)Name.getCXXDeductionGuideTemplate()
|
||||||
|
->getDeclName().getAsIdentifierInfo();
|
||||||
|
break;
|
||||||
case DeclarationName::CXXConstructorName:
|
case DeclarationName::CXXConstructorName:
|
||||||
case DeclarationName::CXXDestructorName:
|
case DeclarationName::CXXDestructorName:
|
||||||
case DeclarationName::CXXConversionFunctionName:
|
case DeclarationName::CXXConversionFunctionName:
|
||||||
|
@ -960,6 +964,7 @@ unsigned DeclarationNameKey::getHash() const {
|
||||||
switch (Kind) {
|
switch (Kind) {
|
||||||
case DeclarationName::Identifier:
|
case DeclarationName::Identifier:
|
||||||
case DeclarationName::CXXLiteralOperatorName:
|
case DeclarationName::CXXLiteralOperatorName:
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
ID.AddString(((IdentifierInfo*)Data)->getName());
|
ID.AddString(((IdentifierInfo*)Data)->getName());
|
||||||
break;
|
break;
|
||||||
case DeclarationName::ObjCZeroArgSelector:
|
case DeclarationName::ObjCZeroArgSelector:
|
||||||
|
@ -1003,6 +1008,8 @@ ASTDeclContextNameLookupTrait::ReadKey(const unsigned char *d, unsigned) {
|
||||||
uint64_t Data;
|
uint64_t Data;
|
||||||
switch (Kind) {
|
switch (Kind) {
|
||||||
case DeclarationName::Identifier:
|
case DeclarationName::Identifier:
|
||||||
|
case DeclarationName::CXXLiteralOperatorName:
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
Data = (uint64_t)Reader.getLocalIdentifier(
|
Data = (uint64_t)Reader.getLocalIdentifier(
|
||||||
F, endian::readNext<uint32_t, little, unaligned>(d));
|
F, endian::readNext<uint32_t, little, unaligned>(d));
|
||||||
break;
|
break;
|
||||||
|
@ -1017,10 +1024,6 @@ ASTDeclContextNameLookupTrait::ReadKey(const unsigned char *d, unsigned) {
|
||||||
case DeclarationName::CXXOperatorName:
|
case DeclarationName::CXXOperatorName:
|
||||||
Data = *d++; // OverloadedOperatorKind
|
Data = *d++; // OverloadedOperatorKind
|
||||||
break;
|
break;
|
||||||
case DeclarationName::CXXLiteralOperatorName:
|
|
||||||
Data = (uint64_t)Reader.getLocalIdentifier(
|
|
||||||
F, endian::readNext<uint32_t, little, unaligned>(d));
|
|
||||||
break;
|
|
||||||
case DeclarationName::CXXConstructorName:
|
case DeclarationName::CXXConstructorName:
|
||||||
case DeclarationName::CXXDestructorName:
|
case DeclarationName::CXXDestructorName:
|
||||||
case DeclarationName::CXXConversionFunctionName:
|
case DeclarationName::CXXConversionFunctionName:
|
||||||
|
@ -7992,6 +7995,10 @@ ASTReader::ReadDeclarationName(ModuleFile &F,
|
||||||
return Context.DeclarationNames.getCXXDestructorName(
|
return Context.DeclarationNames.getCXXDestructorName(
|
||||||
Context.getCanonicalType(readType(F, Record, Idx)));
|
Context.getCanonicalType(readType(F, Record, Idx)));
|
||||||
|
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
|
return Context.DeclarationNames.getCXXDeductionGuideName(
|
||||||
|
ReadDeclAs<TemplateDecl>(F, Record, Idx));
|
||||||
|
|
||||||
case DeclarationName::CXXConversionFunctionName:
|
case DeclarationName::CXXConversionFunctionName:
|
||||||
return Context.DeclarationNames.getCXXConversionFunctionName(
|
return Context.DeclarationNames.getCXXConversionFunctionName(
|
||||||
Context.getCanonicalType(readType(F, Record, Idx)));
|
Context.getCanonicalType(readType(F, Record, Idx)));
|
||||||
|
@ -8039,6 +8046,7 @@ void ASTReader::ReadDeclarationNameLoc(ModuleFile &F,
|
||||||
case DeclarationName::ObjCOneArgSelector:
|
case DeclarationName::ObjCOneArgSelector:
|
||||||
case DeclarationName::ObjCMultiArgSelector:
|
case DeclarationName::ObjCMultiArgSelector:
|
||||||
case DeclarationName::CXXUsingDirective:
|
case DeclarationName::CXXUsingDirective:
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3600,6 +3600,7 @@ public:
|
||||||
case DeclarationName::ObjCOneArgSelector:
|
case DeclarationName::ObjCOneArgSelector:
|
||||||
case DeclarationName::ObjCMultiArgSelector:
|
case DeclarationName::ObjCMultiArgSelector:
|
||||||
case DeclarationName::CXXLiteralOperatorName:
|
case DeclarationName::CXXLiteralOperatorName:
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
KeyLen += 4;
|
KeyLen += 4;
|
||||||
break;
|
break;
|
||||||
case DeclarationName::CXXOperatorName:
|
case DeclarationName::CXXOperatorName:
|
||||||
|
@ -3629,6 +3630,7 @@ public:
|
||||||
switch (Name.getKind()) {
|
switch (Name.getKind()) {
|
||||||
case DeclarationName::Identifier:
|
case DeclarationName::Identifier:
|
||||||
case DeclarationName::CXXLiteralOperatorName:
|
case DeclarationName::CXXLiteralOperatorName:
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
LE.write<uint32_t>(Writer.getIdentifierRef(Name.getIdentifier()));
|
LE.write<uint32_t>(Writer.getIdentifierRef(Name.getIdentifier()));
|
||||||
return;
|
return;
|
||||||
case DeclarationName::ObjCZeroArgSelector:
|
case DeclarationName::ObjCZeroArgSelector:
|
||||||
|
@ -5273,6 +5275,10 @@ void ASTRecordWriter::AddDeclarationName(DeclarationName Name) {
|
||||||
AddTypeRef(Name.getCXXNameType());
|
AddTypeRef(Name.getCXXNameType());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
|
AddDeclRef(Name.getCXXDeductionGuideTemplate());
|
||||||
|
break;
|
||||||
|
|
||||||
case DeclarationName::CXXOperatorName:
|
case DeclarationName::CXXOperatorName:
|
||||||
Record->push_back(Name.getCXXOverloadedOperator());
|
Record->push_back(Name.getCXXOverloadedOperator());
|
||||||
break;
|
break;
|
||||||
|
@ -5334,6 +5340,7 @@ void ASTRecordWriter::AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc,
|
||||||
case DeclarationName::ObjCOneArgSelector:
|
case DeclarationName::ObjCOneArgSelector:
|
||||||
case DeclarationName::ObjCMultiArgSelector:
|
case DeclarationName::ObjCMultiArgSelector:
|
||||||
case DeclarationName::CXXUsingDirective:
|
case DeclarationName::CXXUsingDirective:
|
||||||
|
case DeclarationName::CXXDeductionGuideName:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s
|
||||||
|
// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s -DCLASS
|
||||||
|
|
||||||
|
#ifdef CLASS
|
||||||
|
struct Outer {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<typename> struct A {};
|
||||||
|
|
||||||
|
// Valid forms.
|
||||||
|
A(int(&)[1]) -> A<int>;
|
||||||
|
explicit A(int(&)[2]) -> A<int>;
|
||||||
|
|
||||||
|
// Declarator pieces are not OK.
|
||||||
|
*A(int(&)[3]) -> A<int>; // expected-error {{cannot specify any part of a return type in the declaration of a deduction guide}}
|
||||||
|
&A(int(&)[4]) -> A<int>; // expected-error {{cannot specify any part of a return type in the declaration of a deduction guide}}
|
||||||
|
A(int(&)[5])[3] -> A<int>;
|
||||||
|
#ifdef CLASS // FIXME: These diagnostics are both pretty bad.
|
||||||
|
// expected-error@-2 {{deduction guide declaration without trailing return type}} expected-error@-2 {{array of 'auto'}} expected-error@-2 {{';'}}
|
||||||
|
#else
|
||||||
|
// expected-error@-4 {{expected function body after function declarator}}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// (Pending DR) attributes and parens around the declarator-id are OK.
|
||||||
|
[[deprecated]] A(int(&)[6]) [[]] -> A<int> [[]];
|
||||||
|
A [[]] (int(&)[7]) -> A<int>; // FIXME: expected-error 2{{expected}} expected-note {{to match}}
|
||||||
|
(A)(int(&)[8]) -> A<int>;
|
||||||
|
|
||||||
|
// ... but the trailing-return-type is part of the function-declarator as normal
|
||||||
|
(A(int(&)[9])) -> A<int>;
|
||||||
|
#ifdef CLASS // FIXME: These diagnostics are both pretty bad.
|
||||||
|
// expected-error@-2 {{deduction guide declaration without trailing return type}} expected-error@-2 {{';'}}
|
||||||
|
#else
|
||||||
|
// expected-error@-4 {{expected function body after function declarator}}
|
||||||
|
#endif
|
||||||
|
(A(int(&)[10]) -> A<int>); // expected-error {{trailing return type may not be nested within parentheses}}
|
||||||
|
|
||||||
|
// A trailing-return-type is mandatory.
|
||||||
|
A(int(&)[11]); // expected-error {{deduction guide declaration without trailing return type}}
|
||||||
|
|
||||||
|
// No type specifier is permitted; we don't even parse such cases as a deduction-guide.
|
||||||
|
int A(int) -> A<int>; // expected-error {{function with trailing return type must specify return type 'auto', not 'int'}}
|
||||||
|
template<typename T> struct B {}; // expected-note {{here}}
|
||||||
|
auto B(int) -> B<int>; // expected-error {{redefinition of 'B' as different kind of symbol}}
|
||||||
|
|
||||||
|
// FIXME: No storage class specifier, function specifier, ...
|
||||||
|
friend A(int(&)[20]) -> A<int>;
|
||||||
|
#ifdef CLASS
|
||||||
|
// expected-error@-2 {{cannot declare a deduction guide as a friend}}
|
||||||
|
#else
|
||||||
|
// expected-error@-4 {{'friend' used outside of class}}
|
||||||
|
#endif
|
||||||
|
typedef A(int(&)[21]) -> A<int>; // FIXME: Bad diagnostic: expected-error {{typedef name must be an identifier}}
|
||||||
|
constexpr A(int(&)[22]) -> A<int>;
|
||||||
|
inline A(int(&)[23]) -> A<int>;
|
||||||
|
static A(int(&)[24]) -> A<int>;
|
||||||
|
thread_local A(int(&)[25]) -> A<int>; // expected-error {{'thread_local' is only allowed on variable declarations}}
|
||||||
|
extern A(int(&)[26]) -> A<int>;
|
||||||
|
#ifdef CLASS
|
||||||
|
// expected-error@-2 {{storage class specified for a member}}
|
||||||
|
#endif
|
||||||
|
mutable A(int(&)[27]) -> A<int>; // expected-error-re {{{{'mutable' cannot be applied to|illegal storage class on}} function}}
|
||||||
|
virtual A(int(&)[28]) -> A<int>; // expected-error {{'virtual' can only appear on non-static member functions}}
|
||||||
|
|
||||||
|
// FIXME: No definition is allowed.
|
||||||
|
A(int(&)[30]) -> A<int> {}
|
||||||
|
A(int(&)[31]) -> A<int> = default; // expected-error {{only special member functions may be defaulted}}
|
||||||
|
A(int(&)[32]) -> A<int> = delete;
|
||||||
|
A(int(&)[33]) -> A<int> try {} catch (...) {}
|
||||||
|
|
||||||
|
#ifdef CLASS
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -0,0 +1,14 @@
|
||||||
|
// RUN: %clang_cc1 -std=c++1z -verify %s
|
||||||
|
|
||||||
|
namespace std_example {
|
||||||
|
template<typename T, typename U = int> struct S {
|
||||||
|
T data;
|
||||||
|
};
|
||||||
|
template<typename U> S(U) -> S<typename U::type>;
|
||||||
|
|
||||||
|
struct A {
|
||||||
|
using type = short;
|
||||||
|
operator type();
|
||||||
|
};
|
||||||
|
S x{A()}; // expected-error {{not yet supported}}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
// RUN: %clang_cc1 -std=c++1z %s -verify
|
||||||
|
|
||||||
|
// The same restrictions apply to the parameter-declaration-clause of a
|
||||||
|
// deduction guide as in a function declaration.
|
||||||
|
template<typename T> struct A {};
|
||||||
|
A(void) -> A<int>; // ok
|
||||||
|
A(void, int) -> A<int>; // expected-error {{'void' must be the first and only parameter if specified}}
|
||||||
|
|
||||||
|
// We interpret this as also extending to the validity of redeclarations. It's
|
||||||
|
// a bit of a stretch (OK, a lot of a stretch) but it gives desirable answers.
|
||||||
|
A() -> A<int>; // ok, redeclaration
|
||||||
|
|
||||||
|
A() -> A<int>; // expected-note {{previous}}
|
||||||
|
A() -> A<float>; // FIXME: "functions" is a poor term. expected-error {{functions that differ only in their return type cannot be overloaded}}
|
||||||
|
|
||||||
|
template<typename T> A(T) -> A<typename T::foo>;
|
||||||
|
template<typename T> A(T) -> A<typename T::bar>; // ok, can overload on return type (SFINAE applies)
|
||||||
|
|
||||||
|
A(long) -> A<int>;
|
||||||
|
template<typename T = int> A(long) -> A<char>; // ok, non-template beats template as usual
|
||||||
|
|
||||||
|
// (Pending DR) The template-name shall name a class template.
|
||||||
|
template<typename T> using B = A<T>; // expected-note {{template}}
|
||||||
|
B() -> B<int>; // expected-error {{cannot specify deduction guide for alias template 'B'}}
|
||||||
|
// FIXME: expected-error@-1 {{declarator requires an identifier}}
|
||||||
|
template<typename T> int C;
|
||||||
|
C() -> int; // expected-error {{requires a type specifier}}
|
||||||
|
template<typename T> void D();
|
||||||
|
D() -> int; // expected-error {{requires a type specifier}}
|
||||||
|
template<template<typename> typename TT> struct E { // expected-note 2{{template}}
|
||||||
|
// FIXME: Should only diagnose this once!
|
||||||
|
TT(int) -> TT<int>; // expected-error 2{{cannot specify deduction guide for template template parameter 'TT'}} expected-error {{requires an identifier}}
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: Even if the DR is applied as we hope, we should still warn if the
|
||||||
|
// trailing-return-type can obviously never produce a specialization of the
|
||||||
|
// named template.
|
||||||
|
A(int) -> int;
|
||||||
|
template<typename T> A(T) -> T*;
|
||||||
|
|
||||||
|
// A deduction-guide shall be declared in the same scope as the corresponding
|
||||||
|
// class template.
|
||||||
|
namespace WrongScope {
|
||||||
|
namespace {
|
||||||
|
template<typename T> struct AnonNS1 {};
|
||||||
|
AnonNS1(float) -> AnonNS1<float>; // ok
|
||||||
|
}
|
||||||
|
AnonNS1(int) -> AnonNS1<int>; // FIXME
|
||||||
|
template<typename T> struct AnonNS2 {};
|
||||||
|
namespace {
|
||||||
|
AnonNS1(char) -> AnonNS1<char>; // ok
|
||||||
|
AnonNS2(int) -> AnonNS2<int>; // FIXME
|
||||||
|
}
|
||||||
|
namespace N {
|
||||||
|
template<typename T> struct NamedNS1 {};
|
||||||
|
template<typename T> struct NamedNS2 {};
|
||||||
|
}
|
||||||
|
using N::NamedNS1;
|
||||||
|
NamedNS1(int) -> NamedNS1<int>; // FIXME
|
||||||
|
using namespace N;
|
||||||
|
NamedNS2(int) -> NamedNS2<int>; // FIXME
|
||||||
|
struct ClassMemberA {
|
||||||
|
template<typename T> struct X {};
|
||||||
|
};
|
||||||
|
struct ClassMemberB : ClassMemberA {
|
||||||
|
X(int) -> X<int>; // FIXME
|
||||||
|
};
|
||||||
|
template<typename T> struct Local {};
|
||||||
|
void f() {
|
||||||
|
Local(int) -> Local<int>; // expected-error 2{{expected}} expected-note {{to match}}
|
||||||
|
using WrongScope::Local;
|
||||||
|
Local(int) -> Local<int>; // expected-error 2{{expected}} expected-note {{to match}}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1265,10 +1265,11 @@ bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) {
|
||||||
switch (Name.getName().getNameKind()) {
|
switch (Name.getName().getNameKind()) {
|
||||||
case clang::DeclarationName::Identifier:
|
case clang::DeclarationName::Identifier:
|
||||||
case clang::DeclarationName::CXXLiteralOperatorName:
|
case clang::DeclarationName::CXXLiteralOperatorName:
|
||||||
|
case clang::DeclarationName::CXXDeductionGuideName:
|
||||||
case clang::DeclarationName::CXXOperatorName:
|
case clang::DeclarationName::CXXOperatorName:
|
||||||
case clang::DeclarationName::CXXUsingDirective:
|
case clang::DeclarationName::CXXUsingDirective:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case clang::DeclarationName::CXXConstructorName:
|
case clang::DeclarationName::CXXConstructorName:
|
||||||
case clang::DeclarationName::CXXDestructorName:
|
case clang::DeclarationName::CXXDestructorName:
|
||||||
case clang::DeclarationName::CXXConversionFunctionName:
|
case clang::DeclarationName::CXXConversionFunctionName:
|
||||||
|
|
Loading…
Reference in New Issue