[Concepts] Concept definitions (D40381)
First in a series of patches to land C++2a Concepts support. This patch adds AST and parsing support for concept-declarations. llvm-svn: 365699
This commit is contained in:
parent
0171866672
commit
d7aae33a95
|
@ -529,6 +529,11 @@ public:
|
|||
D->defaultArgumentWasInherited() ? "inherited from" : "previous");
|
||||
}
|
||||
|
||||
void VisitConceptDecl(const ConceptDecl *D) {
|
||||
dumpTemplateParameters(D->getTemplateParameters());
|
||||
Visit(D->getConstraintExpr());
|
||||
}
|
||||
|
||||
void VisitUsingShadowDecl(const UsingShadowDecl *D) {
|
||||
if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl()))
|
||||
Visit(TD->getTypeForDecl());
|
||||
|
|
|
@ -3090,6 +3090,42 @@ public:
|
|||
static bool classofKind(Kind K) { return K == VarTemplate; }
|
||||
};
|
||||
|
||||
// \brief Declaration of a C++2a concept.
|
||||
class ConceptDecl : public TemplateDecl, public Mergeable<ConceptDecl> {
|
||||
protected:
|
||||
Expr *ConstraintExpr;
|
||||
|
||||
ConceptDecl(DeclContext *DC,
|
||||
SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params,
|
||||
Expr *ConstraintExpr)
|
||||
: TemplateDecl(nullptr, Concept, DC, L, Name, Params),
|
||||
ConstraintExpr(ConstraintExpr) {};
|
||||
public:
|
||||
static ConceptDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params,
|
||||
Expr *ConstraintExpr);
|
||||
static ConceptDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
Expr *getConstraintExpr() const {
|
||||
return ConstraintExpr;
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const override LLVM_READONLY {
|
||||
return SourceRange(getTemplateParameters()->getTemplateLoc(),
|
||||
ConstraintExpr->getEndLoc());
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == Concept; }
|
||||
|
||||
friend class ASTReader;
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
};
|
||||
|
||||
inline NamedDecl *getAsNamedDecl(TemplateParameter P) {
|
||||
if (auto *PD = P.dyn_cast<TemplateTypeParmDecl *>())
|
||||
return PD;
|
||||
|
|
|
@ -1800,6 +1800,11 @@ DEF_TRAVERSE_DECL(TypeAliasTemplateDecl, {
|
|||
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ConceptDecl, {
|
||||
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
|
||||
TRY_TO(TraverseStmt(D->getConstraintExpr()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(UnresolvedUsingTypenameDecl, {
|
||||
// A dependent using declaration which was marked with 'typename'.
|
||||
// template<class T> class A : public B<T> { using typename B<T>::foo; };
|
||||
|
|
|
@ -347,6 +347,7 @@ public:
|
|||
void VisitObjCPropertyDecl(const ObjCPropertyDecl *D);
|
||||
void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D);
|
||||
void VisitBlockDecl(const BlockDecl *D);
|
||||
void VisitConceptDecl(const ConceptDecl *D);
|
||||
};
|
||||
|
||||
} // namespace clang
|
||||
|
|
|
@ -70,6 +70,7 @@ def Named : Decl<"named declarations", 1>;
|
|||
def TypeAliasTemplate : DDecl<RedeclarableTemplate>;
|
||||
def TemplateTemplateParm : DDecl<Template>;
|
||||
def BuiltinTemplate : DDecl<Template>;
|
||||
def Concept : DDecl<Template>;
|
||||
def Using : DDecl<Named>;
|
||||
def UsingPack : DDecl<Named>;
|
||||
def UsingShadow : DDecl<Named>;
|
||||
|
|
|
@ -684,7 +684,7 @@ def warn_cxx14_compat_template_template_param_typename : Warning<
|
|||
def err_template_spec_syntax_non_template : Error<
|
||||
"identifier followed by '<' indicates a class template specialization but "
|
||||
"%0 %select{does not refer to a template|refers to a function template|"
|
||||
"<unused>|refers to a variable template|<unused>}1">;
|
||||
"<unused>|refers to a variable template|<unused>|refers to a concept}1">;
|
||||
def err_id_after_template_in_nested_name_spec : Error<
|
||||
"expected template name after 'template' keyword in nested name specifier">;
|
||||
def err_unexpected_template_in_unqualified_id : Error<
|
||||
|
@ -1287,4 +1287,12 @@ def err_for_co_await_not_range_for : Error<
|
|||
"'co_await' modifier can only be applied to range-based for loop">;
|
||||
}
|
||||
|
||||
let CategoryName = "Concepts Issue" in {
|
||||
def err_concept_definition_not_identifier : Error<
|
||||
"name defined in concept definition must be an identifier">;
|
||||
def ext_concept_legacy_bool_keyword : ExtWarn<
|
||||
"ISO C++2a does not permit the 'bool' keyword after 'concept'">,
|
||||
InGroup<DiagGroup<"concepts-ts-compat">>;
|
||||
}
|
||||
|
||||
} // end of Parser diagnostics
|
||||
|
|
|
@ -2010,8 +2010,8 @@ def err_auto_not_allowed : Error<
|
|||
"%select{'auto'|'decltype(auto)'|'__auto_type'|"
|
||||
"use of "
|
||||
"%select{class template|function template|variable template|alias template|"
|
||||
"template template parameter|template}2 %3 requires template arguments; "
|
||||
"argument deduction}0 not allowed "
|
||||
"template template parameter|concept|template}2 %3 requires template "
|
||||
"arguments; argument deduction}0 not allowed "
|
||||
"%select{in function prototype"
|
||||
"|in non-static struct member|in struct member"
|
||||
"|in non-static union member|in union member"
|
||||
|
@ -2100,8 +2100,8 @@ def err_deduced_class_template_compound_type : Error<
|
|||
"deduced class template specialization type">;
|
||||
def err_deduced_non_class_template_specialization_type : Error<
|
||||
"%select{<error>|function template|variable template|alias template|"
|
||||
"template template parameter|template}0 %1 requires template arguments; "
|
||||
"argument deduction only allowed for class templates">;
|
||||
"template template parameter|concept|template}0 %1 requires template "
|
||||
"arguments; argument deduction only allowed for class templates">;
|
||||
def err_deduced_class_template_ctor_ambiguous : Error<
|
||||
"ambiguous deduction for template arguments of %0">;
|
||||
def err_deduced_class_template_ctor_no_viable : Error<
|
||||
|
@ -2128,7 +2128,7 @@ def err_deduction_guide_invalid_specifier : Error<
|
|||
def err_deduction_guide_name_not_class_template : Error<
|
||||
"cannot specify deduction guide for "
|
||||
"%select{<error>|function template|variable template|alias template|"
|
||||
"template template parameter|dependent template name}0 %1">;
|
||||
"template template parameter|concept|dependent template name}0 %1">;
|
||||
def err_deduction_guide_wrong_scope : Error<
|
||||
"deduction guide must be declared in the same scope as template %q0">;
|
||||
def err_deduction_guide_defines_function : Error<
|
||||
|
@ -2456,32 +2456,20 @@ def warn_private_extern : Warning<
|
|||
def note_private_extern : Note<
|
||||
"use __attribute__((visibility(\"hidden\"))) attribute instead">;
|
||||
|
||||
// C++ Concepts TS
|
||||
def err_concept_wrong_decl_kind : Error<
|
||||
"'concept' can only appear on the definition of a function template or variable template">;
|
||||
def err_concept_decls_may_only_appear_in_namespace_scope : Error<
|
||||
"concept declarations may only appear in namespace scope">;
|
||||
def err_function_concept_not_defined : Error<
|
||||
"function concept declaration must be a definition">;
|
||||
def err_var_concept_not_initialized : Error<
|
||||
"variable concept declaration must be initialized">;
|
||||
def err_function_concept_exception_spec : Error<
|
||||
"function concept cannot have exception specification">;
|
||||
def err_concept_decl_invalid_specifiers : Error<
|
||||
"%select{variable|function}0 concept cannot be declared "
|
||||
"'%select{thread_local|inline|friend|constexpr}1'">;
|
||||
def err_function_concept_with_params : Error<
|
||||
"function concept cannot have any parameters">;
|
||||
def err_function_concept_bool_ret : Error<
|
||||
"declared return type of function concept must be 'bool'">;
|
||||
def err_variable_concept_bool_decl : Error<
|
||||
"declared type of variable concept must be 'bool'">;
|
||||
def err_concept_specified_specialization : Error<
|
||||
"'concept' cannot be applied on an "
|
||||
"%select{explicit instantiation|explicit specialization|partial specialization}0">;
|
||||
def err_concept_specialized : Error<
|
||||
"%select{function|variable}0 concept cannot be "
|
||||
"%select{explicitly instantiated|explicitly specialized|partially specialized}1">;
|
||||
// C++ Concepts
|
||||
def err_concept_initialized_with_non_bool_type : Error<
|
||||
"constraint expression must be of type 'bool' but is of type %0">;
|
||||
def err_concept_decls_may_only_appear_in_global_namespace_scope : Error<
|
||||
"concept declarations may only appear in global or namespace scope">;
|
||||
def err_concept_no_parameters : Error<
|
||||
"concept template parameter list must have at least one parameter; explicit "
|
||||
"specialization of concepts is not allowed">;
|
||||
def err_concept_extra_headers : Error<
|
||||
"extraneous template parameter list in concept definition">;
|
||||
def err_concept_no_associated_constraints : Error<
|
||||
"concept cannot have associated constraints">;
|
||||
def err_concept_not_implemented : Error<
|
||||
"sorry, unimplemented concepts feature %0 used">;
|
||||
|
||||
def err_template_different_associated_constraints : Error<
|
||||
"associated constraints differ in template redeclaration">;
|
||||
|
@ -4019,11 +4007,12 @@ def ext_adl_only_template_id : ExtWarn<
|
|||
def err_template_missing_args : Error<
|
||||
"use of "
|
||||
"%select{class template|function template|variable template|alias template|"
|
||||
"template template parameter|template}0 %1 requires template arguments">;
|
||||
"template template parameter|concept|template}0 %1 requires template "
|
||||
"arguments">;
|
||||
def err_template_arg_list_different_arity : Error<
|
||||
"%select{too few|too many}0 template arguments for "
|
||||
"%select{class template|function template|variable template|alias template|"
|
||||
"template template parameter|template}1 %2">;
|
||||
"template template parameter|concept|template}1 %2">;
|
||||
def note_template_decl_here : Note<"template is declared here">;
|
||||
def err_template_arg_must_be_type : Error<
|
||||
"template argument for template type parameter must be a type">;
|
||||
|
|
|
@ -48,9 +48,9 @@ enum TemplateNameKind {
|
|||
/// anyway. In C++20, this is mandatory in order to parse ADL-only function
|
||||
/// template specialization calls.
|
||||
TNK_Undeclared_template,
|
||||
/// The name refers to a concept.
|
||||
TNK_Concept_template,
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -3024,6 +3024,10 @@ private:
|
|||
SourceLocation &DeclEnd,
|
||||
ParsedAttributes &AccessAttrs,
|
||||
AccessSpecifier AS = AS_none);
|
||||
// C++2a: Template, concept definition [temp]
|
||||
Decl *
|
||||
ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
|
||||
SourceLocation &DeclEnd);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Modules
|
||||
|
|
|
@ -1973,6 +1973,7 @@ public:
|
|||
VarTemplate,
|
||||
AliasTemplate,
|
||||
TemplateTemplateParam,
|
||||
Concept,
|
||||
DependentTemplate
|
||||
};
|
||||
TemplateNameKindForDiagnostics
|
||||
|
@ -6551,6 +6552,13 @@ public:
|
|||
SourceLocation TemplateLoc,
|
||||
const TemplateArgumentListInfo *TemplateArgs);
|
||||
|
||||
ExprResult
|
||||
CheckConceptTemplateId(const CXXScopeSpec &SS,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
ConceptDecl *Template,
|
||||
SourceLocation TemplateLoc,
|
||||
const TemplateArgumentListInfo *TemplateArgs);
|
||||
|
||||
void diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc);
|
||||
|
||||
ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS,
|
||||
|
@ -6818,6 +6826,11 @@ public:
|
|||
const TemplateArgument *Args,
|
||||
unsigned NumArgs);
|
||||
|
||||
// Concepts
|
||||
Decl *ActOnConceptDefinition(
|
||||
Scope *S, MultiTemplateParamsArg TemplateParameterLists,
|
||||
IdentifierInfo *Name, SourceLocation NameLoc, Expr *ConstraintExpr);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ Variadic Templates (C++0x [temp.variadic])
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
|
@ -1489,7 +1489,10 @@ namespace serialization {
|
|||
/// A TypeAliasTemplateDecl record.
|
||||
DECL_TYPE_ALIAS_TEMPLATE,
|
||||
|
||||
/// A StaticAssertDecl record.
|
||||
/// \brief A ConceptDecl record.
|
||||
DECL_CONCEPT,
|
||||
|
||||
/// \brief A StaticAssertDecl record.
|
||||
DECL_STATIC_ASSERT,
|
||||
|
||||
/// A record containing CXXBaseSpecifiers.
|
||||
|
|
|
@ -1512,6 +1512,18 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
|||
D2->getTemplatedDecl()->getType());
|
||||
}
|
||||
|
||||
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
||||
ConceptDecl *D1,
|
||||
ConceptDecl *D2) {
|
||||
// Check template parameters.
|
||||
if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
|
||||
return false;
|
||||
|
||||
// Check the constraint expression.
|
||||
return IsStructurallyEquivalent(Context, D1->getConstraintExpr(),
|
||||
D2->getConstraintExpr());
|
||||
}
|
||||
|
||||
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
||||
FriendDecl *D1, FriendDecl *D2) {
|
||||
if ((D1->getFriendType() && D2->getFriendDecl()) ||
|
||||
|
@ -1771,6 +1783,14 @@ bool StructuralEquivalenceContext::CheckKindSpecificEquivalence(
|
|||
// Class template/non-class-template mismatch.
|
||||
return false;
|
||||
}
|
||||
} else if (auto *ConceptDecl1 = dyn_cast<ConceptDecl>(D1)) {
|
||||
if (auto *ConceptDecl2 = dyn_cast<ConceptDecl>(D2)) {
|
||||
if (!::IsStructurallyEquivalent(*this, ConceptDecl1, ConceptDecl2))
|
||||
return false;
|
||||
} else {
|
||||
// Concept/non-concept mismatch.
|
||||
return false;
|
||||
}
|
||||
} else if (auto *TTP1 = dyn_cast<TemplateTypeParmDecl>(D1)) {
|
||||
if (auto *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) {
|
||||
if (!::IsStructurallyEquivalent(*this, TTP1, TTP2))
|
||||
|
|
|
@ -710,6 +710,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
|
|||
case Binding:
|
||||
case NonTypeTemplateParm:
|
||||
case VarTemplate:
|
||||
case Concept:
|
||||
// These (C++-only) declarations are found by redeclaration lookup for
|
||||
// tag types, so we include them in the tag namespace.
|
||||
return IDNS_Ordinary | IDNS_Tag;
|
||||
|
|
|
@ -1123,8 +1123,13 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) {
|
|||
if (TTP->isParameterPack())
|
||||
Out << "...";
|
||||
Out << D->getName();
|
||||
} else {
|
||||
Visit(D->getTemplatedDecl());
|
||||
} else if (auto *TD = D->getTemplatedDecl())
|
||||
Visit(TD);
|
||||
else if (const auto *Concept = dyn_cast<ConceptDecl>(D)) {
|
||||
Out << "concept " << Concept->getName() << " = " ;
|
||||
Concept->getConstraintExpr()->printPretty(Out, nullptr, Policy,
|
||||
Indentation);
|
||||
Out << ";";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -821,6 +821,26 @@ ClassTemplateSpecializationDecl::getSourceRange() const {
|
|||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ConceptDecl Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
ConceptDecl *ConceptDecl::Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation L, DeclarationName Name,
|
||||
TemplateParameterList *Params,
|
||||
Expr *ConstraintExpr) {
|
||||
AdoptTemplateParameterList(Params, DC);
|
||||
return new (C, DC) ConceptDecl(DC, L, Name, Params, ConstraintExpr);
|
||||
}
|
||||
|
||||
ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C,
|
||||
unsigned ID) {
|
||||
ConceptDecl *Result = new (C, ID) ConceptDecl(nullptr, SourceLocation(),
|
||||
DeclarationName(),
|
||||
nullptr, nullptr);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ClassTemplatePartialSpecializationDecl Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -1936,3 +1936,7 @@ void TextNodeDumper::VisitBlockDecl(const BlockDecl *D) {
|
|||
if (D->capturesCXXThis())
|
||||
OS << " captures_this";
|
||||
}
|
||||
|
||||
void TextNodeDumper::VisitConceptDecl(const ConceptDecl *D) {
|
||||
dumpName(D);
|
||||
}
|
|
@ -108,6 +108,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
|
|||
case Decl::OMPCapturedExpr:
|
||||
case Decl::OMPRequires:
|
||||
case Decl::Empty:
|
||||
case Decl::Concept:
|
||||
// None of these decls require codegen support.
|
||||
return;
|
||||
|
||||
|
|
|
@ -5162,6 +5162,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
|
|||
case Decl::UsingShadow:
|
||||
case Decl::ClassTemplate:
|
||||
case Decl::VarTemplate:
|
||||
case Decl::Concept:
|
||||
case Decl::VarTemplatePartialSpecialization:
|
||||
case Decl::FunctionTemplate:
|
||||
case Decl::TypeAliasTemplate:
|
||||
|
|
|
@ -652,10 +652,10 @@ public:
|
|||
}
|
||||
|
||||
static bool shouldIndexTemplateParameterDefaultValue(const NamedDecl *D) {
|
||||
if (!D)
|
||||
return false;
|
||||
// We want to index the template parameters only once when indexing the
|
||||
// canonical declaration.
|
||||
if (!D)
|
||||
return false;
|
||||
if (const auto *FD = dyn_cast<FunctionDecl>(D))
|
||||
return FD->getCanonicalDecl() == FD;
|
||||
else if (const auto *TD = dyn_cast<TagDecl>(D))
|
||||
|
|
|
@ -49,6 +49,15 @@ Decl *Parser::ParseDeclarationStartingWithTemplate(
|
|||
/// template-declaration: [C++ temp]
|
||||
/// 'export'[opt] 'template' '<' template-parameter-list '>' declaration
|
||||
///
|
||||
/// template-declaration: [C++2a]
|
||||
/// template-head declaration
|
||||
/// template-head concept-definition
|
||||
///
|
||||
/// TODO: requires-clause
|
||||
/// template-head: [C++2a]
|
||||
/// 'template' '<' template-parameter-list '>'
|
||||
/// requires-clause[opt]
|
||||
///
|
||||
/// explicit-specialization: [ C++ temp.expl.spec]
|
||||
/// 'template' '<' '>' declaration
|
||||
Decl *Parser::ParseTemplateDeclarationOrSpecialization(
|
||||
|
@ -142,6 +151,12 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
|
|||
ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization);
|
||||
|
||||
// Parse the actual template declaration.
|
||||
if (Tok.is(tok::kw_concept))
|
||||
return ParseConceptDefinition(
|
||||
ParsedTemplateInfo(&ParamLists, isSpecialization,
|
||||
LastParamListWasEmpty),
|
||||
DeclEnd);
|
||||
|
||||
return ParseSingleDeclarationAfterTemplate(
|
||||
Context,
|
||||
ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty),
|
||||
|
@ -315,6 +330,85 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
|
|||
return ThisDecl;
|
||||
}
|
||||
|
||||
/// \brief Parse a single declaration that declares a concept.
|
||||
///
|
||||
/// \param DeclEnd will receive the source location of the last token
|
||||
/// within this declaration.
|
||||
///
|
||||
/// \returns the new declaration.
|
||||
Decl *
|
||||
Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
|
||||
SourceLocation &DeclEnd) {
|
||||
assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
|
||||
"Template information required");
|
||||
assert(Tok.is(tok::kw_concept) &&
|
||||
"ParseConceptDefinition must be called when at a 'concept' keyword");
|
||||
|
||||
ConsumeToken(); // Consume 'concept'
|
||||
|
||||
SourceLocation BoolKWLoc;
|
||||
if (TryConsumeToken(tok::kw_bool, BoolKWLoc))
|
||||
Diag(Tok.getLocation(), diag::ext_concept_legacy_bool_keyword) <<
|
||||
FixItHint::CreateRemoval(SourceLocation(BoolKWLoc));
|
||||
|
||||
DiagnoseAndSkipCXX11Attributes();
|
||||
|
||||
CXXScopeSpec SS;
|
||||
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
|
||||
/*EnteringContext=*/false, /*MayBePseudoDestructor=*/nullptr,
|
||||
/*IsTypename=*/false, /*LastII=*/nullptr, /*OnlyNamespace=*/true) ||
|
||||
SS.isInvalid()) {
|
||||
SkipUntil(tok::semi);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (SS.isNotEmpty())
|
||||
Diag(SS.getBeginLoc(),
|
||||
diag::err_concept_definition_not_identifier);
|
||||
|
||||
UnqualifiedId Result;
|
||||
if (ParseUnqualifiedId(SS, /*EnteringContext=*/false,
|
||||
/*AllowDestructorName=*/false,
|
||||
/*AllowConstructorName=*/false,
|
||||
/*AllowDeductionGuide=*/false,
|
||||
/*ObjectType=*/ParsedType(), /*TemplateKWLoc=*/nullptr,
|
||||
Result)) {
|
||||
SkipUntil(tok::semi);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (Result.getKind() != UnqualifiedIdKind::IK_Identifier) {
|
||||
Diag(Result.getBeginLoc(), diag::err_concept_definition_not_identifier);
|
||||
SkipUntil(tok::semi);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IdentifierInfo *Id = Result.Identifier;
|
||||
SourceLocation IdLoc = Result.getBeginLoc();
|
||||
|
||||
DiagnoseAndSkipCXX11Attributes();
|
||||
|
||||
if (!TryConsumeToken(tok::equal)) {
|
||||
Diag(Tok.getLocation(), diag::err_expected) << tok::equal;
|
||||
SkipUntil(tok::semi);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ExprResult ConstraintExprResult =
|
||||
Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression());
|
||||
if (ConstraintExprResult.isInvalid()) {
|
||||
SkipUntil(tok::semi);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DeclEnd = Tok.getLocation();
|
||||
ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
|
||||
Expr *ConstraintExpr = ConstraintExprResult.get();
|
||||
return Actions.ActOnConceptDefinition(getCurScope(),
|
||||
*TemplateInfo.TemplateParams,
|
||||
Id, IdLoc, ConstraintExpr);
|
||||
}
|
||||
|
||||
/// ParseTemplateParameters - Parses a template-parameter-list enclosed in
|
||||
/// angle brackets. Depth is the depth of this template-parameter-list, which
|
||||
/// is the number of template headers directly enclosing this template header.
|
||||
|
|
|
@ -1189,6 +1189,8 @@ Sema::getTemplateNameKindForDiagnostics(TemplateName Name) {
|
|||
return TemplateNameKindForDiagnostics::AliasTemplate;
|
||||
if (isa<TemplateTemplateParmDecl>(TD))
|
||||
return TemplateNameKindForDiagnostics::TemplateTemplateParam;
|
||||
if (isa<ConceptDecl>(TD))
|
||||
return TemplateNameKindForDiagnostics::Concept;
|
||||
return TemplateNameKindForDiagnostics::DependentTemplate;
|
||||
}
|
||||
|
||||
|
|
|
@ -9802,7 +9802,7 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
|
|||
NonTemplateTarget = TargetTD->getTemplatedDecl();
|
||||
|
||||
UsingShadowDecl *Shadow;
|
||||
if (isa<CXXConstructorDecl>(NonTemplateTarget)) {
|
||||
if (NonTemplateTarget && isa<CXXConstructorDecl>(NonTemplateTarget)) {
|
||||
bool IsVirtualBase =
|
||||
isVirtualDirectBase(cast<CXXRecordDecl>(CurContext),
|
||||
UD->getQualifier()->getAsRecordDecl());
|
||||
|
|
|
@ -5169,7 +5169,8 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) {
|
|||
if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
|
||||
return PD->getDefinition();
|
||||
if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
|
||||
return getDefinitionToImport(TD->getTemplatedDecl());
|
||||
if (NamedDecl *TTD = TD->getTemplatedDecl())
|
||||
return getDefinitionToImport(TTD);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -271,9 +271,11 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
|
|||
} else {
|
||||
assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) ||
|
||||
isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD) ||
|
||||
isa<BuiltinTemplateDecl>(TD));
|
||||
isa<BuiltinTemplateDecl>(TD) || isa<ConceptDecl>(TD));
|
||||
TemplateKind =
|
||||
isa<VarTemplateDecl>(TD) ? TNK_Var_template : TNK_Type_template;
|
||||
isa<VarTemplateDecl>(TD) ? TNK_Var_template :
|
||||
isa<ConceptDecl>(TD) ? TNK_Concept_template :
|
||||
TNK_Type_template;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3227,7 +3229,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
|
|||
|
||||
TemplateDecl *Template = Name.getAsTemplateDecl();
|
||||
if (!Template || isa<FunctionTemplateDecl>(Template) ||
|
||||
isa<VarTemplateDecl>(Template)) {
|
||||
isa<VarTemplateDecl>(Template) ||
|
||||
isa<ConceptDecl>(Template)) {
|
||||
// We might have a substituted template template parameter pack. If so,
|
||||
// build a template specialization type for it.
|
||||
if (Name.getAsSubstTemplateTemplateParmPack())
|
||||
|
@ -4234,6 +4237,18 @@ void Sema::diagnoseMissingTemplateArguments(TemplateName Name,
|
|||
}
|
||||
}
|
||||
|
||||
ExprResult
|
||||
Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
ConceptDecl *Template,
|
||||
SourceLocation TemplateLoc,
|
||||
const TemplateArgumentListInfo *TemplateArgs) {
|
||||
// TODO: Do concept specialization here.
|
||||
Diag(NameInfo.getBeginLoc(), diag::err_concept_not_implemented) <<
|
||||
"concept specialization";
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
|
||||
SourceLocation TemplateKWLoc,
|
||||
LookupResult &R,
|
||||
|
@ -4274,6 +4289,12 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
|
|||
TemplateKWLoc, TemplateArgs);
|
||||
}
|
||||
|
||||
if (R.getAsSingle<ConceptDecl>() && !AnyDependentArguments()) {
|
||||
return CheckConceptTemplateId(SS, R.getLookupNameInfo(),
|
||||
R.getAsSingle<ConceptDecl>(),
|
||||
TemplateKWLoc, TemplateArgs);
|
||||
}
|
||||
|
||||
// We don't want lookup warnings at this point.
|
||||
R.suppressDiagnostics();
|
||||
|
||||
|
@ -7974,7 +7995,74 @@ Decl *Sema::ActOnTemplateDeclarator(Scope *S,
|
|||
return NewDecl;
|
||||
}
|
||||
|
||||
/// Strips various properties off an implicit instantiation
|
||||
Decl *Sema::ActOnConceptDefinition(Scope *S,
|
||||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
IdentifierInfo *Name, SourceLocation NameLoc,
|
||||
Expr *ConstraintExpr) {
|
||||
DeclContext *DC = CurContext;
|
||||
|
||||
if (!DC->getRedeclContext()->isFileContext()) {
|
||||
Diag(NameLoc,
|
||||
diag::err_concept_decls_may_only_appear_in_global_namespace_scope);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (TemplateParameterLists.size() > 1) {
|
||||
Diag(NameLoc, diag::err_concept_extra_headers);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (TemplateParameterLists.front()->size() == 0) {
|
||||
Diag(NameLoc, diag::err_concept_no_parameters);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name,
|
||||
TemplateParameterLists.front(),
|
||||
ConstraintExpr);
|
||||
|
||||
if (!ConstraintExpr->isTypeDependent() &&
|
||||
ConstraintExpr->getType() != Context.BoolTy) {
|
||||
// C++2a [temp.constr.atomic]p3:
|
||||
// E shall be a constant expression of type bool.
|
||||
// TODO: Do this check for individual atomic constraints
|
||||
// and not the constraint expression. Probably should do it in
|
||||
// ParseConstraintExpression.
|
||||
Diag(ConstraintExpr->getSourceRange().getBegin(),
|
||||
diag::err_concept_initialized_with_non_bool_type)
|
||||
<< ConstraintExpr->getType();
|
||||
NewDecl->setInvalidDecl();
|
||||
}
|
||||
|
||||
if (NewDecl->getAssociatedConstraints()) {
|
||||
// C++2a [temp.concept]p4:
|
||||
// A concept shall not have associated constraints.
|
||||
// TODO: Make a test once we have actual associated constraints.
|
||||
Diag(NameLoc, diag::err_concept_no_associated_constraints);
|
||||
NewDecl->setInvalidDecl();
|
||||
}
|
||||
|
||||
// Check for conflicting previous declaration.
|
||||
DeclarationNameInfo NameInfo(NewDecl->getDeclName(), NameLoc);
|
||||
LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
|
||||
ForVisibleRedeclaration);
|
||||
LookupName(Previous, S);
|
||||
|
||||
FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage=*/false,
|
||||
/*AllowInlineNamespace*/false);
|
||||
if (!Previous.empty()) {
|
||||
auto *Old = Previous.getRepresentativeDecl();
|
||||
Diag(NameLoc, isa<ConceptDecl>(Old) ? diag::err_redefinition :
|
||||
diag::err_redefinition_different_kind) << NewDecl->getDeclName();
|
||||
Diag(Old->getLocation(), diag::note_previous_definition);
|
||||
}
|
||||
|
||||
ActOnDocumentableDecl(NewDecl);
|
||||
PushOnScopeChains(NewDecl, S);
|
||||
return NewDecl;
|
||||
}
|
||||
|
||||
/// \brief Strips various properties off an implicit instantiation
|
||||
/// that has just been explicitly specialized.
|
||||
static void StripImplicitInstantiation(NamedDecl *D) {
|
||||
D->dropAttr<DLLImportAttr>();
|
||||
|
|
|
@ -3401,6 +3401,10 @@ Decl *TemplateDeclInstantiator::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) {
|
||||
llvm_unreachable("Concept definitions cannot reside inside a template");
|
||||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitDecl(Decl *D) {
|
||||
llvm_unreachable("Unexpected decl");
|
||||
}
|
||||
|
|
|
@ -395,6 +395,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
|
|||
case Decl::BuiltinTemplate:
|
||||
case Decl::Decomposition:
|
||||
case Decl::Binding:
|
||||
case Decl::Concept:
|
||||
return false;
|
||||
|
||||
// These indirectly derive from Redeclarable<T> but are not actually
|
||||
|
|
|
@ -382,6 +382,7 @@ namespace clang {
|
|||
void VisitBindingDecl(BindingDecl *BD);
|
||||
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
|
||||
DeclID VisitTemplateDecl(TemplateDecl *D);
|
||||
void VisitConceptDecl(ConceptDecl *D);
|
||||
RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
|
||||
void VisitClassTemplateDecl(ClassTemplateDecl *D);
|
||||
void VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D);
|
||||
|
@ -2089,6 +2090,12 @@ DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
|
|||
return PatternID;
|
||||
}
|
||||
|
||||
void ASTDeclReader::VisitConceptDecl(ConceptDecl *D) {
|
||||
VisitTemplateDecl(D);
|
||||
D->ConstraintExpr = Record.readExpr();
|
||||
mergeMergeable(D);
|
||||
}
|
||||
|
||||
ASTDeclReader::RedeclarableResult
|
||||
ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
|
||||
RedeclarableResult Redecl = VisitRedeclarable(D);
|
||||
|
@ -3829,6 +3836,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
|
|||
case DECL_TYPE_ALIAS_TEMPLATE:
|
||||
D = TypeAliasTemplateDecl::CreateDeserialized(Context, ID);
|
||||
break;
|
||||
case DECL_CONCEPT:
|
||||
D = ConceptDecl::CreateDeserialized(Context, ID);
|
||||
break;
|
||||
case DECL_STATIC_ASSERT:
|
||||
D = StaticAssertDecl::CreateDeserialized(Context, ID);
|
||||
break;
|
||||
|
|
|
@ -1293,6 +1293,7 @@ void ASTWriter::WriteBlockInfoBlock() {
|
|||
RECORD(DECL_TEMPLATE_TYPE_PARM);
|
||||
RECORD(DECL_NON_TYPE_TEMPLATE_PARM);
|
||||
RECORD(DECL_TEMPLATE_TEMPLATE_PARM);
|
||||
RECORD(DECL_CONCEPT);
|
||||
RECORD(DECL_TYPE_ALIAS_TEMPLATE);
|
||||
RECORD(DECL_STATIC_ASSERT);
|
||||
RECORD(DECL_CXX_BASE_SPECIFIERS);
|
||||
|
|
|
@ -102,6 +102,7 @@ namespace clang {
|
|||
void VisitBindingDecl(BindingDecl *D);
|
||||
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
|
||||
void VisitTemplateDecl(TemplateDecl *D);
|
||||
void VisitConceptDecl(ConceptDecl *D);
|
||||
void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
|
||||
void VisitClassTemplateDecl(ClassTemplateDecl *D);
|
||||
void VisitVarTemplateDecl(VarTemplateDecl *D);
|
||||
|
@ -1432,6 +1433,12 @@ void ASTDeclWriter::VisitTemplateDecl(TemplateDecl *D) {
|
|||
Record.AddTemplateParameterList(D->getTemplateParameters());
|
||||
}
|
||||
|
||||
void ASTDeclWriter::VisitConceptDecl(ConceptDecl *D) {
|
||||
VisitTemplateDecl(D);
|
||||
Record.AddStmt(D->getConstraintExpr());
|
||||
Code = serialization::DECL_CONCEPT;
|
||||
}
|
||||
|
||||
void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
|
||||
VisitRedeclarable(D);
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
|
||||
|
||||
template<typename T> concept C = true;
|
||||
static_assert(C<int>); // expected-error{{sorry, unimplemented concepts feature concept specialization used}}
|
|
@ -0,0 +1,73 @@
|
|||
// Support parsing of concepts
|
||||
|
||||
// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
|
||||
template<typename T> concept C1 = true; // expected-note 2{{previous}}
|
||||
|
||||
template<typename T> concept C1 = true; // expected-error{{redefinition}}
|
||||
|
||||
template<concept T> concept D1 = true;
|
||||
// expected-error@-1{{expected template parameter}}
|
||||
// expected-error@-2{{concept template parameter list must have at least one parameter; explicit specialization of concepts is not allowed}}
|
||||
|
||||
template<template<typename> concept T> concept D2 = true;
|
||||
// expected-error@-1{{expected identifier}}
|
||||
// expected-error@-2{{template template parameter requires 'class' after the parameter list}}
|
||||
// expected-error@-3{{concept template parameter list must have at least one parameter; explicit specialization of concepts is not allowed}}
|
||||
|
||||
template<typename T> concept C2 = 0.f; // expected-error {{constraint expression must be of type 'bool' but is of type 'float'}}
|
||||
|
||||
struct S1 {
|
||||
template<typename T> concept C1 = true; // expected-error {{concept declarations may only appear in global or namespace scope}}
|
||||
};
|
||||
|
||||
extern "C++" {
|
||||
template<typename T> concept C1 = true; // expected-error{{redefinition}}
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
template<typename B>
|
||||
concept C4 = true; // expected-error {{extraneous template parameter list in concept definition}}
|
||||
|
||||
template<typename T> concept C5 = true; // expected-note {{previous}} expected-note {{previous}}
|
||||
int C5; // expected-error {{redefinition}}
|
||||
struct C5 {}; // expected-error {{redefinition}}
|
||||
|
||||
struct C6 {}; // expected-note{{previous definition is here}}
|
||||
template<typename T> concept C6 = true;
|
||||
// expected-error@-1{{redefinition of 'C6' as different kind of symbol}}
|
||||
|
||||
// TODO: Add test to prevent explicit specialization, partial specialization
|
||||
// and explicit instantiation of concepts.
|
||||
|
||||
template<typename T, T v>
|
||||
struct integral_constant { static constexpr T value = v; };
|
||||
|
||||
namespace N {
|
||||
template<typename T> concept C7 = true;
|
||||
}
|
||||
using N::C7;
|
||||
|
||||
template <bool word> concept C8 = integral_constant<bool, wor>::value;
|
||||
// expected-error@-1{{use of undeclared identifier 'wor'; did you mean 'word'?}}
|
||||
// expected-note@-2{{'word' declared here}}
|
||||
|
||||
template<typename T> concept bool C9 = true;
|
||||
// expected-warning@-1{{ISO C++2a does not permit the 'bool' keyword after 'concept'}}
|
||||
|
||||
template<> concept C10 = false;
|
||||
// expected-error@-1{{concept template parameter list must have at least one parameter; explicit specialization of concepts is not allowed}}
|
||||
|
||||
template<> concept C9<int> = false;
|
||||
// expected-error@-1{{name defined in concept definition must be an identifier}}
|
||||
|
||||
template<typename T> concept N::C11 = false;
|
||||
// expected-error@-1{{name defined in concept definition must be an identifier}}
|
||||
|
||||
class A { };
|
||||
// expected-note@-1{{'A' declared here}}
|
||||
|
||||
template<typename T> concept A::C12 = false;
|
||||
// expected-error@-1{{expected namespace name}}
|
||||
|
||||
template<typename T> concept operator int = false;
|
||||
// expected-error@-1{{name defined in concept definition must be an identifier}}
|
|
@ -6271,6 +6271,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
|
|||
case Decl::PragmaComment:
|
||||
case Decl::PragmaDetectMismatch:
|
||||
case Decl::UsingPack:
|
||||
case Decl::Concept:
|
||||
return C;
|
||||
|
||||
// Declaration kinds that don't make any sense here, but are
|
||||
|
|
Loading…
Reference in New Issue