saar.raz updated this revision to Diff 126950. saar.raz added a comment. - Fixed indentation problems
Repository: rC Clang https://reviews.llvm.org/D41217 Files: include/clang/AST/DeclTemplate.h include/clang/AST/ExprCXX.h include/clang/AST/RecursiveASTVisitor.h include/clang/Basic/DeclNodes.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/StmtNodes.td include/clang/Basic/TemplateKinds.h include/clang/Parse/Parser.h include/clang/Sema/Sema.h include/clang/Serialization/ASTBitCodes.h lib/AST/ASTDumper.cpp lib/AST/DeclBase.cpp lib/AST/DeclTemplate.cpp lib/AST/Expr.cpp lib/AST/ExprCXX.cpp lib/AST/ExprClassification.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/StmtPrinter.cpp lib/AST/StmtProfile.cpp lib/CodeGen/CGDecl.cpp lib/CodeGen/CGExprScalar.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseTemplate.cpp lib/Sema/SemaExceptionSpec.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReaderDecl.cpp lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriter.cpp lib/Serialization/ASTWriterDecl.cpp lib/Serialization/ASTWriterStmt.cpp lib/StaticAnalyzer/Core/ExprEngine.cpp test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp test/Parser/cxx-concept-declaration.cpp tools/libclang/CIndex.cpp tools/libclang/CXCursor.cpp
Index: tools/libclang/CXCursor.cpp =================================================================== --- tools/libclang/CXCursor.cpp +++ tools/libclang/CXCursor.cpp @@ -231,6 +231,7 @@ case Stmt::TypeTraitExprClass: case Stmt::CoroutineBodyStmtClass: case Stmt::CoawaitExprClass: + case Stmt::ConceptSpecializationExprClass: case Stmt::DependentCoawaitExprClass: case Stmt::CoreturnStmtClass: case Stmt::CoyieldExprClass: Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -5951,6 +5951,7 @@ 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 Index: test/Parser/cxx-concept-declaration.cpp =================================================================== --- test/Parser/cxx-concept-declaration.cpp +++ test/Parser/cxx-concept-declaration.cpp @@ -1,7 +1,38 @@ // Support parsing of concepts -// Disabled for now. -// expected-no-diagnostics -// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s -// template<typename T> concept C1 = true; +// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s +template<typename T> concept C1 = true; + +// TODO: Following line should fail. +template<typename T> concept C1 = true; + +template<concept T> concept D1 = true; // expected-error {{expected template parameter}} + +struct S1 { + template<typename T> concept C1 = true; // expected-error {{concept declarations may only appear in global or namespace scope}} +}; + +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}} + +// TODO: Last of the following two lines should fail. +struct C6 {}; +template<typename T> concept C6 = true; + +// TODO: Add test to prevent explicit specialization, partial specialization +// and explicit instantiation of concepts. + +template<bool x> concept C7 = 2; // expected-error {{atomic constraint '2' must be of type 'bool' (found 'int')}} +template<bool x> concept C8 = 2 && x; // expected-error {{atomic constraint '2' must be of type 'bool' (found 'int')}} +template<bool x> concept C9 = x || 2 || x; // expected-error {{atomic constraint '2' must be of type 'bool' (found 'int')}} +template<bool x> concept C10 = 8ull && x || x; // expected-error {{atomic constraint '8ULL' must be of type 'bool' (found 'unsigned long long')}} +template<typename T> concept C11 = sizeof(T); // expected-error {{atomic constraint 'sizeof(T)' must be of type 'bool' (found 'unsigned long')}} +template<typename T> concept C12 = T{}; +template<typename T> concept C13 = (bool&&)true; +template<typename T> concept C14 = (const bool&)true; Index: test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp =================================================================== --- /dev/null +++ test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s + +template<typename T> concept C1 = true; +static_assert(C1<int>); + +template<typename T> concept C2 = sizeof(T) == 4; +static_assert(C2<int>); +static_assert(!C2<long long int>); +static_assert(C2<char[4]>); +static_assert(!C2<char[5]>); + +template<typename T> concept C3 = sizeof(*T{}) == 4; +static_assert(C3<int*>); +static_assert(!C3<long long int>); + +struct A { + static constexpr int add(int a, int b) { + return a + b; + } +}; +struct B { + static int add(int a, int b) { + return a + b; + } +}; +template<typename U> +concept C4 = U::add(1, 2) == 3; +static_assert(C4<A>); +static_assert(!C4<B>); // expected-error {{concept specialization 'C4<B>' resulted in a non-constant expression 'B::add(1, 2) == 3'}} + +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, typename U> +concept Same = is_same_v<T, U>; + +static_assert(Same<int, int>); +static_assert(Same<int, decltype(1)>); +static_assert(!Same<int, unsigned int>); +static_assert(!Same<A, B>); +static_assert(Same<A, A>); + +static_assert(Same<bool, decltype(C1<int>)>); +static_assert(Same<bool, decltype(C2<int>)>); +static_assert(Same<bool, decltype(C3<int*>)>); +static_assert(Same<bool, decltype(C4<A>)>); + +template<typename T> concept C5 = T{}; // expected-error {{atomic constraint 'int{}' must be of type 'bool' (found 'int')}} +constexpr bool x = C5<int>; // expected-note {{in concept specialization 'C5<int>'}} Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1018,6 +1018,7 @@ case Stmt::CUDAKernelCallExprClass: case Stmt::OpaqueValueExprClass: case Stmt::AsTypeExprClass: + case Stmt::ConceptSpecializationExprClass: // Fall through. // Cases we intentionally don't evaluate, since they don't need Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -344,6 +344,23 @@ Code = serialization::EXPR_DEPENDENT_COAWAIT; } +void ASTStmtWriter::VisitConceptSpecializationExpr( + ConceptSpecializationExpr *E) { + VisitExpr(E); + Record.AddDeclRef(E->getSpecializedConcept()); + Record.AddSourceLocation(E->getConceptNameLoc()); + const TemplateArgumentListInfo *TALI = E->getTemplateArgumentListInfo(); + Record.push_back(TALI->size()); + Record.AddSourceLocation(TALI->getLAngleLoc()); + Record.AddSourceLocation(TALI->getRAngleLoc()); + for (unsigned i = 0; i < TALI->size(); ++i) { + Record.AddTemplateArgumentLoc(TALI->getArgumentArray()[i]); + } + Record.push_back(E->isSatisfied()); + Code = serialization::EXPR_CONCEPT_SPECIALIZATION; +} + + void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) { VisitStmt(S); // NumCaptures Index: lib/Serialization/ASTWriterDecl.cpp =================================================================== --- lib/Serialization/ASTWriterDecl.cpp +++ lib/Serialization/ASTWriterDecl.cpp @@ -101,6 +101,7 @@ 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); @@ -1385,6 +1386,12 @@ 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); Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -1277,6 +1277,7 @@ 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); Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -610,6 +610,22 @@ E->setRParenLoc(ReadSourceLocation()); } +void ASTStmtReader::VisitConceptSpecializationExpr( + ConceptSpecializationExpr *E) { + VisitExpr(E); + E->setSpecializedConcept(ReadDeclAs<ConceptDecl>()); + E->setConceptNameLoc(Record.readSourceLocation()); + + TemplateArgumentListInfo ArgInfo; + unsigned NumTemplateArgs = Record.readInt(); + ArgInfo.setLAngleLoc(Record.readSourceLocation()); + ArgInfo.setRAngleLoc(Record.readSourceLocation()); + for (unsigned i = 0; i != NumTemplateArgs; ++i) + ArgInfo.addArgument(Record.readTemplateArgumentLoc()); + E->setTemplateArguments(/*Sema=*/nullptr, &ArgInfo); + E->setSatisfied(Record.readInt() == 1); +} + void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { VisitExpr(E); E->setLHS(Record.readSubExpr()); @@ -4033,6 +4049,9 @@ S = new (Context) DependentCoawaitExpr(Empty); break; + case EXPR_CONCEPT_SPECIALIZATION: + S = new (Context) ConceptSpecializationExpr(Context); + break; } // We hit a STMT_STOP, so we're done with this expression. Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -337,6 +337,7 @@ 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); @@ -1970,6 +1971,11 @@ return PatternID; } +void ASTDeclReader::VisitConceptDecl(ConceptDecl *D) { + VisitTemplateDecl(D); + D->setConstraintExpr(Record.readExpr()); +} + ASTDeclReader::RedeclarableResult ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { RedeclarableResult Redecl = VisitRedeclarable(D); @@ -3522,6 +3528,9 @@ 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; Index: lib/Serialization/ASTCommon.cpp =================================================================== --- lib/Serialization/ASTCommon.cpp +++ lib/Serialization/ASTCommon.cpp @@ -313,6 +313,7 @@ case Decl::BuiltinTemplate: case Decl::Decomposition: case Decl::Binding: + case Decl::Concept: return false; // These indirectly derive from Redeclarable<T> but are not actually Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -2940,7 +2940,22 @@ RParenLoc, Length, PartialArgs); } - /// \brief Build a new Objective-C boxed expression. + /// \brief Build a new concept specialization expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildConceptSpecializationExpr(SourceLocation ConceptNameLoc, + ConceptDecl *CTD, + TemplateArgumentListInfo *TALI) { + ExprResult Result + = getSema().CreateConceptSpecializationExpr(ConceptNameLoc, CTD, + TALI); + if (Result.isInvalid()) + return ExprError(); + return Result; + } + + /// \brief Build a new Objective-C boxed expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -10616,6 +10631,23 @@ E->getLocEnd()); } +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformConceptSpecializationExpr( + ConceptSpecializationExpr *E) { + const TemplateArgumentListInfo *Old = E->getTemplateArgumentListInfo(); + TemplateArgumentListInfo TransArgs(Old->getLAngleLoc(), Old->getRAngleLoc()); + if (getDerived().TransformTemplateArguments(Old->getArgumentArray(), + Old->size(), TransArgs)) { + return ExprError(); + } + + return getDerived().RebuildConceptSpecializationExpr(E->getConceptNameLoc(), + E->getSpecializedConcept(), + &TransArgs); +} + + template<typename Derived> ExprResult TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3095,6 +3095,11 @@ return nullptr; } +Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) { + llvm_unreachable("Concept definitions cannot reside inside a template"); + return nullptr; +} + Decl *TemplateDeclInstantiator::VisitDecl(Decl *D) { llvm_unreachable("Unexpected decl"); } Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -232,9 +232,11 @@ } 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; } } @@ -2930,7 +2932,8 @@ 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()) @@ -3884,6 +3887,25 @@ /*FoundD=*/nullptr, TemplateArgs); } +ExprResult +Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + ConceptDecl *Template, + SourceLocation TemplateLoc, + const TemplateArgumentListInfo *TemplateArgs) { + assert(Template && "A concept template id without template?"); + + // Check that the template argument list is well-formed for this template. + SmallVector<TemplateArgument, 4> Converted; + if (CheckTemplateArgumentList(Template, TemplateLoc, + const_cast<TemplateArgumentListInfo &>(*TemplateArgs), false, + Converted, /*UpdateArgsWithConversions=*/false)) + return ExprError(); + + return CreateConceptSpecializationExpr(NameInfo.getLoc(), Template, + TemplateArgs); +} + ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, @@ -3905,14 +3927,21 @@ // In C++1y, check variable template ids. bool InstantiationDependent; - if (R.getAsSingle<VarTemplateDecl>() && - !TemplateSpecializationType::anyDependentTemplateArguments( - *TemplateArgs, InstantiationDependent)) { + bool DependentArguments = + TemplateSpecializationType::anyDependentTemplateArguments( + *TemplateArgs, InstantiationDependent); + if (R.getAsSingle<VarTemplateDecl>() && !DependentArguments) { return CheckVarTemplateId(SS, R.getLookupNameInfo(), R.getAsSingle<VarTemplateDecl>(), TemplateKWLoc, TemplateArgs); } + if (R.getAsSingle<ConceptDecl>() && !DependentArguments) { + return CheckConceptTemplateId(SS, R.getLookupNameInfo(), + R.getAsSingle<ConceptDecl>(), + TemplateKWLoc, TemplateArgs); + } + // We don't want lookup warnings at this point. R.suppressDiagnostics(); @@ -7663,6 +7692,44 @@ return NewDecl; } +#include <iostream> +using namespace std; +Decl *Sema::ActOnConceptDefinition(Scope *S, + MultiTemplateParamsArg TemplateParameterLists, + IdentifierInfo *Name, SourceLocation L, + Expr *ConstraintExpr) { + DeclContext *DC = CurContext; + + if (!DC->isFileContext()) { + Diag(L, + diag::err_concept_decls_may_only_appear_in_global_namespace_scope); + return nullptr; + } + + if (TemplateParameterLists.size() != 1) { + Diag(L, diag::err_concept_extra_headers); + return nullptr; + } + + ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, L, Name, + TemplateParameterLists[0], + ConstraintExpr); + if (!NewDecl) + return nullptr; + + 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(L, diag::err_concept_no_associated_constraints); + NewDecl->setInvalidDecl(); + } + + ActOnDocumentableDecl(NewDecl); + CurContext->addDecl(NewDecl); + return NewDecl; +} + /// \brief Strips various properties off an implicit instantiation /// that has just been explicitly specialized. static void StripImplicitInstantiation(NamedDecl *D) { Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -7678,3 +7678,38 @@ return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo); } + + +ExprResult Sema::CreateConceptSpecializationExpr(SourceLocation ConceptNameLoc, + ConceptDecl *CTD, + const TemplateArgumentListInfo *TALI) { + return new (Context) ConceptSpecializationExpr(Context, *this, ConceptNameLoc, + CTD, TALI); +} + +bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) { + // C++2a [temp.constr.atomic]p1 + // ..E shall be a constant expression of type bool. + + if (BinaryOperator* BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) { + if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr) { + return CheckConstraintExpression(BinOp->getLHS()) + && CheckConstraintExpression(BinOp->getRHS()); + } + } + // An atomic constraint! + if (!ConstraintExpression->isTypeDependent()) { + if (ConstraintExpression->getType().getLocalUnqualifiedType() + != Context.BoolTy) { + Diag(ConstraintExpression->getExprLoc(), + diag::err_non_bool_atomic_constraint) + << ConstraintExpression << ConstraintExpression->getType(); + return false; + } else if (ImplicitCastExpr *E = + dyn_cast<ImplicitCastExpr>(ConstraintExpression)) { + // This will catch expressions such as '2 && true' + return CheckConstraintExpression(E->getSubExpr()); + } + } + return true; +} \ No newline at end of file Index: lib/Sema/SemaExceptionSpec.cpp =================================================================== --- lib/Sema/SemaExceptionSpec.cpp +++ lib/Sema/SemaExceptionSpec.cpp @@ -1271,6 +1271,7 @@ case Expr::PredefinedExprClass: case Expr::SizeOfPackExprClass: case Expr::StringLiteralClass: + case Expr::ConceptSpecializationExprClass: // These expressions can never throw. return CT_Cannot; Index: lib/Parse/ParseTemplate.cpp =================================================================== --- lib/Parse/ParseTemplate.cpp +++ lib/Parse/ParseTemplate.cpp @@ -54,6 +54,15 @@ /// 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] +/// 'export'[opt] 'template' '<' template-parameter-list '>' +/// requires-clause[opt] +/// /// explicit-specialization: [ C++ temp.expl.spec] /// 'template' '<' '>' declaration Decl * @@ -149,12 +158,20 @@ ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization); // Parse the actual template declaration. - return ParseSingleDeclarationAfterTemplate(Context, - ParsedTemplateInfo(&ParamLists, - isSpecialization, - LastParamListWasEmpty), - ParsingTemplateParams, - DeclEnd, AS, AccessAttrs); + if (!TryConsumeToken(tok::kw_concept)) + return ParseSingleDeclarationAfterTemplate(Context, + ParsedTemplateInfo(&ParamLists, + isSpecialization, + LastParamListWasEmpty), + ParsingTemplateParams, + DeclEnd, AS, AccessAttrs); + + return ParseConceptDefinition(Context, + ParsedTemplateInfo(&ParamLists, + isSpecialization, + LastParamListWasEmpty), + ParsingTemplateParams, + DeclEnd, AS, AccessAttrs); } /// \brief Parse a single declaration that declares a template, @@ -321,6 +338,51 @@ 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. +/// +/// \param AS the access specifier associated with this +/// declaration. Will be AS_none for namespace-scope declarations. +/// +/// \returns the new declaration. +Decl * +Parser::ParseConceptDefinition(unsigned Context, + const ParsedTemplateInfo &TemplateInfo, + ParsingDeclRAIIObject &DiagsFromTParams, + SourceLocation &DeclEnd, + AccessSpecifier AS, + AttributeList *AccessAttrs) { + assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && + "Template information required"); + + if (!Tok.is(tok::identifier)) { + Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; + return nullptr; + } + + IdentifierInfo *Id = Tok.getIdentifierInfo(); + SourceLocation IdLoc = ConsumeToken(); + + if (!TryConsumeToken(tok::equal)) { + Diag(Tok.getLocation(), diag::err_expected) << "equal"; + return nullptr; + } + + ExprResult ConstraintExprResult = ParseConstraintExpression(); + if (ConstraintExprResult.isInvalid()) { + // ParseConstraintExpression will have given a sufficient diagnostic. + return nullptr; + } + + 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. @@ -1024,8 +1086,8 @@ ? OO_None : TemplateName.OperatorFunctionId.Operator; - TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create( - SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK, + TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create( + SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK, LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds); Tok.setAnnotationValue(TemplateId); Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -216,18 +216,14 @@ /// \brief Parse a constraint-expression. /// /// \verbatim -/// constraint-expression: [Concepts TS temp.constr.decl p1] +/// constraint-expression: C++2a[temp.constr.decl]p1 /// logical-or-expression /// \endverbatim ExprResult Parser::ParseConstraintExpression() { - // FIXME: this may erroneously consume a function-body as the braced - // initializer list of a compound literal - // - // FIXME: this may erroneously consume a parenthesized rvalue reference - // declarator as a parenthesized address-of-label expression - ExprResult LHS(ParseCastExpression(/*isUnaryExpression=*/false)); - ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr)); - + ExprResult Res(ParseExpression()); + if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) { + return ExprError(); + } return Res; } Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -602,6 +602,10 @@ return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); } + Value *VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E) { + return Builder.getInt1(E->isSatisfied()); + } + Value *VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) { return llvm::ConstantInt::get(Builder.getInt32Ty(), E->getValue()); } Index: lib/CodeGen/CGDecl.cpp =================================================================== --- lib/CodeGen/CGDecl.cpp +++ lib/CodeGen/CGDecl.cpp @@ -105,6 +105,7 @@ case Decl::OMPThreadPrivate: case Decl::OMPCapturedExpr: case Decl::Empty: + case Decl::Concept: // None of these decls require codegen support. return; Index: lib/AST/StmtProfile.cpp =================================================================== --- lib/AST/StmtProfile.cpp +++ lib/AST/StmtProfile.cpp @@ -1233,6 +1233,14 @@ ID.AddInteger(S->getOp()); } +void StmtProfiler::VisitConceptSpecializationExpr( + const ConceptSpecializationExpr *S) { + VisitExpr(S); + VisitDecl(S->getSpecializedConcept()); + VisitTemplateArguments(S->getTemplateArgumentListInfo()->getArgumentArray(), + S->getTemplateArgumentListInfo()->size()); +} + static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S, UnaryOperatorKind &UnaryOp, BinaryOperatorKind &BinaryOp) { Index: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp +++ lib/AST/StmtPrinter.cpp @@ -2549,6 +2549,12 @@ OS << ")"; } +void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) { + OS << E->getSpecializedConcept()->getName(); + printTemplateArgumentList(OS, E->getTemplateArgumentListInfo()->arguments(), + Policy); +} + // C++ Coroutines TS void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) { Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -3464,6 +3464,7 @@ case Expr::ConvertVectorExprClass: case Expr::StmtExprClass: case Expr::TypeTraitExprClass: + case Expr::ConceptSpecializationExprClass: case Expr::ArrayTypeTraitExprClass: case Expr::ExpressionTraitExprClass: case Expr::VAArgExprClass: Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -7074,6 +7074,7 @@ bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E); bool VisitSizeOfPackExpr(const SizeOfPackExpr *E); + bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E); // FIXME: Missing: array subscript of vector, member of vector }; } // end anonymous namespace @@ -9079,6 +9080,15 @@ return Success(E->getValue(), E); } +bool IntExprEvaluator::VisitConceptSpecializationExpr( + const ConceptSpecializationExpr *E) { + if (E->isValueDependent()) { + return Error(E); + } + return Success(E->isSatisfied(), E); +} + + //===----------------------------------------------------------------------===// // Float Evaluation //===----------------------------------------------------------------------===// @@ -10368,6 +10378,7 @@ case Expr::CXXBoolLiteralExprClass: case Expr::CXXScalarValueInitExprClass: case Expr::TypeTraitExprClass: + case Expr::ConceptSpecializationExprClass: case Expr::ArrayTypeTraitExprClass: case Expr::ExpressionTraitExprClass: case Expr::CXXNoexceptExprClass: Index: lib/AST/ExprClassification.cpp =================================================================== --- lib/AST/ExprClassification.cpp +++ lib/AST/ExprClassification.cpp @@ -190,6 +190,7 @@ case Expr::ArrayInitIndexExprClass: case Expr::NoInitExprClass: case Expr::DesignatedInitUpdateExprClass: + case Expr::ConceptSpecializationExprClass: return Cl::CL_PRValue; // Next come the complicated cases. Index: lib/AST/ExprCXX.cpp =================================================================== --- lib/AST/ExprCXX.cpp +++ lib/AST/ExprCXX.cpp @@ -29,6 +29,9 @@ #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Sema/Template.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Sema/Sema.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" @@ -1433,3 +1436,97 @@ } void ArrayTypeTraitExpr::anchor() {} + +ConceptSpecializationExpr::ConceptSpecializationExpr(ASTContext &C, Sema &S, + SourceLocation ConceptNameLoc, + ConceptDecl *CD, + const TemplateArgumentListInfo *TALI) + : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary, + /*TypeDependent=*/false, + // All the flags below are set in setTemplateArguments. + /*ValueDependent=*/false, /*InstantiationDependent=*/false, + /*ContainsUnexpandedParameterPacks=*/false), SpecializedConcept(CD), + ConceptNameLoc(ConceptNameLoc) { + setTemplateArguments(&S, TALI); +} + +ConceptSpecializationExpr::ConceptSpecializationExpr(ASTContext &C) + : Expr(ConceptSpecializationExprClass, EmptyShell()) { } + +bool ConceptSpecializationExpr::evaluate(Sema &S) +{ + llvm::SmallVector<TemplateArgument, 4> Converted; + if (S.CheckTemplateArgumentList(SpecializedConcept, + SpecializedConcept->getLocStart(), + TemplateArgInfo, + /*PartialTemplateArgs=*/false, Converted, + /*UpdateArgsWithConversion=*/false)) { + // We converted these arguments back in CheckConceptTemplateId, this should + // work. + return true; + } + EnterExpressionEvaluationContext ConstantEvaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + + MultiLevelTemplateArgumentList MLTAL; + MLTAL.addOuterTemplateArguments(Converted); + + ExprResult E; + { + // We do not want error diagnostics escaping here. + Sema::SFINAETrap Trap(S); + E = S.SubstExpr(SpecializedConcept->getConstraintExpr(), MLTAL); + if (E.isInvalid() || Trap.hasErrorOccurred()) { + // C++2a [temp.constr.atomic]p1 + // ...If substitution results in an invalid type or expression, the + // constraint is not satisfied. + IsSatisfied = false; + return true; + } + } + + if (!S.CheckConstraintExpression(E.get())) { + S.Diag(getLocStart(), diag::note_in_concept_specialization) << this; + return true; + } + + bool Satisfied = false; + if (!E.get()->EvaluateAsBooleanCondition(Satisfied, S.Context)) { + // C++2a [temp.constr.atomic]p1 + // ...E shall be a constant expression of type bool. + S.Diag(getLocStart(), diag::err_concept_non_constant_constraint_expression) + << this << E.get(); + return true; + } + IsSatisfied = Satisfied; + return false; +} + +bool ConceptSpecializationExpr::setTemplateArguments(Sema *S, + const TemplateArgumentListInfo *TALI){ + bool IsDependent = false; + bool ContainsUnexpandedParameterPack = false; + TemplateArgInfo = *TALI; + for (const TemplateArgumentLoc& LocInfo : TALI->arguments()) { + if (LocInfo.getArgument().isInstantiationDependent()) { + IsDependent = true; + if (ContainsUnexpandedParameterPack) { + break; + } + } + if (LocInfo.getArgument().containsUnexpandedParameterPack()) { + ContainsUnexpandedParameterPack = true; + if (IsDependent) { + break; + } + } + } + setValueDependent(IsDependent); + setInstantiationDependent(IsDependent); + setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack); + if (!IsDependent && S) { + return evaluate(*S); + } + return false; +} \ No newline at end of file Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -2998,6 +2998,7 @@ case ObjCAvailabilityCheckExprClass: case CXXUuidofExprClass: case OpaqueValueExprClass: + case ConceptSpecializationExprClass: // These never have a side-effect. return false; Index: lib/AST/DeclTemplate.cpp =================================================================== --- lib/AST/DeclTemplate.cpp +++ lib/AST/DeclTemplate.cpp @@ -798,6 +798,27 @@ } } +//===----------------------------------------------------------------------===// +// ConceptDecl Implementation +//===----------------------------------------------------------------------===// +ConceptDecl *ConceptDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, + Expr *ConstraintExpr) { + // TODO: Do we need this? + // AdoptTemplateParameterList(Params, cast<DeclContext>(Decl)); + 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 //===----------------------------------------------------------------------===// Index: lib/AST/DeclBase.cpp =================================================================== --- lib/AST/DeclBase.cpp +++ lib/AST/DeclBase.cpp @@ -768,6 +768,9 @@ case OMPDeclareReduction: return IDNS_OMPReduction; + case Concept: + return IDNS_Ordinary | IDNS_Tag; + // Never have names. case Friend: case FriendTemplate: Index: lib/AST/ASTDumper.cpp =================================================================== --- lib/AST/ASTDumper.cpp +++ lib/AST/ASTDumper.cpp @@ -458,6 +458,7 @@ bool DumpRefOnly); template<typename TemplateDecl> void VisitTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst); + void VisitConceptDecl(const ConceptDecl *D); void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D); void VisitClassTemplateDecl(const ClassTemplateDecl *D); void VisitClassTemplateSpecializationDecl( @@ -1570,6 +1571,12 @@ !D->isCanonicalDecl()); } +void ASTDumper::VisitConceptDecl(const ConceptDecl *D) { + dumpName(D); + dumpTemplateParameters(D->getTemplateParameters()); + dumpStmt(D->getConstraintExpr()); +} + void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { // FIXME: We don't add a declaration of a function template specialization // to its context when it's explicitly instantiated, so dump explicit Index: include/clang/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -1386,6 +1386,9 @@ /// \brief A TypeAliasTemplateDecl record. DECL_TYPE_ALIAS_TEMPLATE, + /// \brief A ConceptDecl record. + DECL_CONCEPT, + /// \brief A StaticAssertDecl record. DECL_STATIC_ASSERT, @@ -1786,6 +1789,7 @@ EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr EXPR_CXX_FOLD, // CXXFoldExpr + EXPR_CONCEPT_SPECIALIZATION,// ConceptSpecializationExpr // CUDA EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -5572,7 +5572,15 @@ CXXConversionDecl *Conv, Expr *Src); - // ParseObjCStringLiteral - Parse Objective-C string literals. + ExprResult CreateConceptSpecializationExpr(SourceLocation ConceptNameLoc, + ConceptDecl *CTD, + const TemplateArgumentListInfo *TALI); + + /// Check whether the given expression is a valid constraint expression. + /// A diagnostic is emmited if it is not, and false is returned. + bool CheckConstraintExpression(Expr *CE); + + // ParseObjCStringLiteral - Parse Objective-C string literals. ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, ArrayRef<Expr *> Strings); @@ -6187,6 +6195,13 @@ SourceLocation TemplateLoc, const TemplateArgumentListInfo *TemplateArgs); + ExprResult + CheckConceptTemplateId(const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + ConceptDecl *Template, + SourceLocation TemplateLoc, + const TemplateArgumentListInfo *TemplateArgs); + ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, @@ -6466,6 +6481,13 @@ const TemplateArgument *Args, unsigned NumArgs); + // Concepts + Decl *ActOnConceptDefinition( + Scope *S, + MultiTemplateParamsArg TemplateParameterLists, + IdentifierInfo *Name, SourceLocation L, + Expr *ConstraintExpr); + //===--------------------------------------------------------------------===// // C++ Variadic Templates (C++0x [temp.variadic]) //===--------------------------------------------------------------------===// Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -2784,6 +2784,14 @@ SourceLocation TemplateLoc, SourceLocation &DeclEnd, AccessSpecifier AS = AS_none); + // C++2a: Template, concept definition [temp] + Decl * + ParseConceptDefinition(unsigned Context, + const ParsedTemplateInfo &TemplateInfo, + ParsingDeclRAIIObject &DiagsFromTParams, + SourceLocation &DeclEnd, + AccessSpecifier AS, + AttributeList *AccessAttrs); //===--------------------------------------------------------------------===// // Modules Index: include/clang/Basic/TemplateKinds.h =================================================================== --- include/clang/Basic/TemplateKinds.h +++ include/clang/Basic/TemplateKinds.h @@ -43,10 +43,9 @@ /// whether the template name is assumed to refer to a type template or a /// function template depends on the context in which the template /// name occurs. - TNK_Dependent_template_name + TNK_Dependent_template_name, + TNK_Concept_template }; } #endif - - Index: include/clang/Basic/StmtNodes.td =================================================================== --- include/clang/Basic/StmtNodes.td +++ include/clang/Basic/StmtNodes.td @@ -153,6 +153,9 @@ def DependentCoawaitExpr : DStmt<Expr>; def CoyieldExpr : DStmt<CoroutineSuspendExpr>; +// C++2a Concepts expressions +def ConceptSpecializationExpr : DStmt<Expr>; + // Obj-C Expressions. def ObjCStringLiteral : DStmt<Expr>; def ObjCBoxedExpr : DStmt<Expr>; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2368,7 +2368,7 @@ def note_private_extern : Note< "use __attribute__((visibility(\"hidden\"))) attribute instead">; -// C++ Concepts TS +// C++ Concepts 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< @@ -2394,6 +2394,18 @@ def err_concept_specialized : Error< "%select{function|variable}0 concept cannot be " "%select{explicitly instantiated|explicitly specialized|partially specialized}1">; +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_extra_headers : Error< + "extraneous template parameter list in concept definition">; +def err_concept_no_associated_constraints : Error< + "concept may not have associated constraints">; +def err_concept_non_constant_constraint_expression : Error< + "concept specialization '%0' resulted in a non-constant expression '%1'.">; +def err_non_bool_atomic_constraint : Error< + "atomic constraint '%0' must be of type 'bool' (found %1)">; +def note_in_concept_specialization : Note< + "in concept specialization '%0'">; def err_template_different_associated_constraints : Error< "associated constraints differ in template redeclaration">; Index: include/clang/Basic/DeclNodes.td =================================================================== --- include/clang/Basic/DeclNodes.td +++ include/clang/Basic/DeclNodes.td @@ -69,6 +69,7 @@ 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>; Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -1722,6 +1722,8 @@ DEF_TRAVERSE_TMPL_DECL(Var) DEF_TRAVERSE_TMPL_DECL(Function) +DEF_TRAVERSE_DECL(ConceptDecl, {}) + DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, { // D is the "T" in something like // template <template <typename> class T> class container { }; @@ -2583,6 +2585,12 @@ } }) +DEF_TRAVERSE_STMT(ConceptSpecializationExpr, { + TRY_TO(TraverseTemplateArgumentLocsHelper( + S->getTemplateArgumentListInfo()->getArgumentArray(), + S->getTemplateArgumentListInfo()->size())); +}) + // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, {}) DEF_TRAVERSE_STMT(CharacterLiteral, {}) Index: include/clang/AST/ExprCXX.h =================================================================== --- include/clang/AST/ExprCXX.h +++ include/clang/AST/ExprCXX.h @@ -57,6 +57,8 @@ class LambdaCapture; class NonTypeTemplateParmDecl; class TemplateParameterList; +class ConceptDecl; +class Sema; //===--------------------------------------------------------------------===// // C++ Expressions. @@ -4407,6 +4409,96 @@ } }; +/// \brief Represents the specialization of a concept - evaluates to a prvalue +/// of type bool. +/// +/// According to C++2a [expr.prim.id]p3 an id-expression that denotes the +/// specialization of a concepts results in a prvalue of type bool. +class ConceptSpecializationExpr final : public Expr { +protected: + /// \brief The concept specialization this represents. + ConceptDecl *SpecializedConcept; + + /// \brief The template argument list used to specialize the concept. + TemplateArgumentList *TemplateArgs; + TemplateArgumentListInfo TemplateArgInfo; + + /// \brief The location of the concept name in the expression. + SourceLocation ConceptNameLoc; + + /// \brief Whether or not the concept with the given arguments was satisfied + /// when the expression was created. If any of the template arguments are + /// dependent (this expr would then be isValueDependent()), this is to be + /// ignored. + bool IsSatisfied : 1; + + /// \brief Evaluates this concept specialization to determine whether or not + /// the concept is satisfied. Returns true if an error occured and the concept + /// could not be checked for satisfaction. + bool evaluate(Sema &S); + +public: + ConceptSpecializationExpr(ASTContext &C, Sema &S, + SourceLocation ConceptNameLoc, ConceptDecl *CD, + const TemplateArgumentListInfo *TALI); + + ConceptSpecializationExpr(ASTContext &C); + + ConceptDecl *getSpecializedConcept() { + return SpecializedConcept; + } + const ConceptDecl *getSpecializedConcept() const { + return SpecializedConcept; + } + void setSpecializedConcept(ConceptDecl *C) { + SpecializedConcept = C; + } + + const TemplateArgumentList *getTemplateArguments() const { + return TemplateArgs; + } + const TemplateArgumentListInfo *getTemplateArgumentListInfo() const { + return &TemplateArgInfo; + } + + /// \brief Set new template arguments for this concept specialization. Returns + /// true if an error occured (the template arguments do not match the concept, + /// probably) + bool setTemplateArguments(Sema *S, const TemplateArgumentListInfo *TALI); + + /// \brief Whether or not the concept with the given arguments was satisfied + /// when the expression was created. This method assumes that the expression + /// is not dependent! + bool isSatisfied() const { + assert(!isValueDependent() + && "isSatisfied called on a dependent ConceptSpecializationExpr"); + return IsSatisfied; + } + + void setSatisfied(bool Satisfied) { + IsSatisfied = Satisfied; + } + + SourceLocation getConceptNameLoc() const { return ConceptNameLoc; } + void setConceptNameLoc(SourceLocation Loc) { + ConceptNameLoc = Loc; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ConceptSpecializationExprClass; + } + + SourceLocation getLocStart() const LLVM_READONLY { return ConceptNameLoc; } + SourceLocation getLocEnd() const LLVM_READONLY { + return TemplateArgInfo.getRAngleLoc(); + } + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } +}; + } // namespace clang #endif // LLVM_CLANG_AST_EXPRCXX_H Index: include/clang/AST/DeclTemplate.h =================================================================== --- include/clang/AST/DeclTemplate.h +++ include/clang/AST/DeclTemplate.h @@ -3032,6 +3032,46 @@ static bool classofKind(Kind K) { return K == VarTemplate; } }; +// \brief Definition of concept, not just declaration actually. +class ConceptDecl : public TemplateDecl { +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; + } + + void setConstraintExpr(Expr *CE) { + ConstraintExpr = CE; + } + + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(getLocation(), getConstraintExpr()->getLocEnd()); + } + + // 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;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits