forked from OSchip/llvm-project
Revert "[Concepts] Placeholder constraints and abbreviated templates"
This temporarily reverts commit e03ead6771
because it breaks LLDB.
http://lab.llvm.org:8011/builders/lldb-x86_64-debian/builds/3356
http://lab.llvm.org:8011/builders/lldb-x64-windows-ninja/builds/12872
http://green.lab.llvm.org/green/view/LLDB/job/lldb-cmake/6407/
This commit is contained in:
parent
bb9b964072
commit
62e4b501ab
|
@ -88,7 +88,6 @@ class AtomicExpr;
|
|||
class BlockExpr;
|
||||
class BuiltinTemplateDecl;
|
||||
class CharUnits;
|
||||
class ConceptDecl;
|
||||
class CXXABI;
|
||||
class CXXConstructorDecl;
|
||||
class CXXMethodDecl;
|
||||
|
@ -212,7 +211,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||
mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
|
||||
mutable llvm::FoldingSet<DependentUnaryTransformType>
|
||||
DependentUnaryTransformTypes;
|
||||
mutable llvm::ContextualFoldingSet<AutoType, ASTContext&> AutoTypes;
|
||||
mutable llvm::FoldingSet<AutoType> AutoTypes;
|
||||
mutable llvm::FoldingSet<DeducedTemplateSpecializationType>
|
||||
DeducedTemplateSpecializationTypes;
|
||||
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
|
||||
|
@ -1543,9 +1542,7 @@ public:
|
|||
|
||||
/// C++11 deduced auto type.
|
||||
QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
|
||||
bool IsDependent, bool IsPack = false,
|
||||
ConceptDecl *TypeConstraintConcept = nullptr,
|
||||
ArrayRef<TemplateArgument> TypeConstraintArgs ={}) const;
|
||||
bool IsDependent, bool IsPack = false) const;
|
||||
|
||||
/// C++11 deduction pattern for 'auto' type.
|
||||
QualType getAutoDeductType() const;
|
||||
|
|
|
@ -548,8 +548,8 @@ public:
|
|||
}
|
||||
|
||||
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
|
||||
if (const auto *E = D->getPlaceholderTypeConstraint())
|
||||
Visit(E);
|
||||
if (const auto *TC = D->getPlaceholderTypeConstraint())
|
||||
Visit(TC->getImmediatelyDeclaredConstraint());
|
||||
if (D->hasDefaultArgument())
|
||||
Visit(D->getDefaultArgument(), SourceRange(),
|
||||
D->getDefaultArgStorage().getInheritedFrom(),
|
||||
|
|
|
@ -1102,17 +1102,6 @@ public:
|
|||
/// template.
|
||||
ArrayRef<TemplateArgument> getInjectedTemplateArgs();
|
||||
|
||||
/// Return whether this function template is an abbreviated function template,
|
||||
/// e.g. `void foo(auto x)` or `template<typename T> void foo(auto x)`
|
||||
bool isAbbreviated() const {
|
||||
// Since the invented template parameters generated from 'auto' parameters
|
||||
// are either appended to the end of the explicit template parameter list or
|
||||
// form a new template paramter list, we can simply observe the last
|
||||
// parameter to determine if such a thing happened.
|
||||
const TemplateParameterList *TPL = getTemplateParameters();
|
||||
return TPL->getParam(TPL->size() - 1)->isImplicit();
|
||||
}
|
||||
|
||||
/// Merge \p Prev with our RedeclarableTemplateDecl::Common.
|
||||
void mergePrevDecl(FunctionTemplateDecl *Prev);
|
||||
|
||||
|
@ -1226,6 +1215,7 @@ public:
|
|||
bool ParameterPack,
|
||||
bool HasTypeConstraint = false,
|
||||
Optional<unsigned> NumExpanded = None);
|
||||
|
||||
static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
|
||||
unsigned ID);
|
||||
static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
|
||||
|
@ -1384,8 +1374,7 @@ class NonTypeTemplateParmDecl final
|
|||
: public DeclaratorDecl,
|
||||
protected TemplateParmPosition,
|
||||
private llvm::TrailingObjects<NonTypeTemplateParmDecl,
|
||||
std::pair<QualType, TypeSourceInfo *>,
|
||||
Expr *> {
|
||||
std::pair<QualType, TypeSourceInfo *>> {
|
||||
friend class ASTDeclReader;
|
||||
friend TrailingObjects;
|
||||
|
||||
|
@ -1440,12 +1429,10 @@ public:
|
|||
ArrayRef<TypeSourceInfo *> ExpandedTInfos);
|
||||
|
||||
static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
|
||||
unsigned ID,
|
||||
bool HasTypeConstraint);
|
||||
unsigned ID);
|
||||
static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
|
||||
unsigned ID,
|
||||
unsigned NumExpandedTypes,
|
||||
bool HasTypeConstraint);
|
||||
unsigned NumExpandedTypes);
|
||||
|
||||
using TemplateParmPosition::getDepth;
|
||||
using TemplateParmPosition::setDepth;
|
||||
|
@ -1556,22 +1543,20 @@ public:
|
|||
return TypesAndInfos[I].second;
|
||||
}
|
||||
|
||||
/// Return the constraint introduced by the placeholder type of this non-type
|
||||
/// Return the type-constraint in the placeholder type of this non-type
|
||||
/// template parameter (if any).
|
||||
Expr *getPlaceholderTypeConstraint() const {
|
||||
return hasPlaceholderTypeConstraint() ? *getTrailingObjects<Expr *>() :
|
||||
nullptr;
|
||||
}
|
||||
|
||||
void setPlaceholderTypeConstraint(Expr *E) {
|
||||
*getTrailingObjects<Expr *>() = E;
|
||||
TypeConstraint *getPlaceholderTypeConstraint() const {
|
||||
// TODO: Concepts: Implement once we have actual placeholders with type
|
||||
// constraints.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Determine whether this non-type template parameter's type has a
|
||||
/// placeholder with a type-constraint.
|
||||
bool hasPlaceholderTypeConstraint() const {
|
||||
auto *AT = getType()->getContainedAutoType();
|
||||
return AT && AT->isConstrained();
|
||||
// TODO: Concepts: Implement once we have actual placeholders with type
|
||||
// constraints.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Get the associated-constraints of this template parameter.
|
||||
|
@ -1581,8 +1566,8 @@ public:
|
|||
/// Use this instead of getPlaceholderImmediatelyDeclaredConstraint for
|
||||
/// concepts APIs that accept an ArrayRef of constraint expressions.
|
||||
void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
|
||||
if (Expr *E = getPlaceholderTypeConstraint())
|
||||
AC.push_back(E);
|
||||
if (TypeConstraint *TC = getPlaceholderTypeConstraint())
|
||||
AC.push_back(TC->getImmediatelyDeclaredConstraint());
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
|
|
@ -99,8 +99,6 @@ def DeclRef : RefPropertyType<"Decl"> { let ConstWhenWriting = 1; }
|
|||
SubclassPropertyType<"TagDecl", DeclRef>;
|
||||
def TemplateDeclRef :
|
||||
SubclassPropertyType<"TemplateDecl", DeclRef>;
|
||||
def ConceptDeclRef :
|
||||
SubclassPropertyType<"ConceptDecl", DeclRef>;
|
||||
def TemplateTypeParmDeclRef :
|
||||
SubclassPropertyType<"TemplateTypeParmDecl", DeclRef>;
|
||||
def TemplateTemplateParmDeclRef :
|
||||
|
|
|
@ -1040,13 +1040,7 @@ DEF_TRAVERSE_TYPE(UnaryTransformType, {
|
|||
TRY_TO(TraverseType(T->getUnderlyingType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(AutoType, {
|
||||
TRY_TO(TraverseType(T->getDeducedType()));
|
||||
if (T->isConstrained()) {
|
||||
TRY_TO(TraverseDecl(T->getTypeConstraintConcept()));
|
||||
TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs()));
|
||||
}
|
||||
})
|
||||
DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); })
|
||||
DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, {
|
||||
TRY_TO(TraverseTemplateName(T->getTemplateName()));
|
||||
TRY_TO(TraverseType(T->getDeducedType()));
|
||||
|
@ -1293,12 +1287,6 @@ DEF_TRAVERSE_TYPELOC(UnaryTransformType, {
|
|||
|
||||
DEF_TRAVERSE_TYPELOC(AutoType, {
|
||||
TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
|
||||
if (TL.isConstrained()) {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(TL.getNestedNameSpecifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(TL.getConceptNameInfo()));
|
||||
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
|
||||
TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, {
|
||||
|
|
|
@ -637,7 +637,7 @@ public:
|
|||
}
|
||||
|
||||
static const ASTTemplateArgumentListInfo *
|
||||
Create(const ASTContext &C, const TemplateArgumentListInfo &List);
|
||||
Create(ASTContext &C, const TemplateArgumentListInfo &List);
|
||||
};
|
||||
|
||||
/// Represents an explicit template argument list in C++, e.g.,
|
||||
|
@ -702,11 +702,6 @@ inline const TemplateArgument &
|
|||
return getArgs()[Idx];
|
||||
}
|
||||
|
||||
inline const TemplateArgument &AutoType::getArg(unsigned Idx) const {
|
||||
assert(Idx < getNumArgs() && "Template argument out of range");
|
||||
return getArgs()[Idx];
|
||||
}
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_AST_TEMPLATEBASE_H
|
||||
|
|
|
@ -58,7 +58,6 @@ namespace clang {
|
|||
|
||||
class ExtQuals;
|
||||
class QualType;
|
||||
class ConceptDecl;
|
||||
class TagDecl;
|
||||
class Type;
|
||||
|
||||
|
@ -1684,15 +1683,6 @@ protected:
|
|||
/// Was this placeholder type spelled as 'auto', 'decltype(auto)',
|
||||
/// or '__auto_type'? AutoTypeKeyword value.
|
||||
unsigned Keyword : 2;
|
||||
|
||||
/// The number of template arguments in the type-constraints, which is
|
||||
/// expected to be able to hold at least 1024 according to [implimits].
|
||||
/// However as this limit is somewhat easy to hit with template
|
||||
/// metaprogramming we'd prefer to keep it as large as possible.
|
||||
/// At the moment it has been left as a non-bitfield since this type
|
||||
/// safely fits in 64 bits as an unsigned, so there is no reason to
|
||||
/// introduce the performance impact of a bitfield.
|
||||
unsigned NumArgs;
|
||||
};
|
||||
|
||||
class SubstTemplateTypeParmPackTypeBitfields {
|
||||
|
@ -4824,7 +4814,8 @@ public:
|
|||
|
||||
/// Common base class for placeholders for types that get replaced by
|
||||
/// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced
|
||||
/// class template types, and constrained type names.
|
||||
/// class template types, and (eventually) constrained type names from the C++
|
||||
/// Concepts TS.
|
||||
///
|
||||
/// These types are usually a placeholder for a deduced type. However, before
|
||||
/// the initializer is attached, or (usually) if the initializer is
|
||||
|
@ -4869,50 +4860,18 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// Represents a C++11 auto or C++14 decltype(auto) type, possibly constrained
|
||||
/// by a type-constraint.
|
||||
class alignas(8) AutoType : public DeducedType, public llvm::FoldingSetNode {
|
||||
/// Represents a C++11 auto or C++14 decltype(auto) type.
|
||||
class AutoType : public DeducedType, public llvm::FoldingSetNode {
|
||||
friend class ASTContext; // ASTContext creates these
|
||||
|
||||
ConceptDecl *TypeConstraintConcept;
|
||||
|
||||
AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
|
||||
bool IsDeducedAsDependent, bool IsDeducedAsPack, ConceptDecl *CD,
|
||||
ArrayRef<TemplateArgument> TypeConstraintArgs);
|
||||
|
||||
const TemplateArgument *getArgBuffer() const {
|
||||
return reinterpret_cast<const TemplateArgument*>(this+1);
|
||||
}
|
||||
|
||||
TemplateArgument *getArgBuffer() {
|
||||
return reinterpret_cast<TemplateArgument*>(this+1);
|
||||
bool IsDeducedAsDependent, bool IsDeducedAsPack)
|
||||
: DeducedType(Auto, DeducedAsType, IsDeducedAsDependent,
|
||||
IsDeducedAsDependent, IsDeducedAsPack) {
|
||||
AutoTypeBits.Keyword = (unsigned)Keyword;
|
||||
}
|
||||
|
||||
public:
|
||||
/// Retrieve the template arguments.
|
||||
const TemplateArgument *getArgs() const {
|
||||
return getArgBuffer();
|
||||
}
|
||||
|
||||
/// Retrieve the number of template arguments.
|
||||
unsigned getNumArgs() const {
|
||||
return AutoTypeBits.NumArgs;
|
||||
}
|
||||
|
||||
const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h
|
||||
|
||||
ArrayRef<TemplateArgument> getTypeConstraintArguments() const {
|
||||
return {getArgs(), getNumArgs()};
|
||||
}
|
||||
|
||||
ConceptDecl *getTypeConstraintConcept() const {
|
||||
return TypeConstraintConcept;
|
||||
}
|
||||
|
||||
bool isConstrained() const {
|
||||
return TypeConstraintConcept != nullptr;
|
||||
}
|
||||
|
||||
bool isDecltypeAuto() const {
|
||||
return getKeyword() == AutoTypeKeyword::DecltypeAuto;
|
||||
}
|
||||
|
@ -4921,15 +4880,18 @@ public:
|
|||
return (AutoTypeKeyword)AutoTypeBits.Keyword;
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
|
||||
Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(),
|
||||
getTypeConstraintConcept(), getTypeConstraintArguments());
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
Profile(ID, getDeducedType(), getKeyword(), isDependentType(),
|
||||
containsUnexpandedParameterPack());
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
|
||||
QualType Deduced, AutoTypeKeyword Keyword,
|
||||
bool IsDependent, ConceptDecl *CD,
|
||||
ArrayRef<TemplateArgument> Arguments);
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced,
|
||||
AutoTypeKeyword Keyword, bool IsDependent, bool IsPack) {
|
||||
ID.AddPointer(Deduced.getAsOpaquePtr());
|
||||
ID.AddInteger((unsigned)Keyword);
|
||||
ID.AddBoolean(IsDependent);
|
||||
ID.AddBoolean(IsPack);
|
||||
}
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == Auto;
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#ifndef LLVM_CLANG_AST_TYPELOC_H
|
||||
#define LLVM_CLANG_AST_TYPELOC_H
|
||||
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
#include "clang/AST/Type.h"
|
||||
|
@ -35,7 +34,6 @@ namespace clang {
|
|||
class Attr;
|
||||
class ASTContext;
|
||||
class CXXRecordDecl;
|
||||
class ConceptDecl;
|
||||
class Expr;
|
||||
class ObjCInterfaceDecl;
|
||||
class ObjCProtocolDecl;
|
||||
|
@ -183,11 +181,6 @@ public:
|
|||
/// AttributedTypeLoc, for those type attributes that behave as qualifiers
|
||||
TypeLoc findExplicitQualifierLoc() const;
|
||||
|
||||
/// Get the typeloc of an AutoType whose type will be deduced for a variable
|
||||
/// with an initializer of this type. This looks through declarators like
|
||||
/// pointer types, but not through decltype or typedefs.
|
||||
AutoTypeLoc getContainedAutoTypeLoc() const;
|
||||
|
||||
/// Initializes this to state that every location in this
|
||||
/// type is the given location.
|
||||
///
|
||||
|
@ -1930,137 +1923,8 @@ class DeducedTypeLoc
|
|||
: public InheritingConcreteTypeLoc<TypeSpecTypeLoc, DeducedTypeLoc,
|
||||
DeducedType> {};
|
||||
|
||||
struct AutoTypeLocInfo : TypeSpecLocInfo {
|
||||
NestedNameSpecifierLoc NestedNameSpec;
|
||||
SourceLocation TemplateKWLoc;
|
||||
SourceLocation ConceptNameLoc;
|
||||
NamedDecl *FoundDecl;
|
||||
SourceLocation LAngleLoc;
|
||||
SourceLocation RAngleLoc;
|
||||
};
|
||||
|
||||
class AutoTypeLoc
|
||||
: public ConcreteTypeLoc<DeducedTypeLoc,
|
||||
AutoTypeLoc,
|
||||
AutoType,
|
||||
AutoTypeLocInfo> {
|
||||
public:
|
||||
AutoTypeKeyword getAutoKeyword() const {
|
||||
return getTypePtr()->getKeyword();
|
||||
}
|
||||
|
||||
bool isConstrained() const {
|
||||
return getTypePtr()->isConstrained();
|
||||
}
|
||||
|
||||
const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
|
||||
return getLocalData()->NestedNameSpec;
|
||||
}
|
||||
|
||||
void setNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
|
||||
getLocalData()->NestedNameSpec = NNS;
|
||||
}
|
||||
|
||||
SourceLocation getTemplateKWLoc() const {
|
||||
return getLocalData()->TemplateKWLoc;
|
||||
}
|
||||
|
||||
void setTemplateKWLoc(SourceLocation Loc) {
|
||||
getLocalData()->TemplateKWLoc = Loc;
|
||||
}
|
||||
|
||||
SourceLocation getConceptNameLoc() const {
|
||||
return getLocalData()->ConceptNameLoc;
|
||||
}
|
||||
|
||||
void setConceptNameLoc(SourceLocation Loc) {
|
||||
getLocalData()->ConceptNameLoc = Loc;
|
||||
}
|
||||
|
||||
NamedDecl *getFoundDecl() const {
|
||||
return getLocalData()->FoundDecl;
|
||||
}
|
||||
|
||||
void setFoundDecl(NamedDecl *D) {
|
||||
getLocalData()->FoundDecl = D;
|
||||
}
|
||||
|
||||
ConceptDecl *getNamedConcept() const {
|
||||
return getTypePtr()->getTypeConstraintConcept();
|
||||
}
|
||||
|
||||
DeclarationNameInfo getConceptNameInfo() const;
|
||||
|
||||
bool hasExplicitTemplateArgs() const {
|
||||
return getLocalData()->LAngleLoc.isValid();
|
||||
}
|
||||
|
||||
SourceLocation getLAngleLoc() const {
|
||||
return this->getLocalData()->LAngleLoc;
|
||||
}
|
||||
|
||||
void setLAngleLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->LAngleLoc = Loc;
|
||||
}
|
||||
|
||||
SourceLocation getRAngleLoc() const {
|
||||
return this->getLocalData()->RAngleLoc;
|
||||
}
|
||||
|
||||
void setRAngleLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->RAngleLoc = Loc;
|
||||
}
|
||||
|
||||
unsigned getNumArgs() const {
|
||||
return getTypePtr()->getNumArgs();
|
||||
}
|
||||
|
||||
void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) {
|
||||
getArgInfos()[i] = AI;
|
||||
}
|
||||
|
||||
TemplateArgumentLocInfo getArgLocInfo(unsigned i) const {
|
||||
return getArgInfos()[i];
|
||||
}
|
||||
|
||||
TemplateArgumentLoc getArgLoc(unsigned i) const {
|
||||
return TemplateArgumentLoc(getTypePtr()->getTypeConstraintArguments()[i],
|
||||
getArgLocInfo(i));
|
||||
}
|
||||
|
||||
SourceRange getLocalSourceRange() const {
|
||||
return{
|
||||
isConstrained()
|
||||
? (getNestedNameSpecifierLoc()
|
||||
? getNestedNameSpecifierLoc().getBeginLoc()
|
||||
: (getTemplateKWLoc().isValid()
|
||||
? getTemplateKWLoc()
|
||||
: getConceptNameLoc()))
|
||||
: getNameLoc(),
|
||||
getNameLoc()
|
||||
};
|
||||
}
|
||||
|
||||
void copy(AutoTypeLoc Loc) {
|
||||
unsigned size = getFullDataSize();
|
||||
assert(size == Loc.getFullDataSize());
|
||||
memcpy(Data, Loc.Data, size);
|
||||
}
|
||||
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc);
|
||||
|
||||
unsigned getExtraLocalDataSize() const {
|
||||
return getNumArgs() * sizeof(TemplateArgumentLocInfo);
|
||||
}
|
||||
|
||||
unsigned getExtraLocalDataAlignment() const {
|
||||
return alignof(TemplateArgumentLocInfo);
|
||||
}
|
||||
|
||||
private:
|
||||
TemplateArgumentLocInfo *getArgInfos() const {
|
||||
return static_cast<TemplateArgumentLocInfo*>(getExtraLocalData());
|
||||
}
|
||||
: public InheritingConcreteTypeLoc<DeducedTypeLoc, AutoTypeLoc, AutoType> {
|
||||
};
|
||||
|
||||
class DeducedTemplateSpecializationTypeLoc
|
||||
|
|
|
@ -395,13 +395,6 @@ let Class = AutoType in {
|
|||
def : Property<"keyword", AutoTypeKeyword> {
|
||||
let Read = [{ node->getKeyword() }];
|
||||
}
|
||||
def : Property<"typeConstraintConcept", Optional<ConceptDeclRef>> {
|
||||
let Read = [{ makeOptionalFromPointer(
|
||||
const_cast<const ConceptDecl*>(node->getTypeConstraintConcept())) }];
|
||||
}
|
||||
def : Property<"typeConstraintArguments", Array<TemplateArgument>> {
|
||||
let Read = [{ node->getTypeConstraintArguments() }];
|
||||
}
|
||||
// FIXME: better enumerated value
|
||||
// Only really required when the deduced type is null
|
||||
def : Property<"dependence", UInt32> {
|
||||
|
@ -413,9 +406,7 @@ let Class = AutoType in {
|
|||
def : Creator<[{
|
||||
return ctx.getAutoType(makeNullableFromOptional(deducedType), keyword,
|
||||
/*isDependentWithoutDeducedType*/ dependence > 0,
|
||||
/*isPackWithoutDeducedType*/ dependence > 1,
|
||||
makePointerFromOptional(typeConstraintConcept),
|
||||
typeConstraintArguments);
|
||||
/*isPackWithoutDeducedType*/ dependence > 1);
|
||||
}]>;
|
||||
}
|
||||
|
||||
|
|
|
@ -1371,8 +1371,6 @@ def err_concept_definition_not_identifier : Error<
|
|||
def ext_concept_legacy_bool_keyword : ExtWarn<
|
||||
"ISO C++2a does not permit the 'bool' keyword after 'concept'">,
|
||||
InGroup<DiagGroup<"concepts-ts-compat">>;
|
||||
def err_placeholder_expected_auto_or_decltype_auto : Error<
|
||||
"expected 'auto' or 'decltype(auto)' after concept name">;
|
||||
}
|
||||
|
||||
} // end of Parser diagnostics
|
||||
|
|
|
@ -2102,8 +2102,11 @@ def err_auto_not_allowed : Error<
|
|||
"|in template argument|in typedef|in type alias|in function return type"
|
||||
"|in conversion function type|here|in lambda parameter"
|
||||
"|in type allocated by 'new'|in K&R-style function parameter"
|
||||
"|in template parameter|in friend declaration|in function prototype that is "
|
||||
"not a function declaration|in requires expression parameter}1">;
|
||||
"|in template parameter|in friend declaration"
|
||||
"|in requires expression parameter}1">;
|
||||
def err_auto_not_allowed_in_return_type_requirement : Error<
|
||||
"%select{'auto'|'decltype(auto)'|'__auto_type'}0 not allowed in expression "
|
||||
"type requirement">;
|
||||
def err_dependent_deduced_tst : Error<
|
||||
"typename specifier refers to "
|
||||
"%select{class template|function template|variable template|alias template|"
|
||||
|
@ -2652,9 +2655,6 @@ def note_ambiguous_atomic_constraints : Note<
|
|||
"same concept">;
|
||||
def note_ambiguous_atomic_constraints_similar_expression : Note<
|
||||
"similar constraint expression here">;
|
||||
def err_unsupported_placeholder_constraint : Error<
|
||||
"constrained placeholder types other than simple 'auto' on non-type template "
|
||||
"parameters not supported yet">;
|
||||
|
||||
def err_template_different_requires_clause : Error<
|
||||
"requires clause differs in template redeclaration">;
|
||||
|
@ -2669,8 +2669,6 @@ def err_type_constraint_non_type_concept : Error<
|
|||
def err_type_constraint_missing_arguments : Error<
|
||||
"%0 requires more than 1 template argument; provide the remaining arguments "
|
||||
"explicitly to use it here">;
|
||||
def err_placeholder_constraints_not_satisfied : Error<
|
||||
"deduced type %0 does not satisfy %1">;
|
||||
|
||||
// C++11 char16_t/char32_t
|
||||
def warn_cxx98_compat_unicode_type : Warning<
|
||||
|
|
|
@ -349,7 +349,6 @@ private:
|
|||
unsigned TypeSpecOwned : 1;
|
||||
unsigned TypeSpecPipe : 1;
|
||||
unsigned TypeSpecSat : 1;
|
||||
unsigned ConstrainedAuto : 1;
|
||||
|
||||
// type-qualifiers
|
||||
unsigned TypeQualifiers : 5; // Bitwise OR of TQ.
|
||||
|
@ -370,7 +369,6 @@ private:
|
|||
UnionParsedType TypeRep;
|
||||
Decl *DeclRep;
|
||||
Expr *ExprRep;
|
||||
TemplateIdAnnotation *TemplateIdRep;
|
||||
};
|
||||
|
||||
/// ExplicitSpecifier - Store information about explicit spicifer.
|
||||
|
@ -415,9 +413,6 @@ private:
|
|||
static bool isExprRep(TST T) {
|
||||
return (T == TST_typeofExpr || T == TST_decltype);
|
||||
}
|
||||
static bool isTemplateIdRep(TST T) {
|
||||
return (T == TST_auto || T == TST_decltype_auto);
|
||||
}
|
||||
|
||||
DeclSpec(const DeclSpec &) = delete;
|
||||
void operator=(const DeclSpec &) = delete;
|
||||
|
@ -435,8 +430,7 @@ public:
|
|||
TypeSpecComplex(TSC_unspecified), TypeSpecSign(TSS_unspecified),
|
||||
TypeSpecType(TST_unspecified), TypeAltiVecVector(false),
|
||||
TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false),
|
||||
TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false),
|
||||
TypeQualifiers(TQ_unspecified),
|
||||
TypeSpecPipe(false), TypeSpecSat(false), TypeQualifiers(TQ_unspecified),
|
||||
FS_inline_specified(false), FS_forceinline_specified(false),
|
||||
FS_virtual_specified(false), FS_noreturn_specified(false),
|
||||
Friend_specified(false), ConstexprSpecifier(CSK_unspecified),
|
||||
|
@ -484,7 +478,6 @@ public:
|
|||
bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); }
|
||||
bool isTypeSpecPipe() const { return TypeSpecPipe; }
|
||||
bool isTypeSpecSat() const { return TypeSpecSat; }
|
||||
bool isConstrainedAuto() const { return ConstrainedAuto; }
|
||||
|
||||
ParsedType getRepAsType() const {
|
||||
assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type");
|
||||
|
@ -498,11 +491,6 @@ public:
|
|||
assert(isExprRep((TST) TypeSpecType) && "DeclSpec does not store an expr");
|
||||
return ExprRep;
|
||||
}
|
||||
TemplateIdAnnotation *getRepAsTemplateId() const {
|
||||
assert(isTemplateIdRep((TST) TypeSpecType) &&
|
||||
"DeclSpec does not store a template id");
|
||||
return TemplateIdRep;
|
||||
}
|
||||
CXXScopeSpec &getTypeSpecScope() { return TypeScope; }
|
||||
const CXXScopeSpec &getTypeSpecScope() const { return TypeScope; }
|
||||
|
||||
|
@ -678,9 +666,6 @@ public:
|
|||
SourceLocation TagNameLoc, const char *&PrevSpec,
|
||||
unsigned &DiagID, Decl *Rep, bool Owned,
|
||||
const PrintingPolicy &Policy);
|
||||
bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
|
||||
unsigned &DiagID, TemplateIdAnnotation *Rep,
|
||||
const PrintingPolicy &Policy);
|
||||
|
||||
bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
|
||||
unsigned &DiagID, Expr *Rep,
|
||||
|
@ -1846,14 +1831,6 @@ private:
|
|||
/// requires-clause, or null if no such clause was specified.
|
||||
Expr *TrailingRequiresClause;
|
||||
|
||||
/// If this declarator declares a template, its template parameter lists.
|
||||
ArrayRef<TemplateParameterList *> TemplateParameterLists;
|
||||
|
||||
/// If the declarator declares an abbreviated function template, the innermost
|
||||
/// template parameter list containing the invented and explicit template
|
||||
/// parameters (if any).
|
||||
TemplateParameterList *InventedTemplateParameterList;
|
||||
|
||||
#ifndef _MSC_VER
|
||||
union {
|
||||
#endif
|
||||
|
@ -1884,8 +1861,7 @@ public:
|
|||
Redeclaration(false), Extension(false), ObjCIvar(false),
|
||||
ObjCWeakProperty(false), InlineStorageUsed(false),
|
||||
Attrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr),
|
||||
TrailingRequiresClause(nullptr),
|
||||
InventedTemplateParameterList(nullptr) {}
|
||||
TrailingRequiresClause(nullptr) {}
|
||||
|
||||
~Declarator() {
|
||||
clear();
|
||||
|
@ -2453,30 +2429,6 @@ public:
|
|||
return TrailingRequiresClause != nullptr;
|
||||
}
|
||||
|
||||
/// Sets the template parameter lists that preceded the declarator.
|
||||
void setTemplateParameterLists(ArrayRef<TemplateParameterList *> TPLs) {
|
||||
TemplateParameterLists = TPLs;
|
||||
}
|
||||
|
||||
/// The template parameter lists that preceded the declarator.
|
||||
ArrayRef<TemplateParameterList *> getTemplateParameterLists() const {
|
||||
return TemplateParameterLists;
|
||||
}
|
||||
|
||||
/// Sets the template parameter list generated from the explicit template
|
||||
/// parameters along with any invented template parameters from
|
||||
/// placeholder-typed parameters.
|
||||
void setInventedTemplateParameterList(TemplateParameterList *Invented) {
|
||||
InventedTemplateParameterList = Invented;
|
||||
}
|
||||
|
||||
/// The template parameter list generated from the explicit template
|
||||
/// parameters along with any invented template parameters from
|
||||
/// placeholder-typed parameters, if there were any such parameters.
|
||||
TemplateParameterList * getInventedTemplateParameterList() const {
|
||||
return InventedTemplateParameterList;
|
||||
}
|
||||
|
||||
/// takeAttributes - Takes attributes from the given parsed-attributes
|
||||
/// set and add them to this declarator.
|
||||
///
|
||||
|
@ -2677,26 +2629,6 @@ struct LambdaIntroducer {
|
|||
}
|
||||
};
|
||||
|
||||
struct InventedTemplateParameterInfo {
|
||||
/// The number of parameters in the template parameter list that were
|
||||
/// explicitly specified by the user, as opposed to being invented by use
|
||||
/// of an auto parameter.
|
||||
unsigned NumExplicitTemplateParams = 0;
|
||||
|
||||
/// If this is a generic lambda or abbreviated function template, use this
|
||||
/// as the depth of each 'auto' parameter, during initial AST construction.
|
||||
unsigned AutoTemplateParameterDepth = 0;
|
||||
|
||||
/// Store the list of the template parameters for a generic lambda or an
|
||||
/// abbreviated function template.
|
||||
/// If this is a generic lambda or abbreviated function template, this holds
|
||||
/// the explicit template parameters followed by the auto parameters
|
||||
/// converted into TemplateTypeParmDecls.
|
||||
/// It can be used to construct the generic lambda or abbreviated template's
|
||||
/// template parameter list during initial AST construction.
|
||||
SmallVector<NamedDecl*, 4> TemplateParams;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_SEMA_DECLSPEC_H
|
||||
|
|
|
@ -385,12 +385,6 @@ public:
|
|||
return getFlags() & Scope::FunctionPrototypeScope;
|
||||
}
|
||||
|
||||
/// isFunctionDeclarationScope - Return true if this scope is a
|
||||
/// function prototype scope.
|
||||
bool isFunctionDeclarationScope() const {
|
||||
return getFlags() & Scope::FunctionDeclarationScope;
|
||||
}
|
||||
|
||||
/// isAtCatchScope - Return true if this scope is \@catch.
|
||||
bool isAtCatchScope() const {
|
||||
return getFlags() & Scope::AtCatchScope;
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include "clang/Basic/PartialDiagnostic.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Sema/CleanupInfo.h"
|
||||
#include "clang/Sema/DeclSpec.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
|
@ -790,8 +789,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class LambdaScopeInfo final :
|
||||
public CapturingScopeInfo, public InventedTemplateParameterInfo {
|
||||
class LambdaScopeInfo final : public CapturingScopeInfo {
|
||||
public:
|
||||
/// The class that describes the lambda.
|
||||
CXXRecordDecl *Lambda = nullptr;
|
||||
|
@ -825,9 +823,25 @@ public:
|
|||
/// Packs introduced by this lambda, if any.
|
||||
SmallVector<NamedDecl*, 4> LocalPacks;
|
||||
|
||||
/// If this is a generic lambda, use this as the depth of
|
||||
/// each 'auto' parameter, during initial AST construction.
|
||||
unsigned AutoTemplateParameterDepth = 0;
|
||||
|
||||
/// The number of parameters in the template parameter list that were
|
||||
/// explicitly specified by the user, as opposed to being invented by use
|
||||
/// of an auto parameter.
|
||||
unsigned NumExplicitTemplateParams = 0;
|
||||
|
||||
/// Source range covering the explicit template parameter list (if it exists).
|
||||
SourceRange ExplicitTemplateParamsRange;
|
||||
|
||||
/// Store the list of the template parameters for a generic lambda.
|
||||
/// If this is a generic lambda, this holds the explicit template parameters
|
||||
/// followed by the auto parameters converted into TemplateTypeParmDecls.
|
||||
/// It can be used to construct the generic lambda's template parameter list
|
||||
/// during initial AST construction.
|
||||
SmallVector<NamedDecl*, 4> TemplateParams;
|
||||
|
||||
/// If this is a generic lambda, and the template parameter
|
||||
/// list has been created (from the TemplateParams) then store
|
||||
/// a reference to it (cache it to avoid reconstructing it).
|
||||
|
|
|
@ -620,13 +620,6 @@ public:
|
|||
/// function, block, and method scopes that are currently active.
|
||||
SmallVector<sema::FunctionScopeInfo *, 4> FunctionScopes;
|
||||
|
||||
/// Stack containing information needed when in C++2a an 'auto' is encountered
|
||||
/// in a function declaration parameter type specifier in order to invent a
|
||||
/// corresponding template parameter in the enclosing abbreviated function
|
||||
/// template. This information is also present in LambdaScopeInfo, stored in
|
||||
/// the FunctionScopes stack.
|
||||
SmallVector<InventedTemplateParameterInfo, 4> InventedParameterInfos;
|
||||
|
||||
typedef LazyVector<TypedefNameDecl *, ExternalSemaSource,
|
||||
&ExternalSemaSource::ReadExtVectorDecls, 2, 2>
|
||||
ExtVectorDeclsType;
|
||||
|
@ -1432,11 +1425,6 @@ public:
|
|||
/// Retrieve the module loader associated with the preprocessor.
|
||||
ModuleLoader &getModuleLoader() const;
|
||||
|
||||
/// Invent a new identifier for parameters of abbreviated templates.
|
||||
IdentifierInfo *
|
||||
InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName,
|
||||
unsigned Index);
|
||||
|
||||
void emitAndClearUnusedLocalTypedefWarnings();
|
||||
|
||||
enum TUFragmentKind {
|
||||
|
@ -1531,15 +1519,6 @@ public:
|
|||
/// WeakTopLevelDeclDecls - access to \#pragma weak-generated Decls
|
||||
SmallVectorImpl<Decl *> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
|
||||
|
||||
/// Called before parsing a function declarator belonging to a function
|
||||
/// declaration.
|
||||
void ActOnStartFunctionDeclarationDeclarator(Declarator &D,
|
||||
unsigned TemplateParameterDepth);
|
||||
|
||||
/// Called after parsing a function declarator belonging to a function
|
||||
/// declaration.
|
||||
void ActOnFinishFunctionDeclarationDeclarator(Declarator &D);
|
||||
|
||||
void ActOnComment(SourceRange Comment);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
@ -1943,8 +1922,6 @@ public:
|
|||
NC_FunctionTemplate,
|
||||
/// The name was classified as an ADL-only function template name.
|
||||
NC_UndeclaredTemplate,
|
||||
/// The name was classified as a concept name.
|
||||
NC_Concept,
|
||||
};
|
||||
|
||||
class NameClassification {
|
||||
|
@ -2009,12 +1986,6 @@ public:
|
|||
return Result;
|
||||
}
|
||||
|
||||
static NameClassification Concept(TemplateName Name) {
|
||||
NameClassification Result(NC_Concept);
|
||||
Result.Template = Name;
|
||||
return Result;
|
||||
}
|
||||
|
||||
static NameClassification UndeclaredTemplate(TemplateName Name) {
|
||||
NameClassification Result(NC_UndeclaredTemplate);
|
||||
Result.Template = Name;
|
||||
|
@ -2040,8 +2011,7 @@ public:
|
|||
|
||||
TemplateName getTemplateName() const {
|
||||
assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate ||
|
||||
Kind == NC_VarTemplate || Kind == NC_Concept ||
|
||||
Kind == NC_UndeclaredTemplate);
|
||||
Kind == NC_VarTemplate || Kind == NC_UndeclaredTemplate);
|
||||
return Template;
|
||||
}
|
||||
|
||||
|
@ -2053,8 +2023,6 @@ public:
|
|||
return TNK_Function_template;
|
||||
case NC_VarTemplate:
|
||||
return TNK_Var_template;
|
||||
case NC_Concept:
|
||||
return TNK_Concept_template;
|
||||
case NC_UndeclaredTemplate:
|
||||
return TNK_Undeclared_template;
|
||||
default:
|
||||
|
@ -6914,10 +6882,6 @@ public:
|
|||
TemplateTypeParmDecl *ConstrainedParameter,
|
||||
SourceLocation EllipsisLoc);
|
||||
|
||||
bool AttachTypeConstraint(AutoTypeLoc TL,
|
||||
NonTypeTemplateParmDecl *ConstrainedParameter,
|
||||
SourceLocation EllipsisLoc);
|
||||
|
||||
QualType CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI,
|
||||
SourceLocation Loc);
|
||||
QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc);
|
||||
|
@ -6967,8 +6931,7 @@ public:
|
|||
SourceLocation DeclStartLoc, SourceLocation DeclLoc,
|
||||
const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId,
|
||||
ArrayRef<TemplateParameterList *> ParamLists,
|
||||
bool IsFriend, bool &IsMemberSpecialization, bool &Invalid,
|
||||
bool SuppressDiagnostic = false);
|
||||
bool IsFriend, bool &IsMemberSpecialization, bool &Invalid);
|
||||
|
||||
DeclResult CheckClassTemplate(
|
||||
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
|
||||
|
@ -7880,12 +7843,10 @@ public:
|
|||
|
||||
DeduceAutoResult
|
||||
DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, QualType &Result,
|
||||
Optional<unsigned> DependentDeductionDepth = None,
|
||||
bool IgnoreConstraints = false);
|
||||
Optional<unsigned> DependentDeductionDepth = None);
|
||||
DeduceAutoResult
|
||||
DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, QualType &Result,
|
||||
Optional<unsigned> DependentDeductionDepth = None,
|
||||
bool IgnoreConstraints = false);
|
||||
Optional<unsigned> DependentDeductionDepth = None);
|
||||
void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
|
||||
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
|
||||
bool Diagnose = true);
|
||||
|
|
|
@ -716,61 +716,6 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
|
|||
RequiresClause->Profile(ID, C, /*Canonical=*/true);
|
||||
}
|
||||
|
||||
static Expr *
|
||||
canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC,
|
||||
QualType ConstrainedType) {
|
||||
// This is a bit ugly - we need to form a new immediately-declared
|
||||
// constraint that references the new parameter; this would ideally
|
||||
// require semantic analysis (e.g. template<C T> struct S {}; - the
|
||||
// converted arguments of C<T> could be an argument pack if C is
|
||||
// declared as template<typename... T> concept C = ...).
|
||||
// We don't have semantic analysis here so we dig deep into the
|
||||
// ready-made constraint expr and change the thing manually.
|
||||
ConceptSpecializationExpr *CSE;
|
||||
if (const auto *Fold = dyn_cast<CXXFoldExpr>(IDC))
|
||||
CSE = cast<ConceptSpecializationExpr>(Fold->getLHS());
|
||||
else
|
||||
CSE = cast<ConceptSpecializationExpr>(IDC);
|
||||
ArrayRef<TemplateArgument> OldConverted = CSE->getTemplateArguments();
|
||||
SmallVector<TemplateArgument, 3> NewConverted;
|
||||
NewConverted.reserve(OldConverted.size());
|
||||
if (OldConverted.front().getKind() == TemplateArgument::Pack) {
|
||||
// The case:
|
||||
// template<typename... T> concept C = true;
|
||||
// template<C<int> T> struct S; -> constraint is C<{T, int}>
|
||||
NewConverted.push_back(ConstrainedType);
|
||||
for (auto &Arg : OldConverted.front().pack_elements().drop_front(1))
|
||||
NewConverted.push_back(Arg);
|
||||
TemplateArgument NewPack(NewConverted);
|
||||
|
||||
NewConverted.clear();
|
||||
NewConverted.push_back(NewPack);
|
||||
assert(OldConverted.size() == 1 &&
|
||||
"Template parameter pack should be the last parameter");
|
||||
} else {
|
||||
assert(OldConverted.front().getKind() == TemplateArgument::Type &&
|
||||
"Unexpected first argument kind for immediately-declared "
|
||||
"constraint");
|
||||
NewConverted.push_back(ConstrainedType);
|
||||
for (auto &Arg : OldConverted.drop_front(1))
|
||||
NewConverted.push_back(Arg);
|
||||
}
|
||||
Expr *NewIDC = ConceptSpecializationExpr::Create(
|
||||
C, NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(),
|
||||
CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(),
|
||||
CSE->getNamedConcept(),
|
||||
// Actually canonicalizing a TemplateArgumentLoc is difficult so we
|
||||
// simply omit the ArgsAsWritten
|
||||
/*ArgsAsWritten=*/nullptr, NewConverted, nullptr);
|
||||
|
||||
if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
|
||||
NewIDC = new (C) CXXFoldExpr(OrigFold->getType(), SourceLocation(), NewIDC,
|
||||
BinaryOperatorKind::BO_LAnd,
|
||||
SourceLocation(), /*RHS=*/nullptr,
|
||||
SourceLocation(), /*NumExpansions=*/None);
|
||||
return NewIDC;
|
||||
}
|
||||
|
||||
TemplateTemplateParmDecl *
|
||||
ASTContext::getCanonicalTemplateTemplateParmDecl(
|
||||
TemplateTemplateParmDecl *TTP) const {
|
||||
|
@ -798,23 +743,68 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
|
|||
TTP->isExpandedParameterPack() ?
|
||||
llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);
|
||||
if (const auto *TC = TTP->getTypeConstraint()) {
|
||||
// This is a bit ugly - we need to form a new immediately-declared
|
||||
// constraint that references the new parameter; this would ideally
|
||||
// require semantic analysis (e.g. template<C T> struct S {}; - the
|
||||
// converted arguments of C<T> could be an argument pack if C is
|
||||
// declared as template<typename... T> concept C = ...).
|
||||
// We don't have semantic analysis here so we dig deep into the
|
||||
// ready-made constraint expr and change the thing manually.
|
||||
Expr *IDC = TC->getImmediatelyDeclaredConstraint();
|
||||
ConceptSpecializationExpr *CSE;
|
||||
if (const auto *Fold = dyn_cast<CXXFoldExpr>(IDC))
|
||||
CSE = cast<ConceptSpecializationExpr>(Fold->getLHS());
|
||||
else
|
||||
CSE = cast<ConceptSpecializationExpr>(IDC);
|
||||
ArrayRef<TemplateArgument> OldConverted = CSE->getTemplateArguments();
|
||||
SmallVector<TemplateArgument, 3> NewConverted;
|
||||
NewConverted.reserve(OldConverted.size());
|
||||
|
||||
QualType ParamAsArgument(NewTTP->getTypeForDecl(), 0);
|
||||
Expr *NewIDC = canonicalizeImmediatelyDeclaredConstraint(
|
||||
*this, TC->getImmediatelyDeclaredConstraint(),
|
||||
ParamAsArgument);
|
||||
TemplateArgumentListInfo CanonArgsAsWritten;
|
||||
if (auto *Args = TC->getTemplateArgsAsWritten())
|
||||
for (const auto &ArgLoc : Args->arguments())
|
||||
CanonArgsAsWritten.addArgument(
|
||||
TemplateArgumentLoc(ArgLoc.getArgument(),
|
||||
TemplateArgumentLocInfo()));
|
||||
if (OldConverted.front().getKind() == TemplateArgument::Pack) {
|
||||
// The case:
|
||||
// template<typename... T> concept C = true;
|
||||
// template<C<int> T> struct S; -> constraint is C<{T, int}>
|
||||
NewConverted.push_back(ParamAsArgument);
|
||||
for (auto &Arg : OldConverted.front().pack_elements().drop_front(1))
|
||||
NewConverted.push_back(Arg);
|
||||
TemplateArgument NewPack(NewConverted);
|
||||
|
||||
NewConverted.clear();
|
||||
NewConverted.push_back(NewPack);
|
||||
assert(OldConverted.size() == 1 &&
|
||||
"Template parameter pack should be the last parameter");
|
||||
} else {
|
||||
assert(OldConverted.front().getKind() == TemplateArgument::Type &&
|
||||
"Unexpected first argument kind for immediately-declared "
|
||||
"constraint");
|
||||
NewConverted.push_back(ParamAsArgument);
|
||||
for (auto &Arg : OldConverted.drop_front(1))
|
||||
NewConverted.push_back(Arg);
|
||||
}
|
||||
Expr *NewIDC = ConceptSpecializationExpr::Create(*this,
|
||||
NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(),
|
||||
CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(),
|
||||
CSE->getNamedConcept(),
|
||||
// Actually canonicalizing a TemplateArgumentLoc is difficult so we
|
||||
// simply omit the ArgsAsWritten
|
||||
/*ArgsAsWritten=*/nullptr, NewConverted, nullptr);
|
||||
|
||||
if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
|
||||
NewIDC = new (*this) CXXFoldExpr(OrigFold->getType(),
|
||||
SourceLocation(), NewIDC,
|
||||
BinaryOperatorKind::BO_LAnd,
|
||||
SourceLocation(), /*RHS=*/nullptr,
|
||||
SourceLocation(),
|
||||
/*NumExpansions=*/None);
|
||||
|
||||
NewTTP->setTypeConstraint(
|
||||
NestedNameSpecifierLoc(),
|
||||
DeclarationNameInfo(TC->getNamedConcept()->getDeclName(),
|
||||
SourceLocation()), /*FoundDecl=*/nullptr,
|
||||
// Actually canonicalizing a TemplateArgumentLoc is difficult so we
|
||||
// simply omit the ArgsAsWritten
|
||||
TC->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC);
|
||||
CSE->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC);
|
||||
}
|
||||
CanonParams.push_back(NewTTP);
|
||||
} else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
|
||||
|
@ -849,13 +839,6 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
|
|||
NTTP->isParameterPack(),
|
||||
TInfo);
|
||||
}
|
||||
if (AutoType *AT = T->getContainedAutoType()) {
|
||||
if (AT->isConstrained()) {
|
||||
Param->setPlaceholderTypeConstraint(
|
||||
canonicalizeImmediatelyDeclaredConstraint(
|
||||
*this, NTTP->getPlaceholderTypeConstraint(), T));
|
||||
}
|
||||
}
|
||||
CanonParams.push_back(Param);
|
||||
|
||||
} else
|
||||
|
@ -960,7 +943,7 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
|
|||
Builtin::Context &builtins)
|
||||
: ConstantArrayTypes(this_()), FunctionProtoTypes(this_()),
|
||||
TemplateSpecializationTypes(this_()),
|
||||
DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()),
|
||||
DependentTemplateSpecializationTypes(this_()),
|
||||
SubstTemplateTemplateParmPacks(this_()),
|
||||
CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts),
|
||||
SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)),
|
||||
|
@ -5141,29 +5124,21 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,
|
|||
/// getAutoType - Return the uniqued reference to the 'auto' type which has been
|
||||
/// deduced to the given type, or to the canonical undeduced 'auto' type, or the
|
||||
/// canonical deduced-but-dependent 'auto' type.
|
||||
QualType
|
||||
ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
|
||||
bool IsDependent, bool IsPack,
|
||||
ConceptDecl *TypeConstraintConcept,
|
||||
ArrayRef<TemplateArgument> TypeConstraintArgs) const {
|
||||
QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
|
||||
bool IsDependent, bool IsPack) const {
|
||||
assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack");
|
||||
if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto &&
|
||||
!TypeConstraintConcept && !IsDependent)
|
||||
if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent)
|
||||
return getAutoDeductType();
|
||||
|
||||
// Look in the folding set for an existing type.
|
||||
void *InsertPos = nullptr;
|
||||
llvm::FoldingSetNodeID ID;
|
||||
AutoType::Profile(ID, *this, DeducedType, Keyword, IsDependent,
|
||||
TypeConstraintConcept, TypeConstraintArgs);
|
||||
AutoType::Profile(ID, DeducedType, Keyword, IsDependent, IsPack);
|
||||
if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
|
||||
return QualType(AT, 0);
|
||||
|
||||
void *Mem = Allocate(sizeof(AutoType) +
|
||||
sizeof(TemplateArgument) * TypeConstraintArgs.size(),
|
||||
TypeAlignment);
|
||||
auto *AT = new (Mem) AutoType(DeducedType, Keyword, IsDependent, IsPack,
|
||||
TypeConstraintConcept, TypeConstraintArgs);
|
||||
auto *AT = new (*this, TypeAlignment)
|
||||
AutoType(DeducedType, Keyword, IsDependent, IsPack);
|
||||
Types.push_back(AT);
|
||||
if (InsertPos)
|
||||
AutoTypes.InsertNode(AT, InsertPos);
|
||||
|
@ -5225,8 +5200,7 @@ QualType ASTContext::getAutoDeductType() const {
|
|||
if (AutoDeductTy.isNull())
|
||||
AutoDeductTy = QualType(
|
||||
new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto,
|
||||
/*dependent*/false, /*pack*/false,
|
||||
/*concept*/nullptr, /*args*/{}),
|
||||
/*dependent*/false, /*pack*/false),
|
||||
0);
|
||||
return AutoDeductTy;
|
||||
}
|
||||
|
|
|
@ -1366,21 +1366,9 @@ ExpectedType ASTNodeImporter::VisitAutoType(const AutoType *T) {
|
|||
if (!ToDeducedTypeOrErr)
|
||||
return ToDeducedTypeOrErr.takeError();
|
||||
|
||||
ExpectedDecl ToTypeConstraintConcept = import(T->getTypeConstraintConcept());
|
||||
if (!ToTypeConstraintConcept)
|
||||
return ToTypeConstraintConcept.takeError();
|
||||
|
||||
SmallVector<TemplateArgument, 2> ToTemplateArgs;
|
||||
ArrayRef<TemplateArgument> FromTemplateArgs = T->getTypeConstraintArguments();
|
||||
if (Error Err = ImportTemplateArguments(FromTemplateArgs.data(),
|
||||
FromTemplateArgs.size(),
|
||||
ToTemplateArgs))
|
||||
return std::move(Err);
|
||||
|
||||
return Importer.getToContext().getAutoType(
|
||||
*ToDeducedTypeOrErr, T->getKeyword(), /*IsDependent*/false,
|
||||
/*IsPack=*/false, cast_or_null<ConceptDecl>(*ToTypeConstraintConcept),
|
||||
ToTemplateArgs);
|
||||
return Importer.getToContext().getAutoType(*ToDeducedTypeOrErr,
|
||||
T->getKeyword(),
|
||||
/*IsDependent*/false);
|
||||
}
|
||||
|
||||
ExpectedType ASTNodeImporter::VisitInjectedClassNameType(
|
||||
|
|
|
@ -729,31 +729,11 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
|||
return false;
|
||||
break;
|
||||
|
||||
case Type::Auto: {
|
||||
auto *Auto1 = cast<AutoType>(T1);
|
||||
auto *Auto2 = cast<AutoType>(T2);
|
||||
if (!IsStructurallyEquivalent(Context, Auto1->getDeducedType(),
|
||||
Auto2->getDeducedType()))
|
||||
case Type::Auto:
|
||||
if (!IsStructurallyEquivalent(Context, cast<AutoType>(T1)->getDeducedType(),
|
||||
cast<AutoType>(T2)->getDeducedType()))
|
||||
return false;
|
||||
if (Auto1->isConstrained() != Auto2->isConstrained())
|
||||
return false;
|
||||
if (Auto1->isConstrained()) {
|
||||
if (Auto1->getTypeConstraintConcept() !=
|
||||
Auto2->getTypeConstraintConcept())
|
||||
return false;
|
||||
ArrayRef<TemplateArgument> Auto1Args =
|
||||
Auto1->getTypeConstraintArguments();
|
||||
ArrayRef<TemplateArgument> Auto2Args =
|
||||
Auto2->getTypeConstraintArguments();
|
||||
if (Auto1Args.size() != Auto2Args.size())
|
||||
return false;
|
||||
for (unsigned I = 0, N = Auto1Args.size(); I != N; ++I) {
|
||||
if (!IsStructurallyEquivalent(Context, Auto1Args[I], Auto2Args[I]))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::DeducedTemplateSpecialization: {
|
||||
const auto *DT1 = cast<DeducedTemplateSpecializationType>(T1);
|
||||
|
|
|
@ -164,15 +164,10 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,
|
|||
void TemplateParameterList::
|
||||
getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
|
||||
if (HasConstrainedParameters)
|
||||
for (const NamedDecl *Param : *this) {
|
||||
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
|
||||
for (const NamedDecl *Param : *this)
|
||||
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
|
||||
if (const auto *TC = TTP->getTypeConstraint())
|
||||
AC.push_back(TC->getImmediatelyDeclaredConstraint());
|
||||
} else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
|
||||
if (const Expr *E = NTTP->getPlaceholderTypeConstraint())
|
||||
AC.push_back(E);
|
||||
}
|
||||
}
|
||||
if (HasRequiresClause)
|
||||
AC.push_back(getRequiresClause());
|
||||
}
|
||||
|
@ -689,13 +684,8 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
|
|||
unsigned D, unsigned P, IdentifierInfo *Id,
|
||||
QualType T, bool ParameterPack,
|
||||
TypeSourceInfo *TInfo) {
|
||||
AutoType *AT = TInfo->getType()->getContainedAutoType();
|
||||
return new (C, DC,
|
||||
additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
|
||||
Expr *>(0,
|
||||
AT && AT->isConstrained() ? 1 : 0))
|
||||
NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, ParameterPack,
|
||||
TInfo);
|
||||
return new (C, DC) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id,
|
||||
T, ParameterPack, TInfo);
|
||||
}
|
||||
|
||||
NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create(
|
||||
|
@ -703,34 +693,26 @@ NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create(
|
|||
SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id,
|
||||
QualType T, TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes,
|
||||
ArrayRef<TypeSourceInfo *> ExpandedTInfos) {
|
||||
AutoType *AT = TInfo->getType()->getContainedAutoType();
|
||||
return new (C, DC,
|
||||
additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
|
||||
Expr *>(
|
||||
ExpandedTypes.size(), AT && AT->isConstrained() ? 1 : 0))
|
||||
additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>>(
|
||||
ExpandedTypes.size()))
|
||||
NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, TInfo,
|
||||
ExpandedTypes, ExpandedTInfos);
|
||||
}
|
||||
|
||||
NonTypeTemplateParmDecl *
|
||||
NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
|
||||
bool HasTypeConstraint) {
|
||||
return new (C, ID, additionalSizeToAlloc<std::pair<QualType,
|
||||
TypeSourceInfo *>,
|
||||
Expr *>(0,
|
||||
HasTypeConstraint ? 1 : 0))
|
||||
NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(),
|
||||
0, 0, nullptr, QualType(), false, nullptr);
|
||||
NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
||||
return new (C, ID) NonTypeTemplateParmDecl(nullptr, SourceLocation(),
|
||||
SourceLocation(), 0, 0, nullptr,
|
||||
QualType(), false, nullptr);
|
||||
}
|
||||
|
||||
NonTypeTemplateParmDecl *
|
||||
NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
|
||||
unsigned NumExpandedTypes,
|
||||
bool HasTypeConstraint) {
|
||||
unsigned NumExpandedTypes) {
|
||||
auto *NTTP =
|
||||
new (C, ID, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
|
||||
Expr *>(
|
||||
NumExpandedTypes, HasTypeConstraint ? 1 : 0))
|
||||
new (C, ID, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>>(
|
||||
NumExpandedTypes))
|
||||
NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(),
|
||||
0, 0, nullptr, QualType(), nullptr, None,
|
||||
None);
|
||||
|
|
|
@ -857,13 +857,6 @@ public:
|
|||
|
||||
void VisitAutoType(const AutoType *T) {
|
||||
ID.AddInteger((unsigned)T->getKeyword());
|
||||
ID.AddInteger(T->isConstrained());
|
||||
if (T->isConstrained()) {
|
||||
AddDecl(T->getTypeConstraintConcept());
|
||||
ID.AddInteger(T->getNumArgs());
|
||||
for (const auto &TA : T->getTypeConstraintArguments())
|
||||
Hash.AddTemplateArgument(TA);
|
||||
}
|
||||
VisitDeducedType(T);
|
||||
}
|
||||
|
||||
|
|
|
@ -561,7 +561,7 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
|
|||
}
|
||||
|
||||
const ASTTemplateArgumentListInfo *
|
||||
ASTTemplateArgumentListInfo::Create(const ASTContext &C,
|
||||
ASTTemplateArgumentListInfo::Create(ASTContext &C,
|
||||
const TemplateArgumentListInfo &List) {
|
||||
std::size_t size = totalSizeToAlloc<TemplateArgumentLoc>(List.size());
|
||||
void *Mem = C.Allocate(size, alignof(ASTTemplateArgumentListInfo));
|
||||
|
|
|
@ -1201,11 +1201,6 @@ void TextNodeDumper::VisitAutoType(const AutoType *T) {
|
|||
OS << " decltype(auto)";
|
||||
if (!T->isDeduced())
|
||||
OS << " undeduced";
|
||||
if (T->isConstrained()) {
|
||||
dumpDeclRef(T->getTypeConstraintConcept());
|
||||
for (const auto &Arg : T->getTypeConstraintArguments())
|
||||
VisitTemplateArgument(Arg);
|
||||
}
|
||||
}
|
||||
|
||||
void TextNodeDumper::VisitTemplateSpecializationType(
|
||||
|
|
|
@ -1114,9 +1114,7 @@ public:
|
|||
return QualType(T, 0);
|
||||
|
||||
return Ctx.getAutoType(deducedType, T->getKeyword(),
|
||||
T->isDependentType(), /*IsPack=*/false,
|
||||
T->getTypeConstraintConcept(),
|
||||
T->getTypeConstraintArguments());
|
||||
T->isDependentType());
|
||||
}
|
||||
|
||||
// FIXME: Non-trivial to implement, but important for C++
|
||||
|
@ -4160,35 +4158,3 @@ void clang::FixedPointValueToString(SmallVectorImpl<char> &Str,
|
|||
/*HasUnsignedPadding=*/false);
|
||||
APFixedPoint(Val, FXSema).toString(Str);
|
||||
}
|
||||
|
||||
AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
|
||||
bool IsDeducedAsDependent, bool IsDeducedAsPack,
|
||||
ConceptDecl *TypeConstraintConcept,
|
||||
ArrayRef<TemplateArgument> TypeConstraintArgs)
|
||||
: DeducedType(Auto, DeducedAsType, IsDeducedAsDependent,
|
||||
IsDeducedAsDependent, IsDeducedAsPack) {
|
||||
AutoTypeBits.Keyword = (unsigned)Keyword;
|
||||
AutoTypeBits.NumArgs = TypeConstraintArgs.size();
|
||||
this->TypeConstraintConcept = TypeConstraintConcept;
|
||||
if (TypeConstraintConcept) {
|
||||
TemplateArgument *ArgBuffer = getArgBuffer();
|
||||
for (const TemplateArgument &Arg : TypeConstraintArgs) {
|
||||
if (Arg.containsUnexpandedParameterPack())
|
||||
setContainsUnexpandedParameterPack();
|
||||
|
||||
new (ArgBuffer++) TemplateArgument(Arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
|
||||
QualType Deduced, AutoTypeKeyword Keyword,
|
||||
bool IsDependent, ConceptDecl *CD,
|
||||
ArrayRef<TemplateArgument> Arguments) {
|
||||
ID.AddPointer(Deduced.getAsOpaquePtr());
|
||||
ID.AddInteger((unsigned)Keyword);
|
||||
ID.AddBoolean(IsDependent);
|
||||
ID.AddPointer(CD);
|
||||
for (const TemplateArgument &Arg : Arguments)
|
||||
Arg.Profile(ID, Context);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/TypeLoc.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
|
@ -590,97 +589,3 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeclarationNameInfo AutoTypeLoc::getConceptNameInfo() const {
|
||||
return DeclarationNameInfo(getNamedConcept()->getDeclName(),
|
||||
getLocalData()->ConceptNameLoc);
|
||||
}
|
||||
|
||||
void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setNestedNameSpecifierLoc(NestedNameSpecifierLoc());
|
||||
setTemplateKWLoc(Loc);
|
||||
setConceptNameLoc(Loc);
|
||||
setFoundDecl(nullptr);
|
||||
setRAngleLoc(Loc);
|
||||
setLAngleLoc(Loc);
|
||||
TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
|
||||
getTypePtr()->getArgs(),
|
||||
getArgInfos(), Loc);
|
||||
setNameLoc(Loc);
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class GetContainedAutoTypeLocVisitor :
|
||||
public TypeLocVisitor<GetContainedAutoTypeLocVisitor, TypeLoc> {
|
||||
public:
|
||||
using TypeLocVisitor<GetContainedAutoTypeLocVisitor, TypeLoc>::Visit;
|
||||
|
||||
TypeLoc VisitAutoTypeLoc(AutoTypeLoc TL) {
|
||||
return TL;
|
||||
}
|
||||
|
||||
// Only these types can contain the desired 'auto' type.
|
||||
|
||||
TypeLoc VisitElaboratedTypeLoc(ElaboratedTypeLoc T) {
|
||||
return Visit(T.getNamedTypeLoc());
|
||||
}
|
||||
|
||||
TypeLoc VisitQualifiedTypeLoc(QualifiedTypeLoc T) {
|
||||
return Visit(T.getUnqualifiedLoc());
|
||||
}
|
||||
|
||||
TypeLoc VisitPointerTypeLoc(PointerTypeLoc T) {
|
||||
return Visit(T.getPointeeLoc());
|
||||
}
|
||||
|
||||
TypeLoc VisitBlockPointerTypeLoc(BlockPointerTypeLoc T) {
|
||||
return Visit(T.getPointeeLoc());
|
||||
}
|
||||
|
||||
TypeLoc VisitReferenceTypeLoc(ReferenceTypeLoc T) {
|
||||
return Visit(T.getPointeeLoc());
|
||||
}
|
||||
|
||||
TypeLoc VisitMemberPointerTypeLoc(MemberPointerTypeLoc T) {
|
||||
return Visit(T.getPointeeLoc());
|
||||
}
|
||||
|
||||
TypeLoc VisitArrayTypeLoc(ArrayTypeLoc T) {
|
||||
return Visit(T.getElementLoc());
|
||||
}
|
||||
|
||||
TypeLoc VisitFunctionTypeLoc(FunctionTypeLoc T) {
|
||||
return Visit(T.getReturnLoc());
|
||||
}
|
||||
|
||||
TypeLoc VisitParenTypeLoc(ParenTypeLoc T) {
|
||||
return Visit(T.getInnerLoc());
|
||||
}
|
||||
|
||||
TypeLoc VisitAttributedTypeLoc(AttributedTypeLoc T) {
|
||||
return Visit(T.getModifiedLoc());
|
||||
}
|
||||
|
||||
TypeLoc VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc T) {
|
||||
return Visit(T.getInnerLoc());
|
||||
}
|
||||
|
||||
TypeLoc VisitAdjustedTypeLoc(AdjustedTypeLoc T) {
|
||||
return Visit(T.getOriginalLoc());
|
||||
}
|
||||
|
||||
TypeLoc VisitPackExpansionTypeLoc(PackExpansionTypeLoc T) {
|
||||
return Visit(T.getPatternLoc());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
AutoTypeLoc TypeLoc::getContainedAutoTypeLoc() const {
|
||||
TypeLoc Res = GetContainedAutoTypeLocVisitor().Visit(*this);
|
||||
if (Res.isNull())
|
||||
return AutoTypeLoc();
|
||||
return Res.getAs<AutoTypeLoc>();
|
||||
}
|
||||
|
|
|
@ -1046,13 +1046,6 @@ void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) {
|
|||
if (!T->getDeducedType().isNull()) {
|
||||
printBefore(T->getDeducedType(), OS);
|
||||
} else {
|
||||
if (T->isConstrained()) {
|
||||
OS << T->getTypeConstraintConcept()->getName();
|
||||
auto Args = T->getTypeConstraintArguments();
|
||||
if (!Args.empty())
|
||||
printTemplateArgumentList(OS, Args, Policy);
|
||||
OS << ' ';
|
||||
}
|
||||
switch (T->getKeyword()) {
|
||||
case AutoTypeKeyword::Auto: OS << "auto"; break;
|
||||
case AutoTypeKeyword::DecltypeAuto: OS << "decltype(auto)"; break;
|
||||
|
@ -1241,18 +1234,20 @@ void TypePrinter::printEnumAfter(const EnumType *T, raw_ostream &OS) {}
|
|||
|
||||
void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T,
|
||||
raw_ostream &OS) {
|
||||
TemplateTypeParmDecl *D = T->getDecl();
|
||||
if (D && D->isImplicit()) {
|
||||
if (auto *TC = D->getTypeConstraint()) {
|
||||
TC->print(OS, Policy);
|
||||
OS << ' ';
|
||||
}
|
||||
OS << "auto";
|
||||
} else if (IdentifierInfo *Id = T->getIdentifier())
|
||||
if (IdentifierInfo *Id = T->getIdentifier())
|
||||
OS << Id->getName();
|
||||
else
|
||||
OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
|
||||
else {
|
||||
bool IsLambdaAutoParam = false;
|
||||
if (auto D = T->getDecl()) {
|
||||
if (auto M = dyn_cast_or_null<CXXMethodDecl>(D->getDeclContext()))
|
||||
IsLambdaAutoParam = D->isImplicit() && M->getParent()->isLambda();
|
||||
}
|
||||
|
||||
if (IsLambdaAutoParam)
|
||||
OS << "auto";
|
||||
else
|
||||
OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
|
||||
}
|
||||
spaceBeforePlaceHolder(OS);
|
||||
}
|
||||
|
||||
|
|
|
@ -133,9 +133,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(
|
|||
|
||||
LexedMethod* LM = new LexedMethod(this, FnD);
|
||||
getCurrentClass().LateParsedDeclarations.push_back(LM);
|
||||
LM->TemplateScope = getCurScope()->isTemplateParamScope() ||
|
||||
(FnD && isa<FunctionTemplateDecl>(FnD) &&
|
||||
cast<FunctionTemplateDecl>(FnD)->isAbbreviated());
|
||||
LM->TemplateScope = getCurScope()->isTemplateParamScope();
|
||||
CachedTokens &Toks = LM->Toks;
|
||||
|
||||
tok::TokenKind kind = Tok.getKind();
|
||||
|
|
|
@ -2962,7 +2962,6 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
|
|||
case Sema::NC_ContextIndependentExpr:
|
||||
case Sema::NC_VarTemplate:
|
||||
case Sema::NC_FunctionTemplate:
|
||||
case Sema::NC_Concept:
|
||||
// Might be a redeclaration of a prior entity.
|
||||
break;
|
||||
}
|
||||
|
@ -3194,18 +3193,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (Next.is(tok::annot_template_id) &&
|
||||
static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
|
||||
->Kind == TNK_Concept_template &&
|
||||
GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype)) {
|
||||
DS.getTypeSpecScope() = SS;
|
||||
// This is a qualified placeholder-specifier, e.g., ::C<int> auto ...
|
||||
// Consume the scope annotation and continue to consume the template-id
|
||||
// as a placeholder-specifier.
|
||||
ConsumeAnnotationToken();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Next.is(tok::annot_typename)) {
|
||||
DS.getTypeSpecScope() = SS;
|
||||
ConsumeAnnotationToken(); // The C++ scope.
|
||||
|
@ -3248,10 +3235,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
// C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the
|
||||
// typename.
|
||||
if (!TypeRep) {
|
||||
if (TryAnnotateTypeConstraint())
|
||||
goto DoneWithDeclSpec;
|
||||
if (isTypeConstraintAnnotation())
|
||||
continue;
|
||||
// Eat the scope spec so the identifier is current.
|
||||
ConsumeAnnotationToken();
|
||||
ParsedAttributesWithRange Attrs(AttrFactory);
|
||||
|
@ -3401,10 +3384,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
// If this is not a typedef name, don't parse it as part of the declspec,
|
||||
// it must be an implicit int or an error.
|
||||
if (!TypeRep) {
|
||||
if (TryAnnotateTypeConstraint())
|
||||
goto DoneWithDeclSpec;
|
||||
if (isTypeConstraintAnnotation())
|
||||
continue;
|
||||
ParsedAttributesWithRange Attrs(AttrFactory);
|
||||
if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) {
|
||||
if (!Attrs.empty()) {
|
||||
|
@ -3454,51 +3433,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
continue;
|
||||
}
|
||||
|
||||
// type-name or placeholder-specifier
|
||||
// type-name
|
||||
case tok::annot_template_id: {
|
||||
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
|
||||
if (TemplateId->Kind == TNK_Concept_template) {
|
||||
if (NextToken().is(tok::identifier)) {
|
||||
Diag(Loc, diag::err_placeholder_expected_auto_or_decltype_auto)
|
||||
<< FixItHint::CreateInsertion(NextToken().getLocation(), "auto");
|
||||
// Attempt to continue as if 'auto' was placed here.
|
||||
isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID,
|
||||
TemplateId, Policy);
|
||||
break;
|
||||
}
|
||||
if (!NextToken().isOneOf(tok::kw_auto, tok::kw_decltype))
|
||||
goto DoneWithDeclSpec;
|
||||
ConsumeAnnotationToken();
|
||||
SourceLocation AutoLoc = Tok.getLocation();
|
||||
if (TryConsumeToken(tok::kw_decltype)) {
|
||||
BalancedDelimiterTracker Tracker(*this, tok::l_paren);
|
||||
if (Tracker.consumeOpen()) {
|
||||
// Something like `void foo(Iterator decltype i)`
|
||||
Diag(Tok, diag::err_expected) << tok::l_paren;
|
||||
} else {
|
||||
if (!TryConsumeToken(tok::kw_auto)) {
|
||||
// Something like `void foo(Iterator decltype(int) i)`
|
||||
Tracker.skipToEnd();
|
||||
Diag(Tok, diag::err_placeholder_expected_auto_or_decltype_auto)
|
||||
<< FixItHint::CreateReplacement(SourceRange(AutoLoc,
|
||||
Tok.getLocation()),
|
||||
"auto");
|
||||
} else {
|
||||
Tracker.consumeClose();
|
||||
}
|
||||
}
|
||||
ConsumedEnd = Tok.getLocation();
|
||||
// Even if something went wrong above, continue as if we've seen
|
||||
// `decltype(auto)`.
|
||||
isInvalid = DS.SetTypeSpecType(TST_decltype_auto, Loc, PrevSpec,
|
||||
DiagID, TemplateId, Policy);
|
||||
} else {
|
||||
isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID,
|
||||
TemplateId, Policy);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (TemplateId->Kind != TNK_Type_template &&
|
||||
TemplateId->Kind != TNK_Undeclared_template) {
|
||||
// This template-id does not refer to a type name, so we're
|
||||
|
@ -6090,12 +6027,11 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
|
|||
|
||||
while (1) {
|
||||
if (Tok.is(tok::l_paren)) {
|
||||
bool IsFunctionDeclaration = D.isFunctionDeclaratorAFunctionDeclaration();
|
||||
// Enter function-declaration scope, limiting any declarators to the
|
||||
// function prototype scope, including parameter declarators.
|
||||
ParseScope PrototypeScope(this,
|
||||
Scope::FunctionPrototypeScope|Scope::DeclScope|
|
||||
(IsFunctionDeclaration
|
||||
(D.isFunctionDeclaratorAFunctionDeclaration()
|
||||
? Scope::FunctionDeclarationScope : 0));
|
||||
|
||||
// The paren may be part of a C++ direct initializer, eg. "int x(1);".
|
||||
|
@ -6114,12 +6050,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
|
|||
ParsedAttributes attrs(AttrFactory);
|
||||
BalancedDelimiterTracker T(*this, tok::l_paren);
|
||||
T.consumeOpen();
|
||||
if (IsFunctionDeclaration)
|
||||
Actions.ActOnStartFunctionDeclarationDeclarator(D,
|
||||
TemplateParameterDepth);
|
||||
ParseFunctionDeclarator(D, attrs, T, IsAmbiguous);
|
||||
if (IsFunctionDeclaration)
|
||||
Actions.ActOnFinishFunctionDeclarationDeclarator(D);
|
||||
PrototypeScope.Exit();
|
||||
} else if (Tok.is(tok::l_square)) {
|
||||
ParseBracketDeclarator(D);
|
||||
|
|
|
@ -2642,8 +2642,6 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
|||
}
|
||||
|
||||
ParsingDeclarator DeclaratorInfo(*this, DS, DeclaratorContext::MemberContext);
|
||||
if (TemplateInfo.TemplateParams)
|
||||
DeclaratorInfo.setTemplateParameterLists(TemplateParams);
|
||||
VirtSpecifiers VS;
|
||||
|
||||
// Hold late-parsed attributes so we can attach a Decl to them later.
|
||||
|
|
|
@ -240,8 +240,6 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
|
|||
|
||||
// Parse the declarator.
|
||||
ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context);
|
||||
if (TemplateInfo.TemplateParams)
|
||||
DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams);
|
||||
ParseDeclarator(DeclaratorInfo);
|
||||
// Error parsing the declarator?
|
||||
if (!DeclaratorInfo.hasName()) {
|
||||
|
@ -603,7 +601,6 @@ Parser::TPResult Parser::isStartOfTemplateTypeParameter() {
|
|||
/// typename
|
||||
///
|
||||
NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
|
||||
|
||||
switch (isStartOfTemplateTypeParameter()) {
|
||||
case TPResult::True:
|
||||
// Is there just a typo in the input code? ('typedef' instead of
|
||||
|
@ -621,6 +618,7 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
|
|||
}
|
||||
|
||||
return ParseTypeParameter(Depth, Position);
|
||||
|
||||
case TPResult::False:
|
||||
break;
|
||||
|
||||
|
@ -680,6 +678,7 @@ bool Parser::isTypeConstraintAnnotation() {
|
|||
bool Parser::TryAnnotateTypeConstraint() {
|
||||
if (!getLangOpts().ConceptsTS)
|
||||
return false;
|
||||
|
||||
CXXScopeSpec SS;
|
||||
bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
|
||||
if (ParseOptionalCXXScopeSpecifier(
|
||||
|
|
|
@ -1313,18 +1313,6 @@ public:
|
|||
Parser::TPResult
|
||||
Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
|
||||
bool *InvalidAsDeclSpec) {
|
||||
auto IsPlaceholderSpecifier = [&] (TemplateIdAnnotation *TemplateId,
|
||||
int Lookahead) {
|
||||
// We have a placeholder-constraint (we check for 'auto' or 'decltype' to
|
||||
// distinguish 'C<int>;' from 'C<int> auto c = 1;')
|
||||
return TemplateId->Kind == TNK_Concept_template &&
|
||||
GetLookAheadToken(Lookahead + 1).isOneOf(tok::kw_auto, tok::kw_decltype,
|
||||
// If we have an identifier here, the user probably forgot the
|
||||
// 'auto' in the placeholder constraint, e.g. 'C<int> x = 2;'
|
||||
// This will be diagnosed nicely later, so disambiguate as a
|
||||
// declaration.
|
||||
tok::identifier);
|
||||
};
|
||||
switch (Tok.getKind()) {
|
||||
case tok::identifier: {
|
||||
// Check for need to substitute AltiVec __vector keyword
|
||||
|
@ -1528,8 +1516,6 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
|
|||
*InvalidAsDeclSpec = NextToken().is(tok::l_paren);
|
||||
return TPResult::Ambiguous;
|
||||
}
|
||||
if (IsPlaceholderSpecifier(TemplateId, /*Lookahead=*/0))
|
||||
return TPResult::True;
|
||||
if (TemplateId->Kind != TNK_Type_template)
|
||||
return TPResult::False;
|
||||
CXXScopeSpec SS;
|
||||
|
@ -1543,13 +1529,6 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
|
|||
if (TryAnnotateTypeOrScopeToken())
|
||||
return TPResult::Error;
|
||||
if (!Tok.is(tok::annot_typename)) {
|
||||
if (Tok.is(tok::annot_cxxscope) &&
|
||||
NextToken().is(tok::annot_template_id)) {
|
||||
TemplateIdAnnotation *TemplateId =
|
||||
takeTemplateIdAnnotation(NextToken());
|
||||
if (IsPlaceholderSpecifier(TemplateId, /*Lookahead=*/1))
|
||||
return TPResult::True;
|
||||
}
|
||||
// If the next token is an identifier or a type qualifier, then this
|
||||
// can't possibly be a valid expression either.
|
||||
if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) {
|
||||
|
|
|
@ -1136,7 +1136,6 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
|
|||
// Poison SEH identifiers so they are flagged as illegal in function bodies.
|
||||
PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);
|
||||
const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
|
||||
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
|
||||
|
||||
// If this is C90 and the declspecs were completely missing, fudge in an
|
||||
// implicit int. We do this here because this is the only place where
|
||||
|
@ -1263,15 +1262,6 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
|
|||
// safe because we're always the sole owner.
|
||||
D.getMutableDeclSpec().abort();
|
||||
|
||||
// With abbreviated function templates - we need to explicitly add depth to
|
||||
// account for the implicit template parameter list induced by the template.
|
||||
if (auto *Template = dyn_cast_or_null<FunctionTemplateDecl>(Res))
|
||||
if (Template->isAbbreviated() &&
|
||||
Template->getTemplateParameters()->getParam(0)->isImplicit())
|
||||
// First template parameter is implicit - meaning no explicit template
|
||||
// parameter list was specified.
|
||||
CurTemplateDepthTracker.addDepth(1);
|
||||
|
||||
if (TryConsumeToken(tok::equal)) {
|
||||
assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='");
|
||||
|
||||
|
@ -1742,20 +1732,6 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
|
|||
return ANK_Error;
|
||||
return ANK_Success;
|
||||
}
|
||||
case Sema::NC_Concept: {
|
||||
UnqualifiedId Id;
|
||||
Id.setIdentifier(Name, NameLoc);
|
||||
if (Next.is(tok::less))
|
||||
// We have a concept name followed by '<'. Consume the identifier token so
|
||||
// we reach the '<' and annotate it.
|
||||
ConsumeToken();
|
||||
if (AnnotateTemplateIdToken(
|
||||
TemplateTy::make(Classification.getTemplateName()),
|
||||
Classification.getTemplateNameKind(), SS, SourceLocation(), Id,
|
||||
/*AllowTypeAnnotation=*/false, /*TypeConstraint=*/true))
|
||||
return ANK_Error;
|
||||
return ANK_Success;
|
||||
}
|
||||
}
|
||||
|
||||
// Unable to classify the name, but maybe we can annotate a scope specifier.
|
||||
|
|
|
@ -784,15 +784,6 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
|
||||
unsigned &DiagID, TemplateIdAnnotation *Rep,
|
||||
const PrintingPolicy &Policy) {
|
||||
assert(T == TST_auto || T == TST_decltype_auto);
|
||||
ConstrainedAuto = true;
|
||||
TemplateIdRep = Rep;
|
||||
return SetTypeSpecType(T, Loc, PrevSpec, DiagID, Policy);
|
||||
}
|
||||
|
||||
bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
|
||||
const char *&PrevSpec,
|
||||
unsigned &DiagID,
|
||||
|
|
|
@ -52,21 +52,6 @@ SourceLocation Sema::getLocForEndOfToken(SourceLocation Loc, unsigned Offset) {
|
|||
|
||||
ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); }
|
||||
|
||||
IdentifierInfo *
|
||||
Sema::InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName,
|
||||
unsigned int Index) {
|
||||
std::string InventedName;
|
||||
llvm::raw_string_ostream OS(InventedName);
|
||||
|
||||
if (!ParamName)
|
||||
OS << "auto:" << Index + 1;
|
||||
else
|
||||
OS << ParamName->getName() << ":auto";
|
||||
|
||||
OS.flush();
|
||||
return &Context.Idents.get(OS.str());
|
||||
}
|
||||
|
||||
PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,
|
||||
const Preprocessor &PP) {
|
||||
PrintingPolicy Policy = Context.getPrintingPolicy();
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "TreeTransform.h"
|
||||
#include "TypeLocBuilder.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
|
@ -1154,10 +1153,6 @@ Corrected:
|
|||
return ParsedType::make(T);
|
||||
}
|
||||
|
||||
if (isa<ConceptDecl>(FirstDecl))
|
||||
return NameClassification::Concept(
|
||||
TemplateName(cast<TemplateDecl>(FirstDecl)));
|
||||
|
||||
// We can have a type template here if we're classifying a template argument.
|
||||
if (isa<TemplateDecl>(FirstDecl) && !isa<FunctionTemplateDecl>(FirstDecl) &&
|
||||
!isa<VarTemplateDecl>(FirstDecl))
|
||||
|
@ -8661,21 +8656,11 @@ static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) {
|
|||
NamedDecl*
|
||||
Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||
TypeSourceInfo *TInfo, LookupResult &Previous,
|
||||
MultiTemplateParamsArg TemplateParamListsRef,
|
||||
MultiTemplateParamsArg TemplateParamLists,
|
||||
bool &AddToScope) {
|
||||
QualType R = TInfo->getType();
|
||||
|
||||
assert(R->isFunctionType());
|
||||
SmallVector<TemplateParameterList *, 4> TemplateParamLists;
|
||||
for (TemplateParameterList *TPL : TemplateParamListsRef)
|
||||
TemplateParamLists.push_back(TPL);
|
||||
if (TemplateParameterList *Invented = D.getInventedTemplateParameterList()) {
|
||||
if (!TemplateParamLists.empty() &&
|
||||
Invented->getDepth() == TemplateParamLists.back()->getDepth())
|
||||
TemplateParamLists.back() = Invented;
|
||||
else
|
||||
TemplateParamLists.push_back(Invented);
|
||||
}
|
||||
|
||||
// TODO: consider using NameInfo for diagnostic.
|
||||
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
|
||||
|
@ -8755,16 +8740,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
// Match up the template parameter lists with the scope specifier, then
|
||||
// determine whether we have a template or a template specialization.
|
||||
bool Invalid = false;
|
||||
TemplateParameterList *TemplateParams =
|
||||
MatchTemplateParametersToScopeSpecifier(
|
||||
D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
|
||||
D.getCXXScopeSpec(),
|
||||
D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
|
||||
? D.getName().TemplateId
|
||||
: nullptr,
|
||||
TemplateParamLists, isFriend, isMemberSpecialization,
|
||||
Invalid);
|
||||
if (TemplateParams) {
|
||||
if (TemplateParameterList *TemplateParams =
|
||||
MatchTemplateParametersToScopeSpecifier(
|
||||
D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
|
||||
D.getCXXScopeSpec(),
|
||||
D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
|
||||
? D.getName().TemplateId
|
||||
: nullptr,
|
||||
TemplateParamLists, isFriend, isMemberSpecialization,
|
||||
Invalid)) {
|
||||
if (TemplateParams->size() > 0) {
|
||||
// This is a function template
|
||||
|
||||
|
@ -8797,8 +8781,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
// For source fidelity, store the other template param lists.
|
||||
if (TemplateParamLists.size() > 1) {
|
||||
NewFD->setTemplateParameterListsInfo(Context,
|
||||
ArrayRef<TemplateParameterList *>(TemplateParamLists)
|
||||
.drop_back(1));
|
||||
TemplateParamLists.drop_back(1));
|
||||
}
|
||||
} else {
|
||||
// This is a function template specialization.
|
||||
|
|
|
@ -17386,50 +17386,3 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record,
|
|||
|
||||
return NewPD;
|
||||
}
|
||||
|
||||
void Sema::ActOnStartFunctionDeclarationDeclarator(
|
||||
Declarator &Declarator, unsigned TemplateParameterDepth) {
|
||||
auto &Info = InventedParameterInfos.emplace_back();
|
||||
TemplateParameterList *ExplicitParams = nullptr;
|
||||
ArrayRef<TemplateParameterList *> ExplicitLists =
|
||||
Declarator.getTemplateParameterLists();
|
||||
if (!ExplicitLists.empty()) {
|
||||
bool IsMemberSpecialization, IsInvalid;
|
||||
ExplicitParams = MatchTemplateParametersToScopeSpecifier(
|
||||
Declarator.getBeginLoc(), Declarator.getIdentifierLoc(),
|
||||
Declarator.getCXXScopeSpec(), /*TemplateId=*/nullptr,
|
||||
ExplicitLists, /*IsFriend=*/false, IsMemberSpecialization, IsInvalid,
|
||||
/*SuppressDiagnostic=*/true);
|
||||
}
|
||||
if (ExplicitParams) {
|
||||
Info.AutoTemplateParameterDepth = ExplicitParams->getDepth();
|
||||
for (NamedDecl *Param : *ExplicitParams)
|
||||
Info.TemplateParams.push_back(Param);
|
||||
Info.NumExplicitTemplateParams = ExplicitParams->size();
|
||||
} else {
|
||||
Info.AutoTemplateParameterDepth = TemplateParameterDepth;
|
||||
Info.NumExplicitTemplateParams = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Sema::ActOnFinishFunctionDeclarationDeclarator(Declarator &Declarator) {
|
||||
auto &FSI = InventedParameterInfos.back();
|
||||
if (FSI.TemplateParams.size() > FSI.NumExplicitTemplateParams) {
|
||||
if (FSI.NumExplicitTemplateParams != 0) {
|
||||
TemplateParameterList *ExplicitParams =
|
||||
Declarator.getTemplateParameterLists().back();
|
||||
Declarator.setInventedTemplateParameterList(
|
||||
TemplateParameterList::Create(
|
||||
Context, ExplicitParams->getTemplateLoc(),
|
||||
ExplicitParams->getLAngleLoc(), FSI.TemplateParams,
|
||||
ExplicitParams->getRAngleLoc(),
|
||||
ExplicitParams->getRequiresClause()));
|
||||
} else {
|
||||
Declarator.setInventedTemplateParameterList(
|
||||
TemplateParameterList::Create(
|
||||
Context, SourceLocation(), SourceLocation(), FSI.TemplateParams,
|
||||
SourceLocation(), /*RequiresClause=*/nullptr));
|
||||
}
|
||||
}
|
||||
InventedParameterInfos.pop_back();
|
||||
}
|
||||
|
|
|
@ -791,8 +791,7 @@ QualType Sema::buildLambdaInitCaptureInitialization(
|
|||
// deduce against.
|
||||
QualType DeductType = Context.getAutoDeductType();
|
||||
TypeLocBuilder TLB;
|
||||
AutoTypeLoc TL = TLB.push<AutoTypeLoc>(DeductType);
|
||||
TL.setNameLoc(Loc);
|
||||
TLB.pushTypeSpec(DeductType).setNameLoc(Loc);
|
||||
if (ByRef) {
|
||||
DeductType = BuildReferenceType(DeductType, true, Loc, Id);
|
||||
assert(!DeductType.isNull() && "can't build reference to auto");
|
||||
|
|
|
@ -1088,50 +1088,6 @@ bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS,
|
|||
ConstrainedParameter, EllipsisLoc);
|
||||
}
|
||||
|
||||
template<typename ArgumentLocAppender>
|
||||
static ExprResult formImmediatelyDeclaredConstraint(
|
||||
Sema &S, NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo,
|
||||
ConceptDecl *NamedConcept, SourceLocation LAngleLoc,
|
||||
SourceLocation RAngleLoc, QualType ConstrainedType,
|
||||
SourceLocation ParamNameLoc, ArgumentLocAppender Appender,
|
||||
SourceLocation EllipsisLoc) {
|
||||
|
||||
TemplateArgumentListInfo ConstraintArgs;
|
||||
ConstraintArgs.addArgument(
|
||||
S.getTrivialTemplateArgumentLoc(TemplateArgument(ConstrainedType),
|
||||
/*NTTPType=*/QualType(), ParamNameLoc));
|
||||
|
||||
ConstraintArgs.setRAngleLoc(RAngleLoc);
|
||||
ConstraintArgs.setLAngleLoc(LAngleLoc);
|
||||
Appender(ConstraintArgs);
|
||||
|
||||
// C++2a [temp.param]p4:
|
||||
// [...] This constraint-expression E is called the immediately-declared
|
||||
// constraint of T. [...]
|
||||
CXXScopeSpec SS;
|
||||
SS.Adopt(NS);
|
||||
ExprResult ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId(
|
||||
SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo,
|
||||
/*FoundDecl=*/NamedConcept, NamedConcept, &ConstraintArgs);
|
||||
if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid())
|
||||
return ImmediatelyDeclaredConstraint;
|
||||
|
||||
// C++2a [temp.param]p4:
|
||||
// [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
|
||||
//
|
||||
// We have the following case:
|
||||
//
|
||||
// template<typename T> concept C1 = true;
|
||||
// template<C1... T> struct s1;
|
||||
//
|
||||
// The constraint: (C1<T> && ...)
|
||||
return S.BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(),
|
||||
ImmediatelyDeclaredConstraint.get(), BO_LAnd,
|
||||
EllipsisLoc, /*RHS=*/nullptr,
|
||||
/*RParenLoc=*/SourceLocation(),
|
||||
/*NumExpansions=*/None);
|
||||
}
|
||||
|
||||
/// Attach a type-constraint to a template parameter.
|
||||
/// \returns true if an error occured. This can happen if the
|
||||
/// immediately-declared constraint could not be formed (e.g. incorrect number
|
||||
|
@ -1150,21 +1106,51 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
|
|||
*TemplateArgs) : nullptr;
|
||||
|
||||
QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0);
|
||||
TemplateArgumentListInfo ConstraintArgs;
|
||||
ConstraintArgs.addArgument(
|
||||
TemplateArgumentLoc(
|
||||
TemplateArgument(ParamAsArgument),
|
||||
TemplateArgumentLocInfo(
|
||||
Context.getTrivialTypeSourceInfo(ParamAsArgument,
|
||||
ConstrainedParameter->getLocation()))));
|
||||
if (TemplateArgs) {
|
||||
ConstraintArgs.setRAngleLoc(TemplateArgs->getRAngleLoc());
|
||||
ConstraintArgs.setLAngleLoc(TemplateArgs->getLAngleLoc());
|
||||
for (const TemplateArgumentLoc &ArgLoc : TemplateArgs->arguments())
|
||||
ConstraintArgs.addArgument(ArgLoc);
|
||||
}
|
||||
|
||||
ExprResult ImmediatelyDeclaredConstraint =
|
||||
formImmediatelyDeclaredConstraint(
|
||||
*this, NS, NameInfo, NamedConcept,
|
||||
TemplateArgs ? TemplateArgs->getLAngleLoc() : SourceLocation(),
|
||||
TemplateArgs ? TemplateArgs->getRAngleLoc() : SourceLocation(),
|
||||
ParamAsArgument, ConstrainedParameter->getLocation(),
|
||||
[&] (TemplateArgumentListInfo &ConstraintArgs) {
|
||||
if (TemplateArgs)
|
||||
for (const auto &ArgLoc : TemplateArgs->arguments())
|
||||
ConstraintArgs.addArgument(ArgLoc);
|
||||
}, EllipsisLoc);
|
||||
// C++2a [temp.param]p4:
|
||||
// [...] This constraint-expression E is called the immediately-declared
|
||||
// constraint of T. [...]
|
||||
CXXScopeSpec SS;
|
||||
SS.Adopt(NS);
|
||||
ExprResult ImmediatelyDeclaredConstraint = CheckConceptTemplateId(SS,
|
||||
/*TemplateKWLoc=*/SourceLocation(), NameInfo, /*FoundDecl=*/NamedConcept,
|
||||
NamedConcept, &ConstraintArgs);
|
||||
if (ImmediatelyDeclaredConstraint.isInvalid())
|
||||
return true;
|
||||
|
||||
if (ConstrainedParameter->isParameterPack()) {
|
||||
// C++2a [temp.param]p4:
|
||||
// [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
|
||||
//
|
||||
// We have the following case:
|
||||
//
|
||||
// template<typename T> concept C1 = true;
|
||||
// template<C1... T> struct s1;
|
||||
//
|
||||
// The constraint: (C1<T> && ...)
|
||||
ImmediatelyDeclaredConstraint =
|
||||
BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(),
|
||||
ImmediatelyDeclaredConstraint.get(), BO_LAnd,
|
||||
EllipsisLoc, /*RHS=*/nullptr,
|
||||
/*RParenLoc=*/SourceLocation(),
|
||||
/*NumExpansions=*/None).get();
|
||||
if (ImmediatelyDeclaredConstraint.isInvalid())
|
||||
return true;
|
||||
}
|
||||
|
||||
ConstrainedParameter->setTypeConstraint(NS, NameInfo,
|
||||
/*FoundDecl=*/NamedConcept,
|
||||
NamedConcept, ArgsAsWritten,
|
||||
|
@ -1172,38 +1158,6 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP,
|
||||
SourceLocation EllipsisLoc) {
|
||||
if (NTTP->getType() != TL.getType() ||
|
||||
TL.getAutoKeyword() != AutoTypeKeyword::Auto) {
|
||||
Diag(NTTP->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
|
||||
diag::err_unsupported_placeholder_constraint)
|
||||
<< NTTP->getTypeSourceInfo()->getTypeLoc().getSourceRange();
|
||||
return true;
|
||||
}
|
||||
// FIXME: Concepts: This should be the type of the placeholder, but this is
|
||||
// unclear in the wording right now.
|
||||
DeclRefExpr *Ref = BuildDeclRefExpr(NTTP, NTTP->getType(), VK_RValue,
|
||||
NTTP->getLocation());
|
||||
if (!Ref)
|
||||
return true;
|
||||
ExprResult ImmediatelyDeclaredConstraint =
|
||||
formImmediatelyDeclaredConstraint(
|
||||
*this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(),
|
||||
TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(),
|
||||
BuildDecltypeType(Ref, NTTP->getLocation()), NTTP->getLocation(),
|
||||
[&] (TemplateArgumentListInfo &ConstraintArgs) {
|
||||
for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I)
|
||||
ConstraintArgs.addArgument(TL.getArgLoc(I));
|
||||
}, EllipsisLoc);
|
||||
if (ImmediatelyDeclaredConstraint.isInvalid() ||
|
||||
!ImmediatelyDeclaredConstraint.isUsable())
|
||||
return true;
|
||||
|
||||
NTTP->setPlaceholderTypeConstraint(ImmediatelyDeclaredConstraint.get());
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Check that the type of a non-type template parameter is
|
||||
/// well-formed.
|
||||
///
|
||||
|
@ -1365,11 +1319,6 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
|
|||
TInfo);
|
||||
Param->setAccess(AS_public);
|
||||
|
||||
if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc())
|
||||
if (TL.isConstrained())
|
||||
if (AttachTypeConstraint(TL, Param, D.getEllipsisLoc()))
|
||||
Invalid = true;
|
||||
|
||||
if (Invalid)
|
||||
Param->setInvalidDecl();
|
||||
|
||||
|
@ -2813,7 +2762,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
|
|||
SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS,
|
||||
TemplateIdAnnotation *TemplateId,
|
||||
ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend,
|
||||
bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic) {
|
||||
bool &IsMemberSpecialization, bool &Invalid) {
|
||||
IsMemberSpecialization = false;
|
||||
Invalid = false;
|
||||
|
||||
|
@ -2921,9 +2870,8 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
|
|||
|
||||
auto CheckExplicitSpecialization = [&](SourceRange Range, bool Recovery) {
|
||||
if (SawNonEmptyTemplateParameterList) {
|
||||
if (!SuppressDiagnostic)
|
||||
Diag(DeclLoc, diag::err_specialize_member_of_template)
|
||||
<< !Recovery << Range;
|
||||
Diag(DeclLoc, diag::err_specialize_member_of_template)
|
||||
<< !Recovery << Range;
|
||||
Invalid = true;
|
||||
IsMemberSpecialization = false;
|
||||
return true;
|
||||
|
@ -2944,10 +2892,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
|
|||
else
|
||||
ExpectedTemplateLoc = DeclStartLoc;
|
||||
|
||||
if (!SuppressDiagnostic)
|
||||
Diag(DeclLoc, diag::err_template_spec_needs_header)
|
||||
<< Range
|
||||
<< FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
|
||||
Diag(DeclLoc, diag::err_template_spec_needs_header)
|
||||
<< Range
|
||||
<< FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
|
||||
return false;
|
||||
};
|
||||
|
||||
|
@ -3037,13 +2984,12 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
|
|||
if (ParamIdx < ParamLists.size()) {
|
||||
if (ParamLists[ParamIdx]->size() > 0) {
|
||||
// The header has template parameters when it shouldn't. Complain.
|
||||
if (!SuppressDiagnostic)
|
||||
Diag(ParamLists[ParamIdx]->getTemplateLoc(),
|
||||
diag::err_template_param_list_matches_nontemplate)
|
||||
<< T
|
||||
<< SourceRange(ParamLists[ParamIdx]->getLAngleLoc(),
|
||||
ParamLists[ParamIdx]->getRAngleLoc())
|
||||
<< getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
|
||||
Diag(ParamLists[ParamIdx]->getTemplateLoc(),
|
||||
diag::err_template_param_list_matches_nontemplate)
|
||||
<< T
|
||||
<< SourceRange(ParamLists[ParamIdx]->getLAngleLoc(),
|
||||
ParamLists[ParamIdx]->getRAngleLoc())
|
||||
<< getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
|
||||
Invalid = true;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -3079,7 +3025,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
|
|||
if (ExpectedTemplateParams &&
|
||||
!TemplateParameterListsAreEqual(ParamLists[ParamIdx],
|
||||
ExpectedTemplateParams,
|
||||
!SuppressDiagnostic, TPL_TemplateMatch))
|
||||
true, TPL_TemplateMatch))
|
||||
Invalid = true;
|
||||
|
||||
if (!Invalid &&
|
||||
|
@ -3091,10 +3037,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!SuppressDiagnostic)
|
||||
Diag(DeclLoc, diag::err_template_spec_needs_template_parameters)
|
||||
<< T
|
||||
<< getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
|
||||
Diag(DeclLoc, diag::err_template_spec_needs_template_parameters)
|
||||
<< T
|
||||
<< getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
|
||||
Invalid = true;
|
||||
continue;
|
||||
}
|
||||
|
@ -3130,18 +3075,16 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
|
|||
AllExplicitSpecHeaders = false;
|
||||
}
|
||||
|
||||
if (!SuppressDiagnostic)
|
||||
Diag(ParamLists[ParamIdx]->getTemplateLoc(),
|
||||
AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers
|
||||
: diag::err_template_spec_extra_headers)
|
||||
<< SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
|
||||
ParamLists[ParamLists.size() - 2]->getRAngleLoc());
|
||||
Diag(ParamLists[ParamIdx]->getTemplateLoc(),
|
||||
AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers
|
||||
: diag::err_template_spec_extra_headers)
|
||||
<< SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
|
||||
ParamLists[ParamLists.size() - 2]->getRAngleLoc());
|
||||
|
||||
// If there was a specialization somewhere, such that 'template<>' is
|
||||
// not required, and there were any 'template<>' headers, note where the
|
||||
// specialization occurred.
|
||||
if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader &&
|
||||
!SuppressDiagnostic)
|
||||
if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader)
|
||||
Diag(ExplicitSpecLoc,
|
||||
diag::note_explicit_template_spec_does_not_need_header)
|
||||
<< NestedTypes.back();
|
||||
|
@ -6587,12 +6530,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
DeductionArg = PE->getPattern();
|
||||
if (DeduceAutoType(
|
||||
Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()),
|
||||
DeductionArg, ParamType, Depth,
|
||||
// We do not check constraints right now because the
|
||||
// immediately-declared constraint of the auto type is also an
|
||||
// associated constraint, and will be checked along with the other
|
||||
// associated constraints after checking the template argument list.
|
||||
/*IgnoreConstraints=*/true) == DAR_Failed) {
|
||||
DeductionArg, ParamType, Depth) == DAR_Failed) {
|
||||
Diag(Arg->getExprLoc(),
|
||||
diag::err_non_type_template_parm_type_deduction_failure)
|
||||
<< Param->getDeclName() << Param->getType() << Arg->getType()
|
||||
|
|
|
@ -4414,10 +4414,9 @@ namespace {
|
|||
|
||||
QualType Result = SemaRef.Context.getAutoType(
|
||||
Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull(),
|
||||
ReplacementIsPack, TL.getTypePtr()->getTypeConstraintConcept(),
|
||||
TL.getTypePtr()->getTypeConstraintArguments());
|
||||
ReplacementIsPack);
|
||||
auto NewTL = TLB.push<AutoTypeLoc>(Result);
|
||||
NewTL.copy(TL);
|
||||
NewTL.setNameLoc(TL.getNameLoc());
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
@ -4452,10 +4451,9 @@ namespace {
|
|||
|
||||
Sema::DeduceAutoResult
|
||||
Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result,
|
||||
Optional<unsigned> DependentDeductionDepth,
|
||||
bool IgnoreConstraints) {
|
||||
Optional<unsigned> DependentDeductionDepth) {
|
||||
return DeduceAutoType(Type->getTypeLoc(), Init, Result,
|
||||
DependentDeductionDepth, IgnoreConstraints);
|
||||
DependentDeductionDepth);
|
||||
}
|
||||
|
||||
/// Attempt to produce an informative diagostic explaining why auto deduction
|
||||
|
@ -4483,49 +4481,6 @@ static bool diagnoseAutoDeductionFailure(Sema &S,
|
|||
}
|
||||
}
|
||||
|
||||
static Sema::DeduceAutoResult
|
||||
CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
|
||||
AutoTypeLoc TypeLoc, QualType Deduced) {
|
||||
ConstraintSatisfaction Satisfaction;
|
||||
ConceptDecl *Concept = Type.getTypeConstraintConcept();
|
||||
TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(),
|
||||
TypeLoc.getRAngleLoc());
|
||||
TemplateArgs.addArgument(
|
||||
TemplateArgumentLoc(TemplateArgument(Deduced),
|
||||
S.Context.getTrivialTypeSourceInfo(
|
||||
Deduced, TypeLoc.getNameLoc())));
|
||||
for (unsigned I = 0, C = TypeLoc.getNumArgs(); I != C; ++I)
|
||||
TemplateArgs.addArgument(TypeLoc.getArgLoc(I));
|
||||
|
||||
llvm::SmallVector<TemplateArgument, 4> Converted;
|
||||
if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs,
|
||||
/*PartialTemplateArgs=*/false, Converted))
|
||||
return Sema::DAR_FailedAlreadyDiagnosed;
|
||||
if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
|
||||
Converted, TypeLoc.getLocalSourceRange(),
|
||||
Satisfaction))
|
||||
return Sema::DAR_FailedAlreadyDiagnosed;
|
||||
if (!Satisfaction.IsSatisfied) {
|
||||
std::string Buf;
|
||||
llvm::raw_string_ostream OS(Buf);
|
||||
OS << "'" << Concept->getName();
|
||||
if (TypeLoc.hasExplicitTemplateArgs()) {
|
||||
OS << "<";
|
||||
for (const auto &Arg : Type.getTypeConstraintArguments())
|
||||
Arg.print(S.getPrintingPolicy(), OS);
|
||||
OS << ">";
|
||||
}
|
||||
OS << "'";
|
||||
OS.flush();
|
||||
S.Diag(TypeLoc.getConceptNameLoc(),
|
||||
diag::err_placeholder_constraints_not_satisfied)
|
||||
<< Deduced << Buf << TypeLoc.getLocalSourceRange();
|
||||
S.DiagnoseUnsatisfiedConstraint(Satisfaction);
|
||||
return Sema::DAR_FailedAlreadyDiagnosed;
|
||||
}
|
||||
return Sema::DAR_Succeeded;
|
||||
}
|
||||
|
||||
/// Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6)
|
||||
///
|
||||
/// Note that this is done even if the initializer is dependent. (This is
|
||||
|
@ -4540,12 +4495,9 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
|
|||
/// dependent cases. This is necessary for template partial ordering with
|
||||
/// 'auto' template parameters. The value specified is the template
|
||||
/// parameter depth at which we should perform 'auto' deduction.
|
||||
/// \param IgnoreConstraints Set if we should not fail if the deduced type does
|
||||
/// not satisfy the type-constraint in the auto type.
|
||||
Sema::DeduceAutoResult
|
||||
Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
|
||||
Optional<unsigned> DependentDeductionDepth,
|
||||
bool IgnoreConstraints) {
|
||||
Optional<unsigned> DependentDeductionDepth) {
|
||||
if (Init->getType()->isNonOverloadPlaceholderType()) {
|
||||
ExprResult NonPlaceholder = CheckPlaceholderExpr(Init);
|
||||
if (NonPlaceholder.isInvalid())
|
||||
|
@ -4586,14 +4538,6 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
|
|||
return DAR_FailedAlreadyDiagnosed;
|
||||
// FIXME: Support a non-canonical deduced type for 'auto'.
|
||||
Deduced = Context.getCanonicalType(Deduced);
|
||||
if (AT->isConstrained() && !IgnoreConstraints) {
|
||||
auto ConstraintsResult =
|
||||
CheckDeducedPlaceholderConstraints(*this, *AT,
|
||||
Type.getContainedAutoTypeLoc(),
|
||||
Deduced);
|
||||
if (ConstraintsResult != DAR_Succeeded)
|
||||
return ConstraintsResult;
|
||||
}
|
||||
Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type);
|
||||
if (Result.isNull())
|
||||
return DAR_FailedAlreadyDiagnosed;
|
||||
|
@ -4701,17 +4645,6 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
|
|||
return DAR_FailedAlreadyDiagnosed;
|
||||
}
|
||||
|
||||
if (const auto *AT = Type.getType()->getAs<AutoType>()) {
|
||||
if (AT->isConstrained() && !IgnoreConstraints) {
|
||||
auto ConstraintsResult =
|
||||
CheckDeducedPlaceholderConstraints(*this, *AT,
|
||||
Type.getContainedAutoTypeLoc(),
|
||||
DeducedType);
|
||||
if (ConstraintsResult != DAR_Succeeded)
|
||||
return ConstraintsResult;
|
||||
}
|
||||
}
|
||||
|
||||
Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type);
|
||||
if (Result.isNull())
|
||||
return DAR_FailedAlreadyDiagnosed;
|
||||
|
|
|
@ -2685,16 +2685,6 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
|
|||
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
|
||||
D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI);
|
||||
|
||||
if (AutoTypeLoc AutoLoc = DI->getTypeLoc().getContainedAutoTypeLoc())
|
||||
if (AutoLoc.isConstrained())
|
||||
if (SemaRef.AttachTypeConstraint(
|
||||
AutoLoc, Param,
|
||||
IsExpandedParameterPack
|
||||
? DI->getTypeLoc().getAs<PackExpansionTypeLoc>()
|
||||
.getEllipsisLoc()
|
||||
: SourceLocation()))
|
||||
Invalid = true;
|
||||
|
||||
Param->setAccess(AS_public);
|
||||
Param->setImplicit(D->isImplicit());
|
||||
if (Invalid)
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "TypeLocBuilder.h"
|
||||
#include "TreeTransform.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/ASTMutationListener.h"
|
||||
|
@ -28,7 +27,6 @@
|
|||
#include "clang/Sema/DeclSpec.h"
|
||||
#include "clang/Sema/DelayedDiagnostic.h"
|
||||
#include "clang/Sema/Lookup.h"
|
||||
#include "clang/Sema/ParsedTemplate.h"
|
||||
#include "clang/Sema/ScopeInfo.h"
|
||||
#include "clang/Sema/SemaInternal.h"
|
||||
#include "clang/Sema/Template.h"
|
||||
|
@ -1253,26 +1251,6 @@ getImageAccess(const ParsedAttributesView &Attrs) {
|
|||
return OpenCLAccessAttr::Keyword_read_only;
|
||||
}
|
||||
|
||||
static QualType ConvertConstrainedAutoDeclSpecToType(Sema &S, DeclSpec &DS,
|
||||
AutoTypeKeyword AutoKW) {
|
||||
assert(DS.isConstrainedAuto());
|
||||
TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId();
|
||||
TemplateArgumentListInfo TemplateArgsInfo;
|
||||
TemplateArgsInfo.setLAngleLoc(TemplateId->LAngleLoc);
|
||||
TemplateArgsInfo.setRAngleLoc(TemplateId->RAngleLoc);
|
||||
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
|
||||
TemplateId->NumArgs);
|
||||
S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo);
|
||||
llvm::SmallVector<TemplateArgument, 8> TemplateArgs;
|
||||
for (auto &ArgLoc : TemplateArgsInfo.arguments())
|
||||
TemplateArgs.push_back(ArgLoc.getArgument());
|
||||
return S.Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false,
|
||||
/*IsPack=*/false,
|
||||
cast<ConceptDecl>(TemplateId->Template.get()
|
||||
.getAsTemplateDecl()),
|
||||
TemplateArgs);
|
||||
}
|
||||
|
||||
/// Convert the specified declspec to the appropriate type
|
||||
/// object.
|
||||
/// \param state Specifies the declarator containing the declaration specifier
|
||||
|
@ -1617,11 +1595,6 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
|
|||
break;
|
||||
|
||||
case DeclSpec::TST_auto:
|
||||
if (DS.isConstrainedAuto()) {
|
||||
Result = ConvertConstrainedAutoDeclSpecToType(S, DS,
|
||||
AutoTypeKeyword::Auto);
|
||||
break;
|
||||
}
|
||||
Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);
|
||||
break;
|
||||
|
||||
|
@ -1630,12 +1603,6 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
|
|||
break;
|
||||
|
||||
case DeclSpec::TST_decltype_auto:
|
||||
if (DS.isConstrainedAuto()) {
|
||||
Result =
|
||||
ConvertConstrainedAutoDeclSpecToType(S, DS,
|
||||
AutoTypeKeyword::DecltypeAuto);
|
||||
break;
|
||||
}
|
||||
Result = Context.getAutoType(QualType(), AutoTypeKeyword::DecltypeAuto,
|
||||
/*IsDependent*/ false);
|
||||
break;
|
||||
|
@ -2954,87 +2921,6 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy,
|
|||
D.getDeclSpec().getUnalignedSpecLoc());
|
||||
}
|
||||
|
||||
static void CopyTypeConstraintFromAutoType(Sema &SemaRef, const AutoType *Auto,
|
||||
AutoTypeLoc AutoLoc,
|
||||
TemplateTypeParmDecl *TP,
|
||||
SourceLocation EllipsisLoc) {
|
||||
|
||||
TemplateArgumentListInfo TAL(AutoLoc.getLAngleLoc(), AutoLoc.getRAngleLoc());
|
||||
for (unsigned Idx = 0; Idx < AutoLoc.getNumArgs(); ++Idx)
|
||||
TAL.addArgument(AutoLoc.getArgLoc(Idx));
|
||||
|
||||
SemaRef.AttachTypeConstraint(
|
||||
AutoLoc.getNestedNameSpecifierLoc(), AutoLoc.getConceptNameInfo(),
|
||||
AutoLoc.getNamedConcept(),
|
||||
AutoLoc.hasExplicitTemplateArgs() ? &TAL : nullptr, TP, EllipsisLoc);
|
||||
}
|
||||
|
||||
static QualType InventTemplateParameter(
|
||||
TypeProcessingState &state, QualType T, TypeSourceInfo *TSI, AutoType *Auto,
|
||||
InventedTemplateParameterInfo &Info) {
|
||||
Sema &S = state.getSema();
|
||||
Declarator &D = state.getDeclarator();
|
||||
|
||||
const unsigned TemplateParameterDepth = Info.AutoTemplateParameterDepth;
|
||||
const unsigned AutoParameterPosition = Info.TemplateParams.size();
|
||||
const bool IsParameterPack = D.hasEllipsis();
|
||||
|
||||
// If auto is mentioned in a lambda parameter or abbreviated function
|
||||
// template context, convert it to a template parameter type.
|
||||
|
||||
// Create the TemplateTypeParmDecl here to retrieve the corresponding
|
||||
// template parameter type. Template parameters are temporarily added
|
||||
// to the TU until the associated TemplateDecl is created.
|
||||
TemplateTypeParmDecl *InventedTemplateParam =
|
||||
TemplateTypeParmDecl::Create(
|
||||
S.Context, S.Context.getTranslationUnitDecl(),
|
||||
/*KeyLoc=*/D.getDeclSpec().getTypeSpecTypeLoc(),
|
||||
/*NameLoc=*/D.getIdentifierLoc(),
|
||||
TemplateParameterDepth, AutoParameterPosition,
|
||||
S.InventAbbreviatedTemplateParameterTypeName(
|
||||
D.getIdentifier(), AutoParameterPosition), false,
|
||||
IsParameterPack, /*HasTypeConstraint=*/Auto->isConstrained());
|
||||
InventedTemplateParam->setImplicit();
|
||||
Info.TemplateParams.push_back(InventedTemplateParam);
|
||||
// Attach type constraints
|
||||
if (Auto->isConstrained()) {
|
||||
if (TSI) {
|
||||
CopyTypeConstraintFromAutoType(
|
||||
S, Auto, TSI->getTypeLoc().getContainedAutoTypeLoc(),
|
||||
InventedTemplateParam, D.getEllipsisLoc());
|
||||
} else {
|
||||
TemplateIdAnnotation *TemplateId = D.getDeclSpec().getRepAsTemplateId();
|
||||
TemplateArgumentListInfo TemplateArgsInfo;
|
||||
if (TemplateId->LAngleLoc.isValid()) {
|
||||
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
|
||||
TemplateId->NumArgs);
|
||||
S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo);
|
||||
}
|
||||
S.AttachTypeConstraint(
|
||||
D.getDeclSpec().getTypeSpecScope().getWithLocInContext(S.Context),
|
||||
DeclarationNameInfo(DeclarationName(TemplateId->Name),
|
||||
TemplateId->TemplateNameLoc),
|
||||
cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl()),
|
||||
TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr,
|
||||
InventedTemplateParam, D.getEllipsisLoc());
|
||||
}
|
||||
}
|
||||
|
||||
// If TSI is nullptr, this is a constrained declspec auto and the type
|
||||
// constraint will be attached later in TypeSpecLocFiller
|
||||
|
||||
// Replace the 'auto' in the function parameter with this invented
|
||||
// template type parameter.
|
||||
// FIXME: Retain some type sugar to indicate that this was written
|
||||
// as 'auto'?
|
||||
return state.ReplaceAutoType(
|
||||
T, QualType(InventedTemplateParam->getTypeForDecl(), 0));
|
||||
}
|
||||
|
||||
static TypeSourceInfo *
|
||||
GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
|
||||
QualType T, TypeSourceInfo *ReturnTypeInfo);
|
||||
|
||||
static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
|
||||
TypeSourceInfo *&ReturnTypeInfo) {
|
||||
Sema &SemaRef = state.getSema();
|
||||
|
@ -3105,43 +2991,46 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
|
|||
break;
|
||||
case DeclaratorContext::ObjCParameterContext:
|
||||
case DeclaratorContext::ObjCResultContext:
|
||||
case DeclaratorContext::PrototypeContext:
|
||||
Error = 0;
|
||||
break;
|
||||
case DeclaratorContext::RequiresExprContext:
|
||||
Error = 22;
|
||||
Error = 21;
|
||||
break;
|
||||
case DeclaratorContext::PrototypeContext:
|
||||
case DeclaratorContext::LambdaExprParameterContext: {
|
||||
InventedTemplateParameterInfo *Info = nullptr;
|
||||
if (D.getContext() == DeclaratorContext::PrototypeContext) {
|
||||
// With concepts we allow 'auto' in function parameters.
|
||||
if (!SemaRef.getLangOpts().ConceptsTS || !Auto ||
|
||||
Auto->getKeyword() != AutoTypeKeyword::Auto) {
|
||||
Error = 0;
|
||||
break;
|
||||
} else if (!SemaRef.getCurScope()->isFunctionDeclarationScope()) {
|
||||
Error = 21;
|
||||
break;
|
||||
} else if (D.hasTrailingReturnType()) {
|
||||
// This might be OK, but we'll need to convert the trailing return
|
||||
// type later.
|
||||
break;
|
||||
}
|
||||
case DeclaratorContext::LambdaExprParameterContext:
|
||||
// In C++14, generic lambdas allow 'auto' in their parameters.
|
||||
if (!SemaRef.getLangOpts().CPlusPlus14 ||
|
||||
!Auto || Auto->getKeyword() != AutoTypeKeyword::Auto)
|
||||
Error = 16;
|
||||
else {
|
||||
// If auto is mentioned in a lambda parameter context, convert it to a
|
||||
// template parameter type.
|
||||
sema::LambdaScopeInfo *LSI = SemaRef.getCurLambda();
|
||||
assert(LSI && "No LambdaScopeInfo on the stack!");
|
||||
const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
|
||||
const unsigned AutoParameterPosition = LSI->TemplateParams.size();
|
||||
const bool IsParameterPack = D.hasEllipsis();
|
||||
|
||||
Info = &SemaRef.InventedParameterInfos.back();
|
||||
} else {
|
||||
// In C++14, generic lambdas allow 'auto' in their parameters.
|
||||
if (!SemaRef.getLangOpts().CPlusPlus14 || !Auto ||
|
||||
Auto->getKeyword() != AutoTypeKeyword::Auto) {
|
||||
Error = 16;
|
||||
break;
|
||||
}
|
||||
Info = SemaRef.getCurLambda();
|
||||
assert(Info && "No LambdaScopeInfo on the stack!");
|
||||
// Create the TemplateTypeParmDecl here to retrieve the corresponding
|
||||
// template parameter type. Template parameters are temporarily added
|
||||
// to the TU until the associated TemplateDecl is created.
|
||||
TemplateTypeParmDecl *CorrespondingTemplateParam =
|
||||
TemplateTypeParmDecl::Create(
|
||||
SemaRef.Context, SemaRef.Context.getTranslationUnitDecl(),
|
||||
/*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(),
|
||||
TemplateParameterDepth, AutoParameterPosition,
|
||||
/*Identifier*/ nullptr, false, IsParameterPack,
|
||||
/*HasTypeConstraint=*/false);
|
||||
CorrespondingTemplateParam->setImplicit();
|
||||
LSI->TemplateParams.push_back(CorrespondingTemplateParam);
|
||||
// Replace the 'auto' in the function parameter with this invented
|
||||
// template type parameter.
|
||||
// FIXME: Retain some type sugar to indicate that this was written
|
||||
// as 'auto'.
|
||||
T = state.ReplaceAutoType(
|
||||
T, QualType(CorrespondingTemplateParam->getTypeForDecl(), 0));
|
||||
}
|
||||
T = InventTemplateParameter(state, T, nullptr, Auto, *Info);
|
||||
break;
|
||||
}
|
||||
case DeclaratorContext::MemberContext: {
|
||||
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
|
||||
D.isFunctionDeclarator())
|
||||
|
@ -4143,6 +4032,10 @@ static bool DiagnoseMultipleAddrSpaceAttributes(Sema &S, LangAS ASOld,
|
|||
return false;
|
||||
}
|
||||
|
||||
static TypeSourceInfo *
|
||||
GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
|
||||
QualType T, TypeSourceInfo *ReturnTypeInfo);
|
||||
|
||||
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
||||
QualType declSpecType,
|
||||
TypeSourceInfo *TInfo) {
|
||||
|
@ -4718,8 +4611,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
} else if (D.getContext() != DeclaratorContext::LambdaExprContext &&
|
||||
(T.hasQualifiers() || !isa<AutoType>(T) ||
|
||||
cast<AutoType>(T)->getKeyword() !=
|
||||
AutoTypeKeyword::Auto ||
|
||||
cast<AutoType>(T)->isConstrained())) {
|
||||
AutoTypeKeyword::Auto)) {
|
||||
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
|
||||
diag::err_trailing_return_without_auto)
|
||||
<< T << D.getDeclSpec().getSourceRange();
|
||||
|
@ -4730,12 +4622,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
// An error occurred parsing the trailing return type.
|
||||
T = Context.IntTy;
|
||||
D.setInvalidType(true);
|
||||
} else if (S.getLangOpts().ConceptsTS)
|
||||
// Handle cases like: `auto f() -> auto` or `auto f() -> C auto`.
|
||||
if (AutoType *Auto = T->getContainedAutoType())
|
||||
if (S.getCurScope()->isFunctionDeclarationScope())
|
||||
T = InventTemplateParameter(state, T, TInfo, Auto,
|
||||
S.InventedParameterInfos.back());
|
||||
}
|
||||
} else {
|
||||
// This function type is not the type of the entity being declared,
|
||||
// so checking the 'auto' is not the responsibility of this chunk.
|
||||
|
@ -5355,8 +5242,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
|
|||
//
|
||||
// We represent function parameter packs as function parameters whose
|
||||
// type is a pack expansion.
|
||||
if (!T->containsUnexpandedParameterPack() &&
|
||||
(!LangOpts.ConceptsTS || !T->getContainedAutoType())) {
|
||||
if (!T->containsUnexpandedParameterPack()) {
|
||||
S.Diag(D.getEllipsisLoc(),
|
||||
diag::err_function_parameter_pack_without_parameter_packs)
|
||||
<< T << D.getSourceRange();
|
||||
|
@ -5564,15 +5450,14 @@ static void fillAttributedTypeLoc(AttributedTypeLoc TL,
|
|||
|
||||
namespace {
|
||||
class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> {
|
||||
Sema &SemaRef;
|
||||
ASTContext &Context;
|
||||
TypeProcessingState &State;
|
||||
const DeclSpec &DS;
|
||||
|
||||
public:
|
||||
TypeSpecLocFiller(Sema &S, ASTContext &Context, TypeProcessingState &State,
|
||||
TypeSpecLocFiller(ASTContext &Context, TypeProcessingState &State,
|
||||
const DeclSpec &DS)
|
||||
: SemaRef(S), Context(Context), State(State), DS(DS) {}
|
||||
: Context(Context), State(State), DS(DS) {}
|
||||
|
||||
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
|
||||
Visit(TL.getModifiedLoc());
|
||||
|
@ -5700,32 +5585,6 @@ namespace {
|
|||
TL.copy(
|
||||
TInfo->getTypeLoc().castAs<DependentTemplateSpecializationTypeLoc>());
|
||||
}
|
||||
void VisitAutoTypeLoc(AutoTypeLoc TL) {
|
||||
assert(DS.getTypeSpecType() == TST_auto ||
|
||||
DS.getTypeSpecType() == TST_decltype_auto ||
|
||||
DS.getTypeSpecType() == TST_auto_type ||
|
||||
DS.getTypeSpecType() == TST_unspecified);
|
||||
TL.setNameLoc(DS.getTypeSpecTypeLoc());
|
||||
if (!DS.isConstrainedAuto())
|
||||
return;
|
||||
TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId();
|
||||
if (DS.getTypeSpecScope().isNotEmpty())
|
||||
TL.setNestedNameSpecifierLoc(
|
||||
DS.getTypeSpecScope().getWithLocInContext(Context));
|
||||
else
|
||||
TL.setNestedNameSpecifierLoc(NestedNameSpecifierLoc());
|
||||
TL.setConceptNameLoc(TemplateId->TemplateNameLoc);
|
||||
TL.setLAngleLoc(TemplateId->LAngleLoc);
|
||||
TL.setRAngleLoc(TemplateId->RAngleLoc);
|
||||
if (TemplateId->NumArgs == 0)
|
||||
return;
|
||||
TemplateArgumentListInfo TemplateArgsInfo;
|
||||
ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
|
||||
TemplateId->NumArgs);
|
||||
SemaRef.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo);
|
||||
for (unsigned I = 0; I < TemplateId->NumArgs; ++I)
|
||||
TL.setArgLocInfo(I, TemplateArgsInfo.arguments()[I].getLocInfo());
|
||||
}
|
||||
void VisitTagTypeLoc(TagTypeLoc TL) {
|
||||
TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
|
||||
}
|
||||
|
@ -5995,7 +5854,7 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
|
|||
assert(TL.getFullDataSize() == CurrTL.getFullDataSize());
|
||||
memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize());
|
||||
} else {
|
||||
TypeSpecLocFiller(S, S.Context, State, D.getDeclSpec()).Visit(CurrTL);
|
||||
TypeSpecLocFiller(S.Context, State, D.getDeclSpec()).Visit(CurrTL);
|
||||
}
|
||||
|
||||
return TInfo;
|
||||
|
|
|
@ -951,16 +951,12 @@ public:
|
|||
/// Build a new C++11 auto type.
|
||||
///
|
||||
/// By default, builds a new AutoType with the given deduced type.
|
||||
QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword,
|
||||
ConceptDecl *TypeConstraintConcept,
|
||||
ArrayRef<TemplateArgument> TypeConstraintArgs) {
|
||||
QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword) {
|
||||
// Note, IsDependent is always false here: we implicitly convert an 'auto'
|
||||
// which has been deduced to a dependent type into an undeduced 'auto', so
|
||||
// that we'll retry deduction after the transformation.
|
||||
return SemaRef.Context.getAutoType(Deduced, Keyword,
|
||||
/*IsDependent*/ false, /*IsPack=*/false,
|
||||
TypeConstraintConcept,
|
||||
TypeConstraintArgs);
|
||||
/*IsDependent*/ false);
|
||||
}
|
||||
|
||||
/// By default, builds a new DeducedTemplateSpecializationType with the given
|
||||
|
@ -4504,10 +4500,7 @@ QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T,
|
|||
Deduced =
|
||||
SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Qs);
|
||||
T = SemaRef.Context.getAutoType(Deduced, AutoTy->getKeyword(),
|
||||
AutoTy->isDependentType(),
|
||||
/*isPack=*/false,
|
||||
AutoTy->getTypeConstraintConcept(),
|
||||
AutoTy->getTypeConstraintArguments());
|
||||
AutoTy->isDependentType());
|
||||
} else {
|
||||
// Otherwise, complain about the addition of a qualifier to an
|
||||
// already-qualified type.
|
||||
|
@ -5240,29 +5233,21 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
|
|||
PackExpansionTypeLoc ExpansionTL = TL.castAs<PackExpansionTypeLoc>();
|
||||
TypeLoc Pattern = ExpansionTL.getPatternLoc();
|
||||
SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
|
||||
assert(Unexpanded.size() > 0 && "Could not find parameter packs!");
|
||||
|
||||
// Determine whether we should expand the parameter packs.
|
||||
bool ShouldExpand = false;
|
||||
bool RetainExpansion = false;
|
||||
Optional<unsigned> OrigNumExpansions;
|
||||
if (Unexpanded.size() > 0) {
|
||||
OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions();
|
||||
NumExpansions = OrigNumExpansions;
|
||||
if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
|
||||
Pattern.getSourceRange(),
|
||||
Unexpanded,
|
||||
ShouldExpand,
|
||||
RetainExpansion,
|
||||
NumExpansions)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
#ifndef NDEBUG
|
||||
const AutoType *AT =
|
||||
Pattern.getType().getTypePtr()->getContainedAutoType();
|
||||
assert((AT && (!AT->isDeduced() || AT->getDeducedType().isNull())) &&
|
||||
"Could not find parameter packs or undeduced auto type!");
|
||||
#endif
|
||||
Optional<unsigned> OrigNumExpansions =
|
||||
ExpansionTL.getTypePtr()->getNumExpansions();
|
||||
NumExpansions = OrigNumExpansions;
|
||||
if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
|
||||
Pattern.getSourceRange(),
|
||||
Unexpanded,
|
||||
ShouldExpand,
|
||||
RetainExpansion,
|
||||
NumExpansions)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ShouldExpand) {
|
||||
|
@ -5322,9 +5307,6 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
|
|||
indexAdjustment,
|
||||
NumExpansions,
|
||||
/*ExpectParameterPack=*/true);
|
||||
assert(NewParm->isParameterPack() &&
|
||||
"Parameter pack no longer a parameter pack after "
|
||||
"transformation.");
|
||||
} else {
|
||||
NewParm = getDerived().TransformFunctionTypeParam(
|
||||
OldParm, indexAdjustment, None, /*ExpectParameterPack=*/ false);
|
||||
|
@ -5829,6 +5811,32 @@ QualType TreeTransform<Derived>::TransformUnaryTransformType(
|
|||
return Result;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
|
||||
AutoTypeLoc TL) {
|
||||
const AutoType *T = TL.getTypePtr();
|
||||
QualType OldDeduced = T->getDeducedType();
|
||||
QualType NewDeduced;
|
||||
if (!OldDeduced.isNull()) {
|
||||
NewDeduced = getDerived().TransformType(OldDeduced);
|
||||
if (NewDeduced.isNull())
|
||||
return QualType();
|
||||
}
|
||||
|
||||
QualType Result = TL.getType();
|
||||
if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced ||
|
||||
T->isDependentType()) {
|
||||
Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword());
|
||||
if (Result.isNull())
|
||||
return QualType();
|
||||
}
|
||||
|
||||
AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
|
||||
NewTL.setNameLoc(TL.getNameLoc());
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformDeducedTemplateSpecializationType(
|
||||
TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) {
|
||||
|
@ -6090,71 +6098,6 @@ QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB,
|
|||
}
|
||||
};
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
|
||||
AutoTypeLoc TL) {
|
||||
const AutoType *T = TL.getTypePtr();
|
||||
QualType OldDeduced = T->getDeducedType();
|
||||
QualType NewDeduced;
|
||||
if (!OldDeduced.isNull()) {
|
||||
NewDeduced = getDerived().TransformType(OldDeduced);
|
||||
if (NewDeduced.isNull())
|
||||
return QualType();
|
||||
}
|
||||
|
||||
ConceptDecl *NewCD = nullptr;
|
||||
TemplateArgumentListInfo NewTemplateArgs;
|
||||
NestedNameSpecifierLoc NewNestedNameSpec;
|
||||
if (TL.getTypePtr()->isConstrained()) {
|
||||
NewCD = cast_or_null<ConceptDecl>(
|
||||
getDerived().TransformDecl(
|
||||
TL.getConceptNameLoc(),
|
||||
TL.getTypePtr()->getTypeConstraintConcept()));
|
||||
|
||||
NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc());
|
||||
NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc());
|
||||
typedef TemplateArgumentLocContainerIterator<AutoTypeLoc> ArgIterator;
|
||||
if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0),
|
||||
ArgIterator(TL,
|
||||
TL.getNumArgs()),
|
||||
NewTemplateArgs))
|
||||
return QualType();
|
||||
|
||||
if (TL.getNestedNameSpecifierLoc()) {
|
||||
NewNestedNameSpec
|
||||
= getDerived().TransformNestedNameSpecifierLoc(
|
||||
TL.getNestedNameSpecifierLoc());
|
||||
if (!NewNestedNameSpec)
|
||||
return QualType();
|
||||
}
|
||||
}
|
||||
|
||||
QualType Result = TL.getType();
|
||||
if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced ||
|
||||
T->isDependentType()) {
|
||||
llvm::SmallVector<TemplateArgument, 4> NewArgList;
|
||||
NewArgList.reserve(NewArgList.size());
|
||||
for (const auto &ArgLoc : NewTemplateArgs.arguments())
|
||||
NewArgList.push_back(ArgLoc.getArgument());
|
||||
Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword(), NewCD,
|
||||
NewArgList);
|
||||
if (Result.isNull())
|
||||
return QualType();
|
||||
}
|
||||
|
||||
AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
|
||||
NewTL.setNameLoc(TL.getNameLoc());
|
||||
NewTL.setNestedNameSpecifierLoc(NewNestedNameSpec);
|
||||
NewTL.setTemplateKWLoc(TL.getTemplateKWLoc());
|
||||
NewTL.setConceptNameLoc(TL.getConceptNameLoc());
|
||||
NewTL.setFoundDecl(TL.getFoundDecl());
|
||||
NewTL.setLAngleLoc(TL.getLAngleLoc());
|
||||
NewTL.setRAngleLoc(TL.getRAngleLoc());
|
||||
for (unsigned I = 0; I < TL.getNumArgs(); ++I)
|
||||
NewTL.setArgLocInfo(I, NewTemplateArgs.arguments()[I].getLocInfo());
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
|
||||
|
|
|
@ -6576,17 +6576,6 @@ void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
|
|||
|
||||
void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
|
||||
TL.setNameLoc(readSourceLocation());
|
||||
if (Reader.readBool()) {
|
||||
TL.setNestedNameSpecifierLoc(ReadNestedNameSpecifierLoc());
|
||||
TL.setTemplateKWLoc(readSourceLocation());
|
||||
TL.setConceptNameLoc(readSourceLocation());
|
||||
TL.setFoundDecl(Reader.readDeclAs<NamedDecl>());
|
||||
TL.setLAngleLoc(readSourceLocation());
|
||||
TL.setRAngleLoc(readSourceLocation());
|
||||
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
|
||||
TL.setArgLocInfo(i, Reader.readTemplateArgumentLocInfo(
|
||||
TL.getTypePtr()->getArg(i).getKind()));
|
||||
}
|
||||
}
|
||||
|
||||
void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc(
|
||||
|
|
|
@ -2317,12 +2317,12 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
|
|||
|
||||
D->setDeclaredWithTypename(Record.readInt());
|
||||
|
||||
if (Record.readBool()) {
|
||||
if (Record.readInt()) {
|
||||
NestedNameSpecifierLoc NNS = Record.readNestedNameSpecifierLoc();
|
||||
DeclarationNameInfo DN = Record.readDeclarationNameInfo();
|
||||
ConceptDecl *NamedConcept = Record.readDeclAs<ConceptDecl>();
|
||||
ConceptDecl *NamedConcept = cast<ConceptDecl>(Record.readDecl());
|
||||
const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
|
||||
if (Record.readBool())
|
||||
if (Record.readInt())
|
||||
ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
|
||||
Expr *ImmediatelyDeclaredConstraint = Record.readExpr();
|
||||
D->setTypeConstraint(NNS, DN, /*FoundDecl=*/nullptr, NamedConcept,
|
||||
|
@ -2340,8 +2340,6 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
|
|||
// TemplateParmPosition.
|
||||
D->setDepth(Record.readInt());
|
||||
D->setPosition(Record.readInt());
|
||||
if (D->hasPlaceholderTypeConstraint())
|
||||
D->setPlaceholderTypeConstraint(Record.readExpr());
|
||||
if (D->isExpandedParameterPack()) {
|
||||
auto TypesAndInfos =
|
||||
D->getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>();
|
||||
|
@ -3825,19 +3823,13 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
|
|||
HasTypeConstraint);
|
||||
break;
|
||||
}
|
||||
case DECL_NON_TYPE_TEMPLATE_PARM: {
|
||||
bool HasTypeConstraint = Record.readInt();
|
||||
D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID,
|
||||
HasTypeConstraint);
|
||||
case DECL_NON_TYPE_TEMPLATE_PARM:
|
||||
D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID);
|
||||
break;
|
||||
}
|
||||
case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK: {
|
||||
bool HasTypeConstraint = Record.readInt();
|
||||
case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK:
|
||||
D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID,
|
||||
Record.readInt(),
|
||||
HasTypeConstraint);
|
||||
Record.readInt());
|
||||
break;
|
||||
}
|
||||
case DECL_TEMPLATE_TEMPLATE_PARM:
|
||||
D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID);
|
||||
break;
|
||||
|
|
|
@ -349,18 +349,6 @@ void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
|
|||
|
||||
void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {
|
||||
Record.AddSourceLocation(TL.getNameLoc());
|
||||
Record.push_back(TL.isConstrained());
|
||||
if (TL.isConstrained()) {
|
||||
Record.AddNestedNameSpecifierLoc(TL.getNestedNameSpecifierLoc());
|
||||
Record.AddSourceLocation(TL.getTemplateKWLoc());
|
||||
Record.AddSourceLocation(TL.getConceptNameLoc());
|
||||
Record.AddDeclRef(TL.getFoundDecl());
|
||||
Record.AddSourceLocation(TL.getLAngleLoc());
|
||||
Record.AddSourceLocation(TL.getRAngleLoc());
|
||||
for (unsigned I = 0; I < TL.getNumArgs(); ++I)
|
||||
Record.AddTemplateArgumentLocInfo(TL.getTypePtr()->getArg(I).getKind(),
|
||||
TL.getArgLocInfo(I));
|
||||
}
|
||||
}
|
||||
|
||||
void TypeLocWriter::VisitDeducedTemplateSpecializationTypeLoc(
|
||||
|
|
|
@ -1675,8 +1675,6 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
|
|||
// For an expanded parameter pack, record the number of expansion types here
|
||||
// so that it's easier for deserialization to allocate the right amount of
|
||||
// memory.
|
||||
Expr *TypeConstraint = D->getPlaceholderTypeConstraint();
|
||||
Record.push_back(!!TypeConstraint);
|
||||
if (D->isExpandedParameterPack())
|
||||
Record.push_back(D->getNumExpansionTypes());
|
||||
|
||||
|
@ -1684,8 +1682,6 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
|
|||
// TemplateParmPosition.
|
||||
Record.push_back(D->getDepth());
|
||||
Record.push_back(D->getPosition());
|
||||
if (TypeConstraint)
|
||||
Record.AddStmt(TypeConstraint);
|
||||
|
||||
if (D->isExpandedParameterPack()) {
|
||||
for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) {
|
||||
|
|
|
@ -417,24 +417,15 @@ struct DoesNotAllowConstDefaultInit {
|
|||
// CHECK-NEXT: "id": "0x{{.*}}",
|
||||
// CHECK-NEXT: "kind": "TemplateTypeParmDecl",
|
||||
// CHECK-NEXT: "loc": {
|
||||
// CHECK-NEXT: "offset": 197,
|
||||
// CHECK-NEXT: "col": 33,
|
||||
// CHECK-NEXT: "tokLen": 1
|
||||
// CHECK-NEXT: "offset": 193,
|
||||
// CHECK-NEXT: "col": 29,
|
||||
// CHECK-NEXT: "tokLen": 4
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "range": {
|
||||
// CHECK-NEXT: "begin": {
|
||||
// CHECK-NEXT: "offset": 193,
|
||||
// CHECK-NEXT: "col": 29,
|
||||
// CHECK-NEXT: "tokLen": 4
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "end": {
|
||||
// CHECK-NEXT: "offset": 197,
|
||||
// CHECK-NEXT: "col": 33,
|
||||
// CHECK-NEXT: "tokLen": 1
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: "begin": {},
|
||||
// CHECK-NEXT: "end": {}
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "isImplicit": true,
|
||||
// CHECK-NEXT: "name": "auto:1",
|
||||
// CHECK-NEXT: "tagUsed": "class",
|
||||
// CHECK-NEXT: "depth": 0,
|
||||
// CHECK-NEXT: "index": 0
|
||||
|
@ -533,24 +524,15 @@ struct DoesNotAllowConstDefaultInit {
|
|||
// CHECK-NEXT: "id": "0x{{.*}}",
|
||||
// CHECK-NEXT: "kind": "TemplateTypeParmDecl",
|
||||
// CHECK-NEXT: "loc": {
|
||||
// CHECK-NEXT: "offset": 197,
|
||||
// CHECK-NEXT: "col": 33,
|
||||
// CHECK-NEXT: "tokLen": 1
|
||||
// CHECK-NEXT: "offset": 193,
|
||||
// CHECK-NEXT: "col": 29,
|
||||
// CHECK-NEXT: "tokLen": 4
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "range": {
|
||||
// CHECK-NEXT: "begin": {
|
||||
// CHECK-NEXT: "offset": 193,
|
||||
// CHECK-NEXT: "col": 29,
|
||||
// CHECK-NEXT: "tokLen": 4
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "end": {
|
||||
// CHECK-NEXT: "offset": 197,
|
||||
// CHECK-NEXT: "col": 33,
|
||||
// CHECK-NEXT: "tokLen": 1
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: "begin": {},
|
||||
// CHECK-NEXT: "end": {}
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "isImplicit": true,
|
||||
// CHECK-NEXT: "name": "auto:1",
|
||||
// CHECK-NEXT: "tagUsed": "class",
|
||||
// CHECK-NEXT: "depth": 0,
|
||||
// CHECK-NEXT: "index": 0
|
||||
|
@ -608,24 +590,15 @@ struct DoesNotAllowConstDefaultInit {
|
|||
// CHECK-NEXT: "id": "0x{{.*}}",
|
||||
// CHECK-NEXT: "kind": "TemplateTypeParmDecl",
|
||||
// CHECK-NEXT: "loc": {
|
||||
// CHECK-NEXT: "offset": 197,
|
||||
// CHECK-NEXT: "col": 33,
|
||||
// CHECK-NEXT: "tokLen": 1
|
||||
// CHECK-NEXT: "offset": 193,
|
||||
// CHECK-NEXT: "col": 29,
|
||||
// CHECK-NEXT: "tokLen": 4
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "range": {
|
||||
// CHECK-NEXT: "begin": {
|
||||
// CHECK-NEXT: "offset": 193,
|
||||
// CHECK-NEXT: "col": 29,
|
||||
// CHECK-NEXT: "tokLen": 4
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "end": {
|
||||
// CHECK-NEXT: "offset": 197,
|
||||
// CHECK-NEXT: "col": 33,
|
||||
// CHECK-NEXT: "tokLen": 1
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: "begin": {},
|
||||
// CHECK-NEXT: "end": {}
|
||||
// CHECK-NEXT: },
|
||||
// CHECK-NEXT: "isImplicit": true,
|
||||
// CHECK-NEXT: "name": "auto:1",
|
||||
// CHECK-NEXT: "tagUsed": "class",
|
||||
// CHECK-NEXT: "depth": 0,
|
||||
// CHECK-NEXT: "index": 0
|
||||
|
|
|
@ -1,260 +0,0 @@
|
|||
// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
|
||||
template<typename T, typename U> constexpr bool is_same_v = false;
|
||||
template<typename T> constexpr bool is_same_v<T, T> = true;
|
||||
|
||||
template<typename... T>
|
||||
struct type_list;
|
||||
|
||||
namespace unconstrained {
|
||||
decltype(auto) f1(auto x) { return x; }
|
||||
static_assert(is_same_v<decltype(f1(1)), int>);
|
||||
static_assert(is_same_v<decltype(f1('c')), char>);
|
||||
|
||||
decltype(auto) f2(auto &x) { return x; }
|
||||
// expected-note@-1{{candidate function [with x:auto = int] not viable: expects an l-value for 1st argument}}
|
||||
// expected-note@-2{{candidate function [with x:auto = char] not viable: expects an l-value for 1st argument}}
|
||||
static_assert(is_same_v<decltype(f2(1)), int &>); // expected-error{{no matching}}
|
||||
static_assert(is_same_v<decltype(f2('c')), char &>); // expected-error{{no matching}}
|
||||
|
||||
decltype(auto) f3(const auto &x) { return x; }
|
||||
static_assert(is_same_v<decltype(f3(1)), const int &>);
|
||||
static_assert(is_same_v<decltype(f3('c')), const char &>);
|
||||
|
||||
decltype(auto) f4(auto (*x)(auto y)) { return x; } // expected-error{{'auto' not allowed in function prototype}}
|
||||
|
||||
decltype(auto) f5(void (*x)(decltype(auto) y)) { return x; } // expected-error{{'decltype(auto)' not allowed in function prototype}}
|
||||
|
||||
int return_int(); void return_void(); int foo(int);
|
||||
|
||||
decltype(auto) f6(auto (*x)()) { return x; }
|
||||
// expected-note@-1{{candidate template ignored: failed template argument deduction}}
|
||||
static_assert(is_same_v<decltype(f6(return_int)), int (*)()>);
|
||||
static_assert(is_same_v<decltype(f6(return_void)), void (*)()>);
|
||||
using f6c1 = decltype(f6(foo)); // expected-error{{no matching}}
|
||||
|
||||
decltype(auto) f7(auto (*x)() -> int) { return x; }
|
||||
// expected-note@-1{{candidate function not viable: no known conversion from 'void ()' to 'auto (*)() -> int' for 1st argument}}
|
||||
// expected-note@-2{{candidate function not viable: no known conversion from 'int (int)' to 'auto (*)() -> int' for 1st argument}}
|
||||
static_assert(is_same_v<decltype(f7(return_int)), int (*)()>);
|
||||
using f7c1 = decltype(f7(return_void)); // expected-error{{no matching}}
|
||||
using f7c2 = decltype(f7(foo)); // expected-error{{no matching}}
|
||||
static_assert(is_same_v<decltype(&f7), int (*(*)(int (*x)()))()>);
|
||||
|
||||
decltype(auto) f8(auto... x) { return (x + ...); }
|
||||
static_assert(is_same_v<decltype(f8(1, 2, 3)), int>);
|
||||
static_assert(is_same_v<decltype(f8('c', 'd')), int>);
|
||||
static_assert(is_same_v<decltype(f8('c', 1)), int>);
|
||||
|
||||
decltype(auto) f9(auto &... x) { return (x, ...); }
|
||||
// expected-note@-1{{candidate function [with x:auto = <int (), int>] not viable: expects an l-value for 2nd argument}}
|
||||
using f9c1 = decltype(f9(return_int, 1)); // expected-error{{no matching}}
|
||||
|
||||
decltype(auto) f11(decltype(auto) x) { return x; } // expected-error{{'decltype(auto)' not allowed in function prototype}}
|
||||
|
||||
template<typename T>
|
||||
auto f12(auto x, T y) -> type_list<T, decltype(x)>;
|
||||
static_assert(is_same_v<decltype(f12(1, 'c')), type_list<char, int>>);
|
||||
static_assert(is_same_v<decltype(f12<char>(1, 'c')), type_list<char, int>>);
|
||||
|
||||
template<typename T>
|
||||
auto f13(T x, auto y) -> type_list<T, decltype(y)>;
|
||||
static_assert(is_same_v<decltype(f13(1, 'c')), type_list<int, char>>);
|
||||
static_assert(is_same_v<decltype(f13<char>(1, 'c')), type_list<char, char>>);
|
||||
|
||||
template<typename T>
|
||||
auto f14(auto y) -> type_list<T, decltype(y)>;
|
||||
static_assert(is_same_v<decltype(f14<int>('c')), type_list<int, char>>);
|
||||
static_assert(is_same_v<decltype(f14<int, char>('c')), type_list<int, char>>);
|
||||
|
||||
template<typename T, typename U>
|
||||
auto f15(auto y, U u) -> type_list<T, U, decltype(y)>;
|
||||
static_assert(is_same_v<decltype(f15<int>('c', nullptr)), type_list<int, decltype(nullptr), char>>);
|
||||
static_assert(is_same_v<decltype(f15<int, decltype(nullptr)>('c', nullptr)), type_list<int, decltype(nullptr), char>>);
|
||||
|
||||
auto f16(auto x, auto y) -> type_list<decltype(x), decltype(y)>;
|
||||
static_assert(is_same_v<decltype(f16('c', 1)), type_list<char, int>>);
|
||||
static_assert(is_same_v<decltype(f16<int>('c', 1)), type_list<int, int>>);
|
||||
static_assert(is_same_v<decltype(f16<int, char>('c', 1)), type_list<int, char>>);
|
||||
|
||||
void f17(auto x, auto y) requires (sizeof(x) > 1);
|
||||
// expected-note@-1{{candidate template ignored: constraints not satisfied [with x:auto = char, y:auto = int]}}
|
||||
// expected-note@-2{{because 'sizeof (x) > 1' (1 > 1) evaluated to false}}
|
||||
static_assert(is_same_v<decltype(f17('c', 1)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(f17<int>('c', 1)), void>);
|
||||
static_assert(is_same_v<decltype(f17<int, char>('c', 1)), void>);
|
||||
|
||||
void f18(auto... x) requires (sizeof...(x) == 2);
|
||||
// expected-note@-1{{candidate template ignored: constraints not satisfied [with x:auto = <char, int, int>]}}
|
||||
// expected-note@-2{{candidate template ignored: constraints not satisfied [with x:auto = <char>]}}
|
||||
// expected-note@-3{{because 'sizeof...(x) == 2' (1 == 2) evaluated to false}}
|
||||
// expected-note@-4{{because 'sizeof...(x) == 2' (3 == 2) evaluated to false}}
|
||||
static_assert(is_same_v<decltype(f18('c')), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(f18('c', 1)), void>);
|
||||
static_assert(is_same_v<decltype(f18('c', 1, 2)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
|
||||
template<typename T>
|
||||
struct S {
|
||||
constexpr auto f1(auto x, T t) -> decltype(x + t);
|
||||
|
||||
template<typename U>
|
||||
constexpr auto f2(U u, auto x, T t) -> decltype(x + u + t);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr auto S<T>::f1(auto x, T t) -> decltype(x + t) { return x + t; }
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
constexpr auto S<T>::f2(auto x, U u, T t) -> decltype(x + u + t) { return x + u + t; }
|
||||
// expected-error@-1 {{out-of-line definition of 'f2' does not match any declaration in 'S<T>'}}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
constexpr auto S<T>::f2(U u, auto x, T t) -> decltype(x + u + t) { return x + u + t; }
|
||||
|
||||
template<>
|
||||
template<>
|
||||
constexpr auto S<int>::f2<double>(double u, char x, int t) -> double { return 42; }
|
||||
|
||||
static_assert(S<char>{}.f1(1, 2) == 3);
|
||||
static_assert(S<char>{}.f2(1, 2, '\x00') == 3);
|
||||
static_assert(S<char>{}.f2<double>(1, 2, '\x00') == 3.);
|
||||
static_assert(S<int>{}.f2<double>(1, '2', '\x00') == 42);
|
||||
}
|
||||
|
||||
namespace constrained {
|
||||
template<typename T>
|
||||
concept C = is_same_v<T, int>;
|
||||
// expected-note@-1 12{{because}}
|
||||
template<typename T, typename U>
|
||||
concept C2 = is_same_v<T, U>;
|
||||
// expected-note@-1 12{{because}}
|
||||
|
||||
int i;
|
||||
const int ci = 1;
|
||||
char c;
|
||||
const char cc = 'a';
|
||||
int g(int);
|
||||
char h(int);
|
||||
|
||||
void f1(C auto x);
|
||||
// expected-note@-1 {{candidate template ignored: constraints not satisfied [with x:auto = }}
|
||||
// expected-note@-2{{because}}
|
||||
static_assert(is_same_v<decltype(f1(1)), void>);
|
||||
static_assert(is_same_v<decltype(f1('a')), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
void f2(C auto &x);
|
||||
// expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}}
|
||||
static_assert(is_same_v<decltype(f2(i)), void>);
|
||||
static_assert(is_same_v<decltype(f2(ci)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(f2(c)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
void f3(const C auto &x);
|
||||
// expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
|
||||
static_assert(is_same_v<decltype(f3(i)), void>);
|
||||
static_assert(is_same_v<decltype(f3(ci)), void>);
|
||||
static_assert(is_same_v<decltype(f3(c)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
void f4(C auto (*x)(C auto y)); // expected-error{{'auto' not allowed}}
|
||||
void f5(C auto (*x)(int y));
|
||||
// expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
|
||||
static_assert(is_same_v<decltype(f5(g)), void>);
|
||||
static_assert(is_same_v<decltype(f5(h)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
void f6(C auto (*x)() -> int); // expected-error{{function with trailing return type must specify return type 'auto', not 'C auto'}}
|
||||
void f7(C auto... x);
|
||||
// expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}}
|
||||
static_assert(is_same_v<decltype(f7(1, 2)), void>);
|
||||
static_assert(is_same_v<decltype(f7(1, 'a')), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(f7('a', 2)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
void f8(C auto &... x);
|
||||
// expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}}
|
||||
static_assert(is_same_v<decltype(f8(i, i)), void>);
|
||||
static_assert(is_same_v<decltype(f8(i, c)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(f8(i, i, ci)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
void f9(const C auto &... x);
|
||||
// expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
|
||||
static_assert(is_same_v<decltype(f9(i, i)), void>);
|
||||
static_assert(is_same_v<decltype(f9(i, c)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(f9(i, i, ci)), void>);
|
||||
void f10(C decltype(auto) x);
|
||||
auto f11 = [] (C auto x) { };
|
||||
// expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
|
||||
static_assert(is_same_v<decltype(f11(1)), void>);
|
||||
static_assert(is_same_v<decltype(f11('a')), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
|
||||
void f12(C2<char> auto x);
|
||||
// expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
|
||||
static_assert(is_same_v<decltype(f12(1)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(f12('a')), void>);
|
||||
void f13(C2<char> auto &x);
|
||||
// expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}}
|
||||
static_assert(is_same_v<decltype(f13(i)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(f13(cc)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(f13(c)), void>);
|
||||
void f14(const C2<char> auto &x);
|
||||
// expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
|
||||
static_assert(is_same_v<decltype(f14(i)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(f14(cc)), void>);
|
||||
static_assert(is_same_v<decltype(f14(c)), void>);
|
||||
void f15(C2<char> auto (*x)(C2<int> auto y)); // expected-error{{'auto' not allowed}}
|
||||
void f16(C2<char> auto (*x)(int y));
|
||||
// expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
|
||||
static_assert(is_same_v<decltype(f16(g)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(f16(h)), void>);
|
||||
void f17(C2<char> auto (*x)() -> int); // expected-error{{function with trailing return type must specify return type 'auto', not 'C2<char> auto'}}
|
||||
void f18(C2<char> auto... x);
|
||||
// expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}}
|
||||
static_assert(is_same_v<decltype(f18('a', 'b')), void>);
|
||||
static_assert(is_same_v<decltype(f18('a', 1)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(f18(2, 'a')), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
void f19(C2<char> auto &... x);
|
||||
// expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}}
|
||||
static_assert(is_same_v<decltype(f19(c, c)), void>);
|
||||
static_assert(is_same_v<decltype(f19(i, c)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(f19(c, c, cc)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
void f20(const C2<char> auto &... x);
|
||||
// expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
|
||||
static_assert(is_same_v<decltype(f20(c, c)), void>);
|
||||
static_assert(is_same_v<decltype(f20(i, c)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(f20(c, c, cc)), void>);
|
||||
void f21(C2<char> decltype(auto) x);
|
||||
auto f22 = [] (C2<char> auto x) { };
|
||||
// expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
|
||||
static_assert(is_same_v<decltype(f22(1)), void>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(f22('a')), void>);
|
||||
|
||||
struct S1 { S1(C auto); };
|
||||
// expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
|
||||
// expected-note@-2 2{{candidate constructor}}
|
||||
static_assert(is_same_v<decltype(S1(1)), S1>);
|
||||
static_assert(is_same_v<decltype(S1('a')), S1>);
|
||||
// expected-error@-1{{no matching}}
|
||||
struct S2 { S2(C2<char> auto); };
|
||||
// expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
|
||||
// expected-note@-2 2{{candidate constructor}}
|
||||
static_assert(is_same_v<decltype(S2(1)), S2>);
|
||||
// expected-error@-1{{no matching}}
|
||||
static_assert(is_same_v<decltype(S2('a')), S2>);
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
|
||||
|
||||
template<typename T, unsigned size>
|
||||
concept LargerThan = sizeof(T) > size;
|
||||
// expected-note@-1 2{{because 'sizeof(char) > 1U' (1 > 1) evaluated to false}}
|
||||
// expected-note@-2 {{because 'sizeof(int) > 10U' (4 > 10) evaluated to false}}
|
||||
// expected-note@-3 {{because 'sizeof(int) > 4U' (4 > 4) evaluated to false}}
|
||||
|
||||
template<typename T>
|
||||
concept Large = LargerThan<T, 1>;
|
||||
// expected-note@-1 2{{because 'LargerThan<char, 1>' evaluated to false}}
|
||||
|
||||
namespace X {
|
||||
template<typename T, unsigned size>
|
||||
concept SmallerThan = sizeof(T) < size;
|
||||
template<typename T>
|
||||
concept Small = SmallerThan<T, 2>;
|
||||
}
|
||||
|
||||
Large auto test1() { // expected-error{{deduced type 'char' does not satisfy 'Large'}}
|
||||
Large auto i = 'a';
|
||||
// expected-error@-1{{deduced type 'char' does not satisfy 'Large'}}
|
||||
Large auto j = 10;
|
||||
::Large auto k = 10;
|
||||
LargerThan<1> auto l = 10;
|
||||
::LargerThan<1> auto m = 10;
|
||||
LargerThan<10> auto n = 10;
|
||||
// expected-error@-1{{deduced type 'int' does not satisfy 'LargerThan<10>'}}
|
||||
X::Small auto o = 'x';
|
||||
X::SmallerThan<5> auto p = 1;
|
||||
return 'a';
|
||||
}
|
||||
|
||||
::Large auto test2() { return 10; }
|
||||
LargerThan<4> auto test3() { return 10; }
|
||||
// expected-error@-1{{deduced type 'int' does not satisfy 'LargerThan<4>'}}
|
||||
::LargerThan<2> auto test4() { return 10; }
|
||||
|
||||
Large auto test5() -> void;
|
||||
// expected-error@-1{{function with trailing return type must specify return type 'auto', not 'Large auto'}}
|
||||
auto test6() -> Large auto { return 1; }
|
||||
|
||||
X::Small auto test7() { return 'a'; }
|
||||
X::SmallerThan<5> auto test8() { return 10; }
|
|
@ -1,7 +1,7 @@
|
|||
// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
|
||||
|
||||
auto l1 = [] (auto x) requires (sizeof(decltype(x)) == 1) { return x; };
|
||||
// expected-note@-1{{candidate template ignored: constraints not satisfied [with x:auto = int]}}
|
||||
// expected-note@-1{{candidate template ignored: constraints not satisfied [with $0 = int]}}
|
||||
// expected-note@-2{{because 'sizeof(decltype(x)) == 1' (4 == 1) evaluated to false}}
|
||||
|
||||
auto l1t1 = l1('a');
|
||||
|
@ -9,8 +9,8 @@ auto l1t2 = l1(1);
|
|||
// expected-error@-1{{no matching function for call to object of type '(lambda at}}
|
||||
|
||||
auto l2 = [] (auto... x) requires ((sizeof(decltype(x)) >= 2) && ...) { return (x + ...); };
|
||||
// expected-note@-1{{candidate template ignored: constraints not satisfied [with x:auto = <char>]}}
|
||||
// expected-note@-2{{candidate template ignored: constraints not satisfied [with x:auto = <int, char>]}}
|
||||
// expected-note@-1{{candidate template ignored: constraints not satisfied [with $0 = <char>]}}
|
||||
// expected-note@-2{{candidate template ignored: constraints not satisfied [with $0 = <int, char>]}}
|
||||
// expected-note@-3 2{{because 'sizeof(decltype(x)) >= 2' (1 >= 2) evaluated to false}}
|
||||
|
||||
auto l2t1 = l2('a');
|
||||
|
|
|
@ -94,8 +94,6 @@ concept OneOf = (is_same_v<T, Ts> || ...);
|
|||
// expected-note@-5 {{and 'is_same_v<short, char>' evaluated to false}}
|
||||
// expected-note@-6 3{{because 'is_same_v<int, char [1]>' evaluated to false}}
|
||||
// expected-note@-7 3{{and 'is_same_v<int, char [2]>' evaluated to false}}
|
||||
// expected-note@-8 2{{because 'is_same_v<nullptr_t, char>' evaluated to false}}
|
||||
// expected-note@-9 2{{and 'is_same_v<nullptr_t, int>' evaluated to false}}
|
||||
|
||||
template<OneOf<char[1], char[2]> T, OneOf<int, long, char> U>
|
||||
// expected-note@-1 2{{because 'OneOf<char, char [1], char [2]>' evaluated to false}}
|
||||
|
@ -116,25 +114,4 @@ using h1 = H<char[1], int>;
|
|||
// expected-error@-1 {{constraints not satisfied for alias template 'H' [with Ts = <char [1], int>]}}
|
||||
using h2 = H<int, int>;
|
||||
// expected-error@-1 {{constraints not satisfied for alias template 'H' [with Ts = <int, int>]}}
|
||||
using h3 = H<char[1], char[2]>;
|
||||
|
||||
template<OneOf<char, int> auto x>
|
||||
// expected-note@-1 {{because 'OneOf<decltype(nullptr), char, int>' evaluated to false}}
|
||||
using I = int;
|
||||
|
||||
using i1 = I<1>;
|
||||
using i2 = I<'a'>;
|
||||
using i3 = I<nullptr>;
|
||||
// expected-error@-1 {{constraints not satisfied for alias template 'I' [with x = nullptr]}}
|
||||
|
||||
template<OneOf<char, int> auto... x>
|
||||
// expected-note@-1 {{because 'OneOf<decltype(nullptr), char, int>' evaluated to false}}
|
||||
using J = int;
|
||||
|
||||
using j1 = J<1, 'b'>;
|
||||
using j2 = J<'a', nullptr>;
|
||||
// expected-error@-1 {{constraints not satisfied for alias template 'J' [with x = <'a', nullptr>]}}
|
||||
|
||||
template<OneOf<char, int> auto &x>
|
||||
// expected-error@-1 {{constrained placeholder types other than simple 'auto' on non-type template parameters not supported yet}}
|
||||
using K = int;
|
||||
using h3 = H<char[1], char[2]>;
|
|
@ -1,26 +0,0 @@
|
|||
// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ %s -verify
|
||||
|
||||
template<typename T, typename U=void>
|
||||
concept C = true;
|
||||
|
||||
int foo() {
|
||||
C auto a4 = 1;
|
||||
C<> auto a5 = 1;
|
||||
C<int> auto a6 = 1;
|
||||
const C auto &a7 = 1;
|
||||
const C<> auto &a8 = 1;
|
||||
const C<int> auto &a9 = 1;
|
||||
C decltype(auto) a10 = 1;
|
||||
C<> decltype(auto) a11 = 1;
|
||||
C<int> decltype(auto) a12 = 1;
|
||||
const C<> decltype(auto) &a13 = 1; // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}}
|
||||
// expected-error@-1{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
|
||||
const C<int> decltype(auto) &a14 = 1; // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}}
|
||||
// expected-error@-1{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
|
||||
C a15 = 1;
|
||||
// expected-error@-1{{expected 'auto' or 'decltype(auto)' after concept name}}
|
||||
C decltype a19 = 1;
|
||||
// expected-error@-1{{expected '('}}
|
||||
C decltype(1) a20 = 1;
|
||||
// expected-error@-1{{expected 'auto' or 'decltype(auto)' after concept name}}
|
||||
}
|
|
@ -181,7 +181,7 @@ int test() {
|
|||
int (*fp2)(int) = [](auto b) -> int { return b; };
|
||||
int (*fp3)(char) = [](auto c) -> int { return c; };
|
||||
char (*fp4)(int) = [](auto d) { return d; }; //expected-error{{no viable conversion}}\
|
||||
//expected-note{{candidate function [with d:auto = int]}}
|
||||
//expected-note{{candidate function [with $0 = int]}}
|
||||
char (*fp5)(char) = [](auto e) -> int { return e; }; //expected-error{{no viable conversion}}\
|
||||
//expected-note{{candidate template ignored}}
|
||||
|
||||
|
|
|
@ -93,8 +93,7 @@ namespace test_undeclared_nontype_parm_arg {
|
|||
// template parameter.
|
||||
template <typename T> struct Bar { T x; };
|
||||
|
||||
template <Bar<Xylophone> *P> // expected-error {{use of undeclared identifier 'Xylophone'}}
|
||||
// expected-note@-1{{template parameter is declared here}}
|
||||
template <Bar<Xylophone> *P> // expected-error {{use of undeclared identifier 'Xylophone'}} expected-note {{declared here}}
|
||||
struct Foo { };
|
||||
|
||||
typedef int Xylophone;
|
||||
|
|
Loading…
Reference in New Issue