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());
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;
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; };
void VisitObjCPropertyDecl(const ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D);
void VisitBlockDecl(const BlockDecl *D);
+ void VisitConceptDecl(const ConceptDecl *D);
};
} // namespace clang
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>;
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<
"'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
"%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"
"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<
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<
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">;
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">;
/// 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
-
-
SourceLocation &DeclEnd,
ParsedAttributes &AccessAttrs,
AccessSpecifier AS = AS_none);
+ // C++2a: Template, concept definition [temp]
+ Decl *
+ ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
+ SourceLocation &DeclEnd);
//===--------------------------------------------------------------------===//
// Modules
VarTemplate,
AliasTemplate,
TemplateTemplateParam,
+ Concept,
DependentTemplate
};
TemplateNameKindForDiagnostics
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,
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])
//===--------------------------------------------------------------------===//
/// 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.
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()) ||
// 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))
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;
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 << ";";
}
}
}
}
+//===----------------------------------------------------------------------===//
+// 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
//===----------------------------------------------------------------------===//
if (D->capturesCXXThis())
OS << " captures_this";
}
+
+void TextNodeDumper::VisitConceptDecl(const ConceptDecl *D) {
+ dumpName(D);
+}
\ No newline at end of file
case Decl::OMPCapturedExpr:
case Decl::OMPRequires:
case Decl::Empty:
+ case Decl::Concept:
// None of these decls require codegen support.
return;
case Decl::UsingShadow:
case Decl::ClassTemplate:
case Decl::VarTemplate:
+ case Decl::Concept:
case Decl::VarTemplatePartialSpecialization:
case Decl::FunctionTemplate:
case Decl::TypeAliasTemplate:
}
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))
/// 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(
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),
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.
return TemplateNameKindForDiagnostics::AliasTemplate;
if (isa<TemplateTemplateParmDecl>(TD))
return TemplateNameKindForDiagnostics::TemplateTemplateParam;
+ if (isa<ConceptDecl>(TD))
+ return TemplateNameKindForDiagnostics::Concept;
return TemplateNameKindForDiagnostics::DependentTemplate;
}
NonTemplateTarget = TargetTD->getTemplatedDecl();
UsingShadowDecl *Shadow;
- if (isa<CXXConstructorDecl>(NonTemplateTarget)) {
+ if (NonTemplateTarget && isa<CXXConstructorDecl>(NonTemplateTarget)) {
bool IsVirtualBase =
isVirtualDirectBase(cast<CXXRecordDecl>(CurContext),
UD->getQualifier()->getAsRecordDecl());
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;
}
} 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;
}
}
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())
}
}
+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,
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();
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>();
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");
}
case Decl::BuiltinTemplate:
case Decl::Decomposition:
case Decl::Binding:
+ case Decl::Concept:
return false;
// These indirectly derive from Redeclarable<T> but are not actually
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);
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);
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;
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);
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);
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);
--- /dev/null
+// 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}}
--- /dev/null
+// 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}}
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