|
@@ -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>();
|