summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFaisal Vali <faisalv@yahoo.com>2018-04-25 02:42:26 +0000
committerFaisal Vali <faisalv@yahoo.com>2018-04-25 02:42:26 +0000
commit45d663da5615045d3c2da1b97ef06319055deb42 (patch)
tree985c65f7cadf4c48303264e03a14e0bbb2ec286e
parente4c4fc5523dfcbad4efc78103cbb51ba34613f53 (diff)
downloadclang-45d663da5615045d3c2da1b97ef06319055deb42.tar.gz
[c++2a] [concepts] Add rudimentary parsing support for template concept declarations
This patch is a tweak of changyu's patch: https://reviews.llvm.org/D40381. It differs in that the recognition of the 'concept' token is moved into the machinery that recognizes declaration-specifiers - this allows us to leverage the attribute handling machinery more seamlessly. See the test file to get a sense of the basic parsing that this patch supports. There is much more work to be done before concepts are usable... Thanks Changyu! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@330794 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/DeclTemplate.h40
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h7
-rw-r--r--include/clang/Basic/DeclNodes.td1
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td18
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td35
-rw-r--r--include/clang/Basic/TemplateKinds.h6
-rw-r--r--include/clang/Parse/Parser.h16
-rw-r--r--include/clang/Sema/DeclSpec.h52
-rw-r--r--include/clang/Sema/Sema.h15
-rw-r--r--include/clang/Serialization/ASTBitCodes.h3
-rw-r--r--lib/AST/ASTDumper.cpp7
-rw-r--r--lib/AST/DeclBase.cpp1
-rw-r--r--lib/AST/DeclTemplate.cpp21
-rw-r--r--lib/CodeGen/CGDecl.cpp1
-rw-r--r--lib/CodeGen/CodeGenModule.cpp1
-rw-r--r--lib/Parse/ParseDecl.cpp22
-rw-r--r--lib/Parse/ParseDeclCXX.cpp4
-rw-r--r--lib/Parse/ParseObjc.cpp4
-rw-r--r--lib/Parse/ParseTemplate.cpp169
-rw-r--r--lib/Parse/ParseTentative.cpp1
-rw-r--r--lib/Parse/Parser.cpp6
-rw-r--r--lib/Sema/DeclSpec.cpp66
-rw-r--r--lib/Sema/SemaDecl.cpp6
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2
-rw-r--r--lib/Sema/SemaTemplate.cpp89
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp5
-rw-r--r--lib/Serialization/ASTCommon.cpp1
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp9
-rw-r--r--lib/Serialization/ASTWriter.cpp1
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp7
-rw-r--r--test/Parser/cxx-concept-declaration.cpp7
-rw-r--r--test/Parser/cxx2a-concept-declaration.cpp83
-rw-r--r--tools/libclang/CIndex.cpp1
33 files changed, 635 insertions, 72 deletions
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 9c68352e76..1fe95f4a59 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -3015,6 +3015,46 @@ public:
static bool classofKind(Kind K) { return K == VarTemplate; }
};
+/// \brief Represents a C++2a ([temp] p1) concept-definition.
+class ConceptDecl : public TemplateDecl {
+protected:
+ Expr *ConstraintExpr;
+
+ ConceptDecl(DeclContext *DC,
+ SourceLocation NameLoc, DeclarationName Name,
+ TemplateParameterList *Params,
+ Expr *ConstraintExpr)
+ : TemplateDecl(nullptr, Concept, DC, NameLoc, Name, Params),
+ ConstraintExpr(ConstraintExpr) {};
+public:
+ static ConceptDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation NameLoc, 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(getTemplateParameters()->getTemplateLoc(),
+ 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;
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 57641793f8..d9cc89b126 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -1722,6 +1722,13 @@ DEF_TRAVERSE_TMPL_DECL(Class)
DEF_TRAVERSE_TMPL_DECL(Var)
DEF_TRAVERSE_TMPL_DECL(Function)
+DEF_TRAVERSE_DECL(ConceptDecl, {
+ TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
+ TRY_TO(TraverseStmt(D->getConstraintExpr()));
+ // FIXME: Traverse all the concept specializations (once we implement forming
+ // template-ids with them).
+})
+
DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
// D is the "T" in something like
// template <template <typename> class T> class container { };
diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td
index 67ca9e5c6c..0ab6e32e4d 100644
--- a/include/clang/Basic/DeclNodes.td
+++ b/include/clang/Basic/DeclNodes.td
@@ -69,6 +69,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>;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 7c7c0fb24d..4b6c9fcb1a 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -1150,6 +1150,24 @@ def err_pragma_cannot_end_force_cuda_host_device : Error<
"force_cuda_host_device begin">;
} // end of Parse Issue category.
+let CategoryName = "Concepts Issue" in {
+def err_concept_at_non_namespace_scope : Error<
+ "'concept' can only appear in namespace scope">;
+
+def err_concept_extra_headers : Error<
+ "extraneous template parameter list in concept definition">;
+def err_concept_unexpected_scope_spec : Error<
+ "invalid nested name specifier; concepts must be defined in their own namespace">;
+def err_concept_nontemplate : Error<"concept definition must be a template; "
+ "missing template parameter list">;
+def err_concept_specialized : Error<
+ "'concept' cannot be "
+ "%select{explicitly specialized|partially specialized}0">;
+def note_concept_specialized : Note<
+ "'concept' cannot be "
+ "%select{explicitly specialized|partially specialized}0">;
+}
+
let CategoryName = "Modules Issue" in {
def err_unexpected_module_decl : Error<
"module declaration can only appear at the top level">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index c1ee929e23..59b78b6fe6 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2387,33 +2387,16 @@ 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<
+ "type of constraint expression must be 'bool' - not '%0'">;
+def err_concept_no_associated_constraints : Error<
+ "concept may not have associated constraints">;
+def err_concept_feature_unimplemented : Error<
+ "unimplemented concept feature: %0 (coming soon)">;
def err_template_different_associated_constraints : Error<
"associated constraints differ in template redeclaration">;
diff --git a/include/clang/Basic/TemplateKinds.h b/include/clang/Basic/TemplateKinds.h
index ac99ad185f..85658af007 100644
--- a/include/clang/Basic/TemplateKinds.h
+++ b/include/clang/Basic/TemplateKinds.h
@@ -43,10 +43,10 @@ enum TemplateNameKind {
/// 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,
+ /// The name refers to a concept definition.
+ TNK_Concept_template
};
}
#endif
-
-
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 619b56363f..514656ffb9 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -1959,7 +1959,16 @@ private:
ParsedAttributesWithRange &Attrs);
DeclSpecContext
getDeclSpecContextFromDeclaratorContext(DeclaratorContext Context);
- void ParseDeclarationSpecifiers(
+
+ /// \brief Parses declaration-specifiers upto a declarator or ';' emitting
+ /// diagnostics as necessary and storing parsed information within DS.
+ ///
+ /// Note: Asides from parsing the routine C/C++ decl-specifiers (which could
+ /// include entire class or enum definitions), this also parses a concept
+ /// definition and stores the appropriate AST representations (for
+ /// class/enum/concept declarations/definitions, decltype
+ /// expression-operands or types, where appropriate) within DS.
+ void ParseDeclarationSpecifiersOrConceptDefinition(
DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
AccessSpecifier AS = AS_none,
@@ -2811,6 +2820,11 @@ private:
SourceLocation &DeclEnd,
AccessSpecifier AS = AS_none);
+ /// \brief Parse a single template declaration that declares a concept [c++2a]
+ /// and store the AST node within DS.
+ void ParseConceptDefinition(SourceLocation ConceptLoc, DeclSpec &DS,
+ const ParsedTemplateInfo &TemplateInfo,
+ AccessSpecifier AS, DeclSpecContext DSC);
//===--------------------------------------------------------------------===//
// Modules
DeclGroupPtrTy ParseModuleDecl();
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index e9b116fb71..d693012c71 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -38,6 +38,7 @@
namespace clang {
class ASTContext;
class CXXRecordDecl;
+ class ConceptDecl;
class TypeLoc;
class LangOptions;
class IdentifierInfo;
@@ -221,10 +222,13 @@ public:
unsigned location_size() const { return Builder.getBuffer().second; }
};
-/// \brief Captures information about "declaration specifiers".
+/// \brief Captures information about "decl-specifiers" and also concept
+/// definitions.
///
/// "Declaration specifiers" encompasses storage-class-specifiers,
-/// type-specifiers, type-qualifiers, and function-specifiers.
+/// type-specifiers, type-qualifiers, and function-specifiers. This includes
+/// class and enum definitions whose AST representations must be stored - same
+/// with the expression-operands of decltype.
class DeclSpec {
public:
/// \brief storage-class-specifier
@@ -363,8 +367,14 @@ private:
unsigned Constexpr_specified : 1;
union {
+ // Valid if isTypeRep is true.
UnionParsedType TypeRep;
+ // If we parsed a concept, class, enum (etc.) defintion or elaborated type
+ // specifier, this stores the AST representation. This is valid if either
+ // isDeclRep or isConceptSpecified returns true.
Decl *DeclRep;
+ // If we parsed a typeof(e) or decltype(e) operator, this stores the
+ // expression 'e'. Valid if isExprRep is true.
Expr *ExprRep;
};
@@ -393,6 +403,11 @@ private:
SourceLocation FS_forceinlineLoc;
SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
SourceLocation TQ_pipeLoc;
+
+ // Even though 'concept' is not a specifier, we handle it here. This allows us
+ // to reuse infrastructure for diagnosing attributes and invalid
+ // decl-specifiers.
+ SourceLocation ConceptLoc;
WrittenBuiltinSpecs writtenBS;
void SaveWrittenBuiltinSpecs();
@@ -482,7 +497,10 @@ public:
bool isTypeSpecOwned() const { return TypeSpecOwned; }
bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); }
bool isTypeSpecPipe() const { return TypeSpecPipe; }
-
+ bool isDeclRep() const {
+ return isDeclRep((TST)TypeSpecType);
+ }
+
ParsedType getRepAsType() const {
assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type");
return TypeRep;
@@ -491,6 +509,17 @@ public:
assert(isDeclRep((TST) TypeSpecType) && "DeclSpec does not store a decl");
return DeclRep;
}
+ // This is a template that should only be instantiated with the type
+ // ConceptDecl. By making it a template we only require ConceptDecl to be a
+ // complete type where this function is called.
+ template<class ConceptDeclTy = ConceptDecl>
+ ConceptDeclTy *getRepAsConcept() const {
+ static_assert(std::is_same<ConceptDeclTy, ConceptDecl>::value,
+ "Must only be instantiated with ConceptDecl");
+ assert(isConceptSpecified() && "DeclSpec does not store a concept");
+
+ return cast_or_null<ConceptDeclTy>(DeclRep);
+ }
Expr *getRepAsExpr() const {
assert(isExprRep((TST) TypeSpecType) && "DeclSpec does not store an expr");
return ExprRep;
@@ -665,6 +694,19 @@ public:
assert(isDeclRep((TST) TypeSpecType));
DeclRep = Rep;
}
+ // This function can only be instantiated with ConceptDecl. We made it a
+ // template so that ConceptDecl only has to be defined where this is called.
+ template <class ConceptDeclTy = ConceptDecl>
+ void setConceptRep(ConceptDecl *Rep) {
+ static_assert(std::is_same<ConceptDeclTy, ConceptDecl>::value,
+ "Must only be instantiated with ConceptDecl");
+ assert(isConceptSpecified() && "DeclSpec does not store a concept");
+ assert(!DeclRep &&
+ "why is this not null? We expect this function to be called only "
+ "once, and usually right after DeclRep was set to null");
+ DeclRep = Rep;
+ }
+
void UpdateTypeRep(ParsedType Rep) {
assert(isTypeRep((TST) TypeSpecType));
TypeRep = Rep;
@@ -694,6 +736,8 @@ public:
unsigned &DiagID);
bool SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);
+ bool setConceptSpec(SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID, const PrintingPolicy &P);
bool isFriendSpecified() const { return Friend_specified; }
SourceLocation getFriendSpecLoc() const { return FriendLoc; }
@@ -704,6 +748,8 @@ public:
bool isConstexprSpecified() const { return Constexpr_specified; }
SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; }
+ bool isConceptSpecified() const { return ConceptLoc.isValid(); }
+ SourceLocation getConceptLoc() const { return ConceptLoc; }
void ClearConstexprSpec() {
Constexpr_specified = false;
ConstexprLoc = SourceLocation();
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 485c537949..7897cf2a27 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -2126,6 +2126,7 @@ public:
Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
RecordDecl *&AnonRecord);
+
Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
MultiTemplateParamsArg TemplateParams,
bool IsExplicitInstantiation,
@@ -6229,6 +6230,13 @@ public:
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,
@@ -6507,6 +6515,13 @@ public:
const TemplateArgument *Args,
unsigned NumArgs);
+ // Concepts
+ ConceptDecl *ActOnConceptDefinition(
+ Scope *S,
+ MultiTemplateParamsArg TemplateParameterLists,
+ IdentifierInfo *Name, SourceLocation NameLoc,
+ Expr *ConstraintExpr);
+
//===--------------------------------------------------------------------===//
// C++ Variadic Templates (C++0x [temp.variadic])
//===--------------------------------------------------------------------===//
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 1f4e0347bc..169075983c 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -1408,6 +1408,9 @@ namespace serialization {
/// \brief A TypeAliasTemplateDecl record.
DECL_TYPE_ALIAS_TEMPLATE,
+ /// \brief A ConceptDecl record.
+ DECL_CONCEPT,
+
/// \brief A StaticAssertDecl record.
DECL_STATIC_ASSERT,
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index cf512b9bd3..b0f0c5d0f5 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -466,6 +466,7 @@ namespace {
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(
@@ -1577,6 +1578,12 @@ void ASTDumper::VisitTemplateDecl(const TemplateDecl *D,
!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
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index baf83a393c..ba02903683 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -724,6 +724,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;
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 8854f7879a..19778af79f 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -789,6 +789,27 @@ ClassTemplateSpecializationDecl::getSourceRange() const {
}
//===----------------------------------------------------------------------===//
+// ConceptDecl Implementation
+//===----------------------------------------------------------------------===//
+ConceptDecl *ConceptDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation NameLoc, DeclarationName Name,
+ TemplateParameterList *Params,
+ Expr *ConstraintExpr) {
+ // TODO: Do we need this?
+ // AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
+ return new (C, DC) ConceptDecl(DC, NameLoc, 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
//===----------------------------------------------------------------------===//
void ClassTemplatePartialSpecializationDecl::anchor() {}
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index c9b80e38d4..38eb0c8fe7 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -105,6 +105,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::OMPThreadPrivate:
case Decl::OMPCapturedExpr:
case Decl::Empty:
+ case Decl::Concept:
// None of these decls require codegen support.
return;
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 063b9be4cd..b8bed33b02 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -4423,6 +4423,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::TypeAliasTemplate:
case Decl::Block:
case Decl::Empty:
+ case Decl::Concept:
break;
case Decl::Using: // using X; [C++]
if (CGDebugInfo *DI = getModuleDebugInfo())
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 3d3abe32ab..9b0828a6d5 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1739,7 +1739,8 @@ Parser::ParseSimpleDeclaration(DeclaratorContext Context,
ParsingDeclSpec DS(*this);
DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(Context);
- ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, DSContext);
+ ParseDeclarationSpecifiersOrConceptDefinition(DS, ParsedTemplateInfo(),
+ AS_none, DSContext);
// If we had a free-standing type definition with a missing semicolon, we
// may get this far before the problem becomes obvious.
@@ -2386,7 +2387,8 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
/// specifier-qualifier-list is a subset of declaration-specifiers. Just
/// parse declaration-specifiers and complain about extra stuff.
/// TODO: diagnose attribute-specifiers and alignment-specifiers.
- ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC);
+ ParseDeclarationSpecifiersOrConceptDefinition(DS, ParsedTemplateInfo(), AS,
+ DSC);
// Validate declspec for type-name.
unsigned Specs = DS.getParsedSpecifiers();
@@ -2871,11 +2873,12 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
// and call ParsedFreeStandingDeclSpec as appropriate.
DS.ClearTypeSpecType();
ParsedTemplateInfo NotATemplate;
- ParseDeclarationSpecifiers(DS, NotATemplate, AS, DSContext, LateAttrs);
+ ParseDeclarationSpecifiersOrConceptDefinition(DS, NotATemplate, AS, DSContext,
+ LateAttrs);
return false;
}
-/// ParseDeclarationSpecifiers
+/// ParseDeclarationSpecifiersOrConceptDefinition
/// declaration-specifiers: [C99 6.7]
/// storage-class-specifier declaration-specifiers[opt]
/// type-specifier declaration-specifiers[opt]
@@ -2902,7 +2905,8 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
/// [OpenCL] '__kernel'
/// 'friend': [C++ dcl.friend]
/// 'constexpr': [C++0x dcl.constexpr]
-void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
+/// [C++2a] 'concept'
+void Parser::ParseDeclarationSpecifiersOrConceptDefinition(DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS,
DeclSpecContext DSContext,
@@ -3680,7 +3684,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
ConsumeToken();
ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSContext);
continue;
-
+
+ case tok::kw_concept:
+ ConsumeToken();
+ ParseConceptDefinition(Loc, DS, TemplateInfo, AS, DSContext);
+ continue;
// cv-qualifier:
case tok::kw_const:
isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID,
@@ -6366,7 +6374,7 @@ void Parser::ParseParameterDeclarationClause(
// too much hassle.
DS.takeAttributesFrom(FirstArgAttrs);
- ParseDeclarationSpecifiers(DS);
+ ParseDeclarationSpecifiersOrConceptDefinition(DS);
// Parse the declarator. This is "PrototypeContext" or
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 0c789c9b1c..e0db75ced5 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -2561,8 +2561,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (MalformedTypeSpec)
DS.SetTypeSpecError();
- ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DeclSpecContext::DSC_class,
- &CommonLateParsedAttrs);
+ ParseDeclarationSpecifiersOrConceptDefinition(
+ DS, TemplateInfo, AS, DeclSpecContext::DSC_class, &CommonLateParsedAttrs);
// Turn off colon protection that was set for declspec.
X.restore();
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 0ac418ad70..203d5e6d0d 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -1490,7 +1490,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
cStyleParamWarned = true;
}
DeclSpec DS(AttrFactory);
- ParseDeclarationSpecifiers(DS);
+ ParseDeclarationSpecifiersOrConceptDefinition(DS);
// Parse the declarator.
Declarator ParmDecl(DS, DeclaratorContext::PrototypeContext);
ParseDeclarator(ParmDecl);
@@ -2541,7 +2541,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
Scope::AtCatchScope);
if (Tok.isNot(tok::ellipsis)) {
DeclSpec DS(AttrFactory);
- ParseDeclarationSpecifiers(DS);
+ ParseDeclarationSpecifiersOrConceptDefinition(DS);
Declarator ParmDecl(DS, DeclaratorContext::ObjCCatchContext);
ParseDeclarator(ParmDecl);
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 88a5745350..82a049fddd 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -54,6 +54,15 @@ Parser::ParseDeclarationStartingWithTemplate(DeclaratorContext Context,
/// 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 *
@@ -148,13 +157,10 @@ Parser::ParseTemplateDeclarationOrSpecialization(DeclaratorContext Context,
unsigned NewFlags = getCurScope()->getFlags() & ~Scope::TemplateParamScope;
ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization);
- // Parse the actual template declaration.
- return ParseSingleDeclarationAfterTemplate(Context,
- ParsedTemplateInfo(&ParamLists,
- isSpecialization,
- LastParamListWasEmpty),
- ParsingTemplateParams,
- DeclEnd, AS, AccessAttrs);
+ return ParseSingleDeclarationAfterTemplate(
+ Context,
+ ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty),
+ ParsingTemplateParams, DeclEnd, AS, AccessAttrs);
}
/// \brief Parse a single declaration that declares a template,
@@ -208,7 +214,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
// the template parameters.
ParsingDeclSpec DS(*this, &DiagsFromTParams);
- ParseDeclarationSpecifiers(DS, TemplateInfo, AS,
+ ParseDeclarationSpecifiersOrConceptDefinition(DS, TemplateInfo, AS,
getDeclSpecContextFromDeclaratorContext(Context));
if (Tok.is(tok::semi)) {
@@ -322,6 +328,149 @@ Parser::ParseSingleDeclarationAfterTemplate(
return ThisDecl;
}
+
+void
+Parser::ParseConceptDefinition(SourceLocation ConceptLoc,
+ DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo,
+ AccessSpecifier AS,
+ DeclSpecContext DSC) {
+
+
+ auto DiagnoseAttributes = [this] {
+ ParsedAttributesWithRange attrs(this->AttrFactory);
+ this->MaybeParseGNUAttributes(attrs);
+ this->MaybeParseCXX11Attributes(attrs);
+ this->MaybeParseMicrosoftDeclSpecs(attrs);
+ this->ProhibitAttributes(attrs);
+ };
+
+
+ // If attributes exist after 'concept' kw but before the concept name,
+ // prohibit them for now (if CWG approves attributes on concepts, this is
+ // likely where they will go...).
+ DiagnoseAttributes();
+
+ // Set the concept specifier at ConceptLoc within 'DS' along with emitting any
+ // incompatible decl-specifier diagnostics.
+ {
+ const char *PrevSpec = 0;
+ unsigned int DiagId = 0;
+ if (DS.setConceptSpec(ConceptLoc, PrevSpec, DiagId,
+ Actions.getASTContext().getPrintingPolicy())) {
+ Diag(ConceptLoc, DiagId) << PrevSpec;
+ }
+ Actions.DiagnoseFunctionSpecifiers(DS);
+ }
+
+ if (DSC != DeclSpecContext::DSC_top_level) {
+ Diag(ConceptLoc, diag::err_concept_at_non_namespace_scope);
+ // If we are not in a template parameter context, skip to a '}' or ';'. The
+ // error messages are better if we just ignore this within template
+ // parameter lists.
+ if (DSC != DeclSpecContext::DSC_template_param) {
+ SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
+ } else {
+ SkipUntil(llvm::makeArrayRef({tok::comma, tok::greater}),
+ StopAtSemi | StopBeforeMatch);
+ }
+ return;
+ }
+
+ // A scope-guard that (if an error occurs while parsing a concept) skips to
+ // the next semi or closing brace.
+ class SkipUntilSemiOrClosingBraceOnScopeExit {
+ Parser &P;
+ bool Disabled = false;
+
+ public:
+ SkipUntilSemiOrClosingBraceOnScopeExit(Parser &P)
+ : P(P) {}
+ void disable() { Disabled = true; }
+ ~SkipUntilSemiOrClosingBraceOnScopeExit() {
+ if (!Disabled) {
+ // Skip until the semi-colon or a '}'.
+ P.SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
+ }
+ }
+ } SkipUntilSemiOrClosingBraceOnScopeExit(*this);
+
+ if (TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate) {
+ Diag(ConceptLoc, diag::err_concept_nontemplate);
+ return;
+ }
+
+ const TemplateParameterLists &ParamLists = *TemplateInfo.TemplateParams;
+
+
+ // More than one TPL wouldn't make sense here.
+ if (ParamLists.size() != 1) {
+ Diag(Tok.getLocation(), diag::err_concept_extra_headers);
+ return;
+ }
+ const TemplateParameterList *const TPL = ParamLists[0];
+
+ // Explicit specializations of concepts are not allowed.
+ if (TPL->getLAngleLoc().getLocWithOffset(1) == TPL->getRAngleLoc()) {
+ assert(!TPL->size() &&
+ "can not have template parameters within empty angle brackets!");
+ Diag(ConceptLoc, diag::err_concept_specialized) << 0;
+ return;
+ }
+ // Concepts can not be defined with nested name specifiers.
+ CXXScopeSpec SS;
+ if (ParseOptionalCXXScopeSpecifier(SS, nullptr,
+ /*EnteringContext=*/false) ||
+ SS.isNotEmpty()) {
+
+ if (SS.isNotEmpty())
+ Diag(Tok.getLocation(), diag::err_concept_unexpected_scope_spec);
+ return;
+ }
+ // An identifier (i.e. the concept-name) should follow 'concept'.
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_expected) << "concept name";
+ return;
+ }
+
+ IdentifierInfo *Id = Tok.getIdentifierInfo();
+ SourceLocation IdLoc = ConsumeToken();
+
+ // If attributes exist after the identifier, parse them and diagnose
+ DiagnoseAttributes();
+
+ if (!TryConsumeToken(tok::equal)) {
+ Diag(Tok.getLocation(), diag::err_expected) << "equal";
+ return;
+ }
+
+ ExprResult ConstraintExprResult = ParseConstraintExpression();
+ if (ConstraintExprResult.isInvalid()) {
+ Diag(Tok.getLocation(), diag::err_expected_expression)
+ << "constraint-expression";
+ return;
+ }
+
+ // We can try to create a valid concept decl node now, so disable the
+ // scope-guard.
+ SkipUntilSemiOrClosingBraceOnScopeExit.disable();
+
+ Expr *ConstraintExpr = ConstraintExprResult.get();
+ ConceptDecl *const ConDecl = Actions.ActOnConceptDefinition(
+ getCurScope(), *TemplateInfo.TemplateParams, Id, IdLoc, ConstraintExpr);
+ DS.setConceptRep(ConDecl);
+
+ if (Tok.isNot(tok::semi)) {
+
+ ExpectAndConsume(tok::semi, diag::err_expected_after, "concept");
+ // Push this token back into the preprocessor and change our current token
+ // to ';' so that the rest of the code recovers as though there were an
+ // ';' after the definition.
+ PP.EnterToken(Tok);
+ Tok.setKind(tok::semi);
+ }
+ return;
+}
+
/// 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.
@@ -690,8 +839,8 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
// FIXME: The type should probably be restricted in some way... Not all
// declarators (parts of declarators?) are accepted for parameters.
DeclSpec DS(AttrFactory);
- ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
- DeclSpecContext::DSC_template_param);
+ ParseDeclarationSpecifiersOrConceptDefinition(
+ DS, ParsedTemplateInfo(), AS_none, DeclSpecContext::DSC_template_param);
// Parse this as a typename.
Declarator ParamDecl(DS, DeclaratorContext::TemplateParamContext);
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index ebd6f0f5b8..5648d994fc 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -1351,6 +1351,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
case tok::kw_struct:
case tok::kw_union:
case tok::kw___interface:
+ case tok::kw_concept:
// enum-specifier
case tok::kw_enum:
// cv-qualifier
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index d8f9f7a390..17d046958d 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -919,7 +919,7 @@ Parser::ParseDeclOrFunctionDefInternal(ParsedAttributesWithRange &attrs,
AccessSpecifier AS) {
MaybeParseMicrosoftAttributes(DS.getAttributes());
// Parse the common declaration-specifiers piece.
- ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS,
+ ParseDeclarationSpecifiersOrConceptDefinition(DS, ParsedTemplateInfo(), AS,
DeclSpecContext::DSC_top_level);
// If we had a free-standing type definition with a missing semicolon, we
@@ -1287,7 +1287,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
// Parse the common declaration-specifiers piece.
DeclSpec DS(AttrFactory);
- ParseDeclarationSpecifiers(DS);
+ ParseDeclarationSpecifiersOrConceptDefinition(DS);
// C99 6.9.1p6: 'each declaration in the declaration list shall have at
// least one declarator'.
@@ -1647,7 +1647,7 @@ bool Parser::TryKeywordIdentFallback(bool DisableKeyword) {
/// Actions.getTypeName will not be needed to be called again (e.g. getTypeName
/// will not be called twice, once to check whether we have a declaration
/// specifier, and another one to get the actual type inside
-/// ParseDeclarationSpecifiers).
+/// ParseDeclarationSpecifiersOrConceptDefinition).
///
/// This returns true if an error occurred.
///
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index 2fad5a18ba..5f5d94eee3 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -426,6 +426,7 @@ unsigned DeclSpec::getParsedSpecifiers() const {
return Res;
}
+
template <class T> static bool BadSpecifier(T TNew, T TPrev,
const char *&PrevSpec,
unsigned &DiagID,
@@ -491,7 +492,6 @@ const char *DeclSpec::getSpecifierName(TSS S) {
}
llvm_unreachable("Unknown typespec!");
}
-
const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
const PrintingPolicy &Policy) {
switch (T) {
@@ -969,6 +969,69 @@ bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec,
return false;
}
+bool DeclSpec::setConceptSpec(const SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID, const PrintingPolicy &PP) {
+ assert(Loc.isValid() && "Loc must be valid, since it is used to identify "
+ "that this function was called before");
+ assert(!ConceptLoc.isValid() &&
+ "how is this called if concept was already encountered and triggered "
+ "ParseConceptDefinition which parses upto the semi-colon");
+
+ PrevSpec = nullptr;
+ if (TypeSpecType != TST_unspecified) {
+ PrevSpec = DeclSpec::getSpecifierName(static_cast<TST>(TypeSpecType), PP);
+ ClearTypeSpecType();
+ }
+ if (TypeSpecSign != TSS_unspecified) {
+ PrevSpec = DeclSpec::getSpecifierName(static_cast<TSS>(TypeSpecSign));
+ TypeSpecSign = TSS_unspecified;
+ }
+ if (TypeSpecWidth != TSW_unspecified) {
+ PrevSpec = DeclSpec::getSpecifierName(static_cast<TSW>(TypeSpecWidth));
+ TypeSpecWidth = TSW_unspecified;
+ }
+ if (StorageClassSpec != SCS_unspecified) {
+ PrevSpec = DeclSpec::getSpecifierName(static_cast<SCS>(StorageClassSpec));
+ ClearStorageClassSpecs();
+ }
+ if (ThreadStorageClassSpec != TSCS_unspecified) {
+ PrevSpec =
+ DeclSpec::getSpecifierName(static_cast<TSCS>(ThreadStorageClassSpec));
+ ClearStorageClassSpecs();
+ }
+ if (TypeSpecComplex != TSC_unspecified) {
+ PrevSpec = DeclSpec::getSpecifierName(static_cast<TSC>(TypeSpecComplex));
+ TypeSpecComplex = TSC_unspecified;
+ }
+ if (getTypeQualifiers()) {
+ PrevSpec = DeclSpec::getSpecifierName(static_cast<TQ>(TypeQualifiers));
+ ClearTypeQualifiers();
+ }
+ if (isFriendSpecified()) {
+ PrevSpec = "friend";
+ Friend_specified = false;
+ FriendLoc = SourceLocation();
+ }
+ if (isConstexprSpecified()) {
+ PrevSpec = "constexpr";
+ Constexpr_specified = false;
+ ConstexprLoc = SourceLocation();
+ }
+ if (isInlineSpecified()) {
+ PrevSpec = "inline";
+ FS_inlineLoc = SourceLocation();
+ FS_inline_specified = false;
+ }
+
+ if (PrevSpec) {
+ DiagID = diag::err_invalid_decl_spec_combination;
+ }
+ // We set the concept location regardless of whether an error occurred.
+ DeclRep = nullptr;
+ ConceptLoc = Loc;
+ return PrevSpec; // If this is non-null, an error occurred.
+}
+
void DeclSpec::SaveWrittenBuiltinSpecs() {
writtenBS.Sign = getTypeSpecSign();
writtenBS.Width = getTypeSpecWidth();
@@ -1270,6 +1333,7 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
// TODO: return "auto function" and other bad things based on the real type.
// 'data definition has no type or storage class'?
+
}
bool DeclSpec::isMissingDeclaratorOk() {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 1bcc9329e4..acbec1aca9 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -4212,6 +4212,12 @@ Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
MultiTemplateParamsArg TemplateParams,
bool IsExplicitInstantiation,
RecordDecl *&AnonRecord) {
+
+ // We don't need to do any additional declspecifier checking on concept
+ // definitions since that should already have been done when the concept kw
+ // location was set within DS.
+ if (DS.isConceptSpecified()) return DS.getRepAsConcept();
+
Decl *TagD = nullptr;
TagDecl *Tag = nullptr;
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 678f6af068..0fc399a375 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -9467,7 +9467,7 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
NonTemplateTarget = TargetTD->getTemplatedDecl();
UsingShadowDecl *Shadow;
- if (isa<CXXConstructorDecl>(NonTemplateTarget)) {
+ if (!isa<ConceptDecl>(Target) && isa<CXXConstructorDecl>(NonTemplateTarget)) {
bool IsVirtualBase =
isVirtualDirectBase(cast<CXXRecordDecl>(CurContext),
UD->getQualifier()->getAsRecordDecl());
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 5f739fd550..fbc65835d9 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -232,9 +232,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;
}
}
@@ -3034,7 +3036,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())
@@ -3988,6 +3991,18 @@ Sema::CheckVarTemplateId(const CXXScopeSpec &SS,
/*FoundD=*/nullptr, TemplateArgs);
}
+ExprResult
+Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
+ const DeclarationNameInfo &NameInfo,
+ ConceptDecl *Template,
+ SourceLocation TemplateLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ // TODO: Do concept specialization here.
+ Diag(Template->getLocation(), diag::err_concept_feature_unimplemented)
+ << "can not form concept template-id";
+ return ExprError();
+}
+
ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
LookupResult &R,
@@ -4009,14 +4024,21 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
// In C++1y, check variable template ids.
bool InstantiationDependent;
- if (R.getAsSingle<VarTemplateDecl>() &&
- !TemplateSpecializationType::anyDependentTemplateArguments(
- *TemplateArgs, InstantiationDependent)) {
+ const 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();
@@ -7688,6 +7710,61 @@ Decl *Sema::ActOnTemplateDeclarator(Scope *S,
return NewDecl;
}
+ConceptDecl *Sema::ActOnConceptDefinition(Scope *S,
+ MultiTemplateParamsArg TemplateParameterLists, IdentifierInfo *Name,
+ SourceLocation NameLoc, Expr *ConstraintExpr) {
+ // C++2a [temp.concept]p3:
+ // A concept-definition shall appear in the global scope or in a namespace
+ // scope.
+ assert(
+ CurContext->isFileContext() &&
+ "We check during parsing that 'concept's only occur at namespace scope");
+
+ // Forbid any prior declaration of this name within the current namespace.
+ LookupResult Previous(*this,
+ DeclarationNameInfo(DeclarationName(Name), NameLoc),
+ LookupOrdinaryName);
+ LookupName(Previous, S);
+ if (!Previous.empty()) {
+ const NamedDecl *PrevDecl = Previous.getRepresentativeDecl();
+ if (PrevDecl->getDeclContext()->Equals(CurContext)) {
+ if (Previous.isSingleResult() &&
+ isa<ConceptDecl>(Previous.getFoundDecl())) {
+ Diag(NameLoc, diag::err_redefinition) << Name;
+ } else {
+ Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
+ }
+ Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl;
+ return nullptr;
+ }
+ }
+
+ ConceptDecl *NewDecl = ConceptDecl::Create(Context, CurContext, NameLoc,
+ 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(NameLoc, diag::err_concept_no_associated_constraints);
+ NewDecl->setInvalidDecl();
+ }
+
+ assert((S->isTemplateParamScope() || !TemplateParameterLists[0]->size()) &&
+ "Not in template param scope?");
+ assert(S->getParent() && !S->getParent()->isTemplateParamScope() &&
+ "Parent scope should exist and not be template parameter.");
+
+ ActOnDocumentableDecl(NewDecl);
+ PushOnScopeChains(NewDecl, S->getParent(), /*AddToContext=*/true);
+
+ return NewDecl;
+}
+
/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
static void StripImplicitInstantiation(NamedDecl *D) {
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index a7883c67b8..0ebcb03ca3 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3073,6 +3073,11 @@ Decl *TemplateDeclInstantiator::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
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");
}
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index 535aacb8c4..82809cb465 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -313,6 +313,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
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 7a5d22c00f..1b0e1bbbf7 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -381,6 +381,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);
@@ -2031,6 +2032,11 @@ DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) {
return PatternID;
}
+void ASTDeclReader::VisitConceptDecl(ConceptDecl *D) {
+ VisitTemplateDecl(D);
+ D->setConstraintExpr(Record.readExpr());
+}
+
ASTDeclReader::RedeclarableResult
ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
RedeclarableResult Redecl = VisitRedeclarable(D);
@@ -3595,6 +3601,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;
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 7f2b1861d1..a055899009 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -1280,6 +1280,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);
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 189de14cff..432c2559e4 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -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);
@@ -1395,6 +1396,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);
diff --git a/test/Parser/cxx-concept-declaration.cpp b/test/Parser/cxx-concept-declaration.cpp
deleted file mode 100644
index 2e9d1ac2fc..0000000000
--- a/test/Parser/cxx-concept-declaration.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-
-// 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;
diff --git a/test/Parser/cxx2a-concept-declaration.cpp b/test/Parser/cxx2a-concept-declaration.cpp
new file mode 100644
index 0000000000..7c0923cfe7
--- /dev/null
+++ b/test/Parser/cxx2a-concept-declaration.cpp
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+// Support parsing of concepts
+
+concept X; //expected-error {{must be a template}}
+
+template<typename T> concept C1 = true; //expected-note{{declared here}} <-- previous declaration
+
+template<typename T> concept C1 = true; // expected-error {{redefinition of 'C1'}}
+
+template<concept T> concept D1 = true; // expected-error {{'concept' can only appear in namespace scope}} \
+ expected-error {{expected template parameter}}
+
+template<> concept X = true; // expected-error {{cannot be explicitly specialized}}
+
+namespace ns1 {
+template<> concept D1 = true; // expected-error {{cannot be explicitly specialized}}
+template<typename T> const concept C1 = true; //expected-error{{cannot combine with}}
+namespace ns12 {
+template<typename T> decltype(T{}) concept C2 = true; //expected-error{{cannot combine with}}
+template<typename T> bool concept C3 = true; //expected-error{{cannot combine with}}
+template<typename T> unsigned concept C4 = true; //expected-error{{cannot combine with}}
+template<typename T> short concept C5 = true; //expected-error{{cannot combine with}}
+template<typename T> typedef concept C6 = true; //expected-error{{cannot combine with}}
+}
+template<class> concept
+ const //expected-error{{expected concept name}}
+ C2 = true;
+
+void f() {
+ concept X; //expected-error{{'concept' can only appear in namespace scope}}
+}
+template<concept X, //expected-error{{'concept' can only appear in namespace scope}} \
+ expected-error {{expected template parameter}}
+ int J> void f();
+}
+
+template<class T>
+concept [[test]] X2 [[test2]] = T::value; //expected-error2{{attribute list cannot appear here}}
+
+namespace ns2 {
+template<class T>
+concept [[test]] X2 [[test2]] = T::value; //expected-error2{{attribute list cannot appear here}}
+
+}
+
+namespace ns3 {
+ template<typename T> concept C1 = true;
+
+ namespace ns1 {
+ using ns3::C1; //expected-note{{declared here}}
+ template<typename T> concept C1 = true; // expected-error {{redefinition of 'C1'}}
+ }
+
+}
+
+// TODO:
+// template<typename T> concept C2 = 0.f; // expected error {{constraint expression must be 'bool'}}
+
+struct S1 {
+ template<typename T> concept C1 = true; // expected-error {{can only appear in 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}}
+
+struct C6 {}; //expected-note{{declared here}} <-- previous declaration
+template<typename T> concept C6 = true; // expected-error {{redefinition of 'C6' as different kind of symbol}}
+
+namespace thing {};
+
+template<typename T> concept thing::C7 = true; // expected-error {{concepts must be defined in their own namespace}}
+
+
+namespace ns5 {
+}
+
+// TODO: Add test to prevent explicit specialization, partial specialization
+// and explicit instantiation of concepts.
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 497a3ca8f5..17548f3379 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -6173,6 +6173,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