[llvm-branch-commits] [clang] 9e08e51 - [c++20] P1907R1: Support for generalized non-type template arguments of scalar type.
Richard Smith via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Dec 18 01:13:46 PST 2020
Author: Richard Smith
Date: 2020-12-18T01:08:41-08:00
New Revision: 9e08e51a20d0d2b1c5724bb17e969d036fced4cd
URL: https://github.com/llvm/llvm-project/commit/9e08e51a20d0d2b1c5724bb17e969d036fced4cd
DIFF: https://github.com/llvm/llvm-project/commit/9e08e51a20d0d2b1c5724bb17e969d036fced4cd.diff
LOG: [c++20] P1907R1: Support for generalized non-type template arguments of scalar type.
Added:
clang/test/CodeGenCXX/template-arguments.cpp
Modified:
clang/include/clang/AST/PropertiesBase.td
clang/include/clang/AST/RecursiveASTVisitor.h
clang/include/clang/AST/TemplateArgumentVisitor.h
clang/include/clang/AST/TemplateBase.h
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/include/clang/Serialization/ASTRecordWriter.h
clang/lib/AST/ASTContext.cpp
clang/lib/AST/ASTImporter.cpp
clang/lib/AST/ASTStructuralEquivalence.cpp
clang/lib/AST/Decl.cpp
clang/lib/AST/ItaniumMangle.cpp
clang/lib/AST/MicrosoftMangle.cpp
clang/lib/AST/ODRHash.cpp
clang/lib/AST/StmtProfile.cpp
clang/lib/AST/TemplateBase.cpp
clang/lib/AST/TypeLoc.cpp
clang/lib/CodeGen/CGDebugInfo.cpp
clang/lib/CodeGen/CGExprConstant.cpp
clang/lib/Index/USRGeneration.cpp
clang/lib/Sema/SemaLookup.cpp
clang/lib/Sema/SemaOverload.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/SemaTemplateVariadic.cpp
clang/lib/Sema/TreeTransform.h
clang/lib/Serialization/ASTReader.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/test/CodeGenCXX/mangle-ms-templates.cpp
clang/test/CodeGenCXX/mangle-template.cpp
clang/test/SemaTemplate/temp_arg_nontype_cxx17.cpp
clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
clang/tools/libclang/CIndex.cpp
clang/tools/libclang/CXCursor.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td
index ba0f237a3bc3..dbe75ab9de19 100644
--- a/clang/include/clang/AST/PropertiesBase.td
+++ b/clang/include/clang/AST/PropertiesBase.td
@@ -72,6 +72,7 @@ class CountPropertyType<string typeName = ""> : PropertyType<typeName> {
def APInt : PropertyType<"llvm::APInt"> { let PassByReference = 1; }
def APSInt : PropertyType<"llvm::APSInt"> { let PassByReference = 1; }
+def APValue : PropertyType { let PassByReference = 1; }
def ArraySizeModifier : EnumPropertyType<"ArrayType::ArraySizeModifier">;
def AttrKind : EnumPropertyType<"attr::Kind">;
def AutoTypeKeyword : EnumPropertyType;
@@ -450,6 +451,17 @@ let Class = PropertyTypeCase<TemplateArgument, "Integral"> in {
return TemplateArgument(ctx, value, type);
}]>;
}
+let Class = PropertyTypeCase<TemplateArgument, "UncommonValue"> in {
+ def : Property<"value", APValue> {
+ let Read = [{ node.getAsUncommonValue() }];
+ }
+ def : Property<"type", QualType> {
+ let Read = [{ node.getUncommonValueType() }];
+ }
+ def : Creator<[{
+ return TemplateArgument(ctx, type, value);
+ }]>;
+}
let Class = PropertyTypeCase<TemplateArgument, "Template"> in {
def : Property<"name", TemplateName> {
let Read = [{ node.getAsTemplateOrTemplatePattern() }];
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 96db0e439952..61e524793ec7 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -767,6 +767,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument(
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::NullPtr:
+ case TemplateArgument::UncommonValue:
return true;
case TemplateArgument::Type:
@@ -800,6 +801,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::NullPtr:
+ case TemplateArgument::UncommonValue:
return true;
case TemplateArgument::Type: {
diff --git a/clang/include/clang/AST/TemplateArgumentVisitor.h b/clang/include/clang/AST/TemplateArgumentVisitor.h
index 190aa97adf45..8c0da70b25eb 100644
--- a/clang/include/clang/AST/TemplateArgumentVisitor.h
+++ b/clang/include/clang/AST/TemplateArgumentVisitor.h
@@ -37,6 +37,7 @@ class Base {
DISPATCH(Declaration);
DISPATCH(NullPtr);
DISPATCH(Integral);
+ DISPATCH(UncommonValue);
DISPATCH(Template);
DISPATCH(TemplateExpansion);
DISPATCH(Expression);
@@ -59,6 +60,7 @@ class Base {
VISIT_METHOD(Declaration);
VISIT_METHOD(NullPtr);
VISIT_METHOD(Integral);
+ VISIT_METHOD(UncommonValue);
VISIT_METHOD(Template);
VISIT_METHOD(TemplateExpansion);
VISIT_METHOD(Expression);
diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h
index abf873a7ee40..9968143e8761 100644
--- a/clang/include/clang/AST/TemplateBase.h
+++ b/clang/include/clang/AST/TemplateBase.h
@@ -51,6 +51,7 @@ template <> struct PointerLikeTypeTraits<clang::Expr *> {
namespace clang {
+class APValue;
class ASTContext;
class DiagnosticBuilder;
class Expr;
@@ -82,6 +83,12 @@ class TemplateArgument {
/// that was provided for an integral non-type template parameter.
Integral,
+ /// The template argument is a non-type template argument that can't be
+ /// represented by the special-case Declaration, NullPtr, or Integral
+ /// forms. These values are only ever produced by constant evaluation,
+ /// so cannot be dependent.
+ UncommonValue,
+
/// The template argument is a template name that was provided for a
/// template template parameter.
Template,
@@ -125,6 +132,11 @@ class TemplateArgument {
};
void *Type;
};
+ struct V {
+ unsigned Kind;
+ const APValue *Value;
+ void *Type;
+ };
struct A {
unsigned Kind;
unsigned NumArgs;
@@ -142,6 +154,7 @@ class TemplateArgument {
union {
struct DA DeclArg;
struct I Integer;
+ struct V Value;
struct A Args;
struct TA TemplateArg;
struct TV TypeOrValue;
@@ -157,9 +170,8 @@ class TemplateArgument {
TypeOrValue.V = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
}
- /// Construct a template argument that refers to a
- /// declaration, which is either an external declaration or a
- /// template declaration.
+ /// Construct a template argument that refers to a (non-dependent)
+ /// declaration.
TemplateArgument(ValueDecl *D, QualType QT) {
assert(D && "Expected decl");
DeclArg.Kind = Declaration;
@@ -169,7 +181,11 @@ class TemplateArgument {
/// Construct an integral constant template argument. The memory to
/// store the value is allocated with Ctx.
- TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType Type);
+ TemplateArgument(const ASTContext &Ctx, const llvm::APSInt &Value,
+ QualType Type);
+
+ /// Construct a template argument from an arbitrary constant value.
+ TemplateArgument(const ASTContext &Ctx, QualType Type, const APValue &Value);
/// Construct an integral constant template argument with the same
/// value as Other but a
diff erent type.
@@ -340,6 +356,16 @@ class TemplateArgument {
Integer.Type = T.getAsOpaquePtr();
}
+ /// Get the value of an UncommonValue.
+ const APValue &getAsUncommonValue() const {
+ return *Value.Value;
+ }
+
+ /// Get the type of an UncommonValue.
+ QualType getUncommonValueType() const {
+ return QualType::getFromOpaquePtr(Value.Type);
+ }
+
/// If this is a non-type template argument, get its type. Otherwise,
/// returns a null QualType.
QualType getNonTypeTemplateArgumentType() const;
@@ -484,6 +510,7 @@ class TemplateArgumentLoc {
assert(Argument.getKind() == TemplateArgument::NullPtr ||
Argument.getKind() == TemplateArgument::Integral ||
Argument.getKind() == TemplateArgument::Declaration ||
+ Argument.getKind() == TemplateArgument::UncommonValue ||
Argument.getKind() == TemplateArgument::Expression);
}
@@ -542,6 +569,11 @@ class TemplateArgumentLoc {
return LocInfo.getAsExpr();
}
+ Expr *getSourceUncommonValueExpression() const {
+ assert(Argument.getKind() == TemplateArgument::UncommonValue);
+ return LocInfo.getAsExpr();
+ }
+
NestedNameSpecifierLoc getTemplateQualifierLoc() const {
if (Argument.getKind() != TemplateArgument::Template &&
Argument.getKind() != TemplateArgument::TemplateExpansion)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 24c2bb57b6f9..ace3064be7bc 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4656,8 +4656,6 @@ def err_non_type_template_arg_subobject : Error<
"non-type template argument refers to subobject '%0'">;
def err_non_type_template_arg_addr_label_
diff : Error<
"template argument / label address
diff erence / what did you expect?">;
-def err_non_type_template_arg_unsupported : Error<
- "sorry, non-type template argument of type %0 is not yet supported">;
def err_template_arg_not_convertible : Error<
"non-type template argument of type %0 cannot be converted to a value "
"of type %1">;
@@ -4709,9 +4707,6 @@ def err_template_arg_not_object_or_func : Error<
"non-type template argument does not refer to an object or function">;
def err_template_arg_not_pointer_to_member_form : Error<
"non-type template argument is not a pointer to member constant">;
-def err_template_arg_member_ptr_base_derived_not_supported : Error<
- "sorry, non-type template argument of pointer-to-member type %1 that refers "
- "to member %q0 of a
diff erent class is not supported yet">;
def ext_template_arg_extra_parens : ExtWarn<
"address non-type template argument cannot be surrounded by parentheses">;
def warn_cxx98_compat_template_arg_extra_parens : Warning<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 2c781eb88415..460d0c961c92 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -7623,8 +7623,8 @@ class Sema final {
QualType ParamType,
SourceLocation Loc);
ExprResult
- BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
- SourceLocation Loc);
+ BuildExpressionFromNonTypeTemplateArgument(const TemplateArgument &Arg,
+ SourceLocation Loc);
/// Enumeration describing how template parameter lists are compared
/// for equality.
diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h b/clang/include/clang/Serialization/ASTRecordWriter.h
index e362463b2309..ff654f417dda 100644
--- a/clang/include/clang/Serialization/ASTRecordWriter.h
+++ b/clang/include/clang/Serialization/ASTRecordWriter.h
@@ -166,6 +166,7 @@ class ASTRecordWriter
/// Emit an APvalue.
void AddAPValue(const APValue &Value);
+ void writeAPValue(const APValue &Value) { AddAPValue(Value); }
/// Emit a reference to an identifier.
void AddIdentifierRef(const IdentifierInfo *II) {
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 0190573fe36e..d396f81188df 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5941,6 +5941,11 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
case TemplateArgument::Integral:
return TemplateArgument(Arg, getCanonicalType(Arg.getIntegralType()));
+ case TemplateArgument::UncommonValue:
+ return TemplateArgument(*this,
+ getCanonicalType(Arg.getUncommonValueType()),
+ Arg.getAsUncommonValue());
+
case TemplateArgument::Type:
return TemplateArgument(getCanonicalType(Arg.getAsType()));
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 54816b721a4a..456e51ad3db4 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -808,6 +808,17 @@ ASTNodeImporter::import(const TemplateArgument &From) {
return TemplateArgument(*ToTypeOrErr, /*isNullPtr*/true);
}
+ case TemplateArgument::UncommonValue: {
+ ExpectedType ToTypeOrErr = import(From.getUncommonValueType());
+ if (!ToTypeOrErr)
+ return ToTypeOrErr.takeError();
+ Expected<APValue> ToValueOrErr = import(From.getAsUncommonValue());
+ if (!ToValueOrErr)
+ return ToValueOrErr.takeError();
+ return TemplateArgument(Importer.getToContext(), *ToTypeOrErr,
+ *ToValueOrErr);
+ }
+
case TemplateArgument::Template: {
Expected<TemplateName> ToTemplateOrErr = import(From.getAsTemplate());
if (!ToTemplateOrErr)
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index d004e443ae06..f7696bc7c921 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -565,6 +565,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return IsStructurallyEquivalent(Context, Arg1.getAsExpr(),
Arg2.getAsExpr());
+ case TemplateArgument::UncommonValue:
+ // FIXME: Do we need to customize the comparison?
+ return Arg1.structurallyEquals(Arg2);
+
case TemplateArgument::Pack:
if (Arg1.pack_size() != Arg2.pack_size())
return false;
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index f0c925f9cdf9..fd10ea56f171 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -342,6 +342,10 @@ LinkageComputer::getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args,
LV.merge(getTypeLinkageAndVisibility(Arg.getNullPtrType()));
continue;
+ case TemplateArgument::UncommonValue:
+ LV.merge(getLVForValue(Arg.getAsUncommonValue(), computation));
+ continue;
+
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
if (TemplateDecl *Template =
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 01deb598a078..08206c4e1a41 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -4079,10 +4079,28 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
mangleExpression(cast<CXXStdInitializerListExpr>(E)->getSubExpr(), Arity);
break;
- case Expr::SubstNonTypeTemplateParmExprClass:
- mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
- Arity);
+ case Expr::SubstNonTypeTemplateParmExprClass: {
+ // Mangle a substituted parameter the same way we mangle the template
+ // argument.
+ // As proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/111.
+ auto *SNTTPE = cast<SubstNonTypeTemplateParmExpr>(E);
+ if (auto *CE = dyn_cast<ConstantExpr>(SNTTPE->getReplacement())) {
+ // Pull out the constant value and mangle it as a template argument.
+ QualType ParamType = SNTTPE->getParameterType(Context.getASTContext());
+ if (CE->hasAPValueResult())
+ mangleValueInTemplateArg(ParamType, CE->getResultAsAPValue(), false,
+ /*NeedExactType=*/true);
+ else
+ mangleValueInTemplateArg(ParamType, CE->getAPValueResult(), false,
+ /*NeedExactType=*/true);
+ } else {
+ // The remaining cases all happen to be substituted with expressions that
+ // mangle the same as a corresponding template argument anyway.
+ mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
+ Arity);
+ }
break;
+ }
case Expr::UserDefinedLiteralClass:
// We follow g++'s approach of mangling a UDL as a call to the literal
@@ -5039,6 +5057,10 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A, bool NeedExactType) {
mangleNullPointer(A.getNullPtrType());
break;
}
+ case TemplateArgument::UncommonValue:
+ mangleValueInTemplateArg(A.getUncommonValueType(), A.getAsUncommonValue(),
+ /*TopLevel=*/true, NeedExactType);
+ break;
case TemplateArgument::Pack: {
// <template-arg> ::= J <template-arg>* E
Out << 'J';
@@ -5373,7 +5395,20 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V,
Out << "plcvPcad";
Kind = Offset;
} else {
- if (!V.getLValuePath().empty() || V.isLValueOnePastTheEnd()) {
+ // Clang 11 and before mangled an array subject to array-to-pointer decay
+ // as if it were the declaration itself.
+ bool IsArrayToPointerDecayMangledAsDecl = false;
+ if (TopLevel && Ctx.getLangOpts().getClangABICompat() <=
+ LangOptions::ClangABI::Ver11) {
+ QualType BType = B.getType();
+ IsArrayToPointerDecayMangledAsDecl =
+ BType->isArrayType() && V.getLValuePath().size() == 1 &&
+ V.getLValuePath()[0].getAsArrayIndex() == 0 &&
+ Ctx.hasSimilarType(T, Ctx.getDecayedType(BType));
+ }
+
+ if ((!V.getLValuePath().empty() || V.isLValueOnePastTheEnd()) &&
+ !IsArrayToPointerDecayMangledAsDecl) {
NotPrimaryExpr();
// A final conversion to the template parameter's type is usually
// folded into the 'so' mangling, but we can't do that for 'void*'
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index df6c566abc7d..16e0aa2ae466 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -1575,6 +1575,17 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
cast<NonTypeTemplateParmDecl>(Parm), T);
break;
}
+ case TemplateArgument::UncommonValue:
+ Out << "$";
+ if (cast<NonTypeTemplateParmDecl>(Parm)
+ ->getType()
+ ->getContainedDeducedType()) {
+ Out << "M";
+ mangleType(TA.getNonTypeTemplateArgumentType(), SourceRange(), QMM_Drop);
+ }
+ mangleTemplateArgValue(TA.getUncommonValueType(), TA.getAsUncommonValue(),
+ /*WithScalarType=*/false);
+ break;
case TemplateArgument::Expression:
mangleExpression(TA.getAsExpr(), cast<NonTypeTemplateParmDecl>(Parm));
break;
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 735bcff8f113..92e3bc27fca0 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -169,6 +169,8 @@ void ODRHash::AddTemplateArgument(TemplateArgument TA) {
break;
case TemplateArgument::NullPtr:
case TemplateArgument::Integral:
+ case TemplateArgument::UncommonValue:
+ // FIXME: Include a representation of these arguments.
break;
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index de9de6ff463c..569e3b06f3b2 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2208,6 +2208,12 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
Arg.getAsIntegral().Profile(ID);
break;
+ case TemplateArgument::UncommonValue:
+ VisitType(Arg.getUncommonValueType());
+ // FIXME: Do we need to recursively decompose this ourselves?
+ Arg.getAsUncommonValue().Profile(ID);
+ break;
+
case TemplateArgument::Expression:
Visit(Arg.getAsExpr());
break;
diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index 44d52c56ffbb..0029c90a0ab6 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -84,8 +84,8 @@ static void printIntegral(const TemplateArgument &TemplArg,
// TemplateArgument Implementation
//===----------------------------------------------------------------------===//
-TemplateArgument::TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value,
- QualType Type) {
+TemplateArgument::TemplateArgument(const ASTContext &Ctx,
+ const llvm::APSInt &Value, QualType Type) {
Integer.Kind = Integral;
// Copy the APSInt value into our decomposed form.
Integer.BitWidth = Value.getBitWidth();
@@ -103,6 +103,44 @@ TemplateArgument::TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value,
Integer.Type = Type.getAsOpaquePtr();
}
+static const ValueDecl *getAsSimpleValueDeclRef(const ASTContext &Ctx,
+ QualType T, const APValue &V) {
+ // Pointers to members are relatively easy.
+ if (V.isMemberPointer() && V.getMemberPointerPath().empty())
+ return V.getMemberPointerDecl();
+
+ // We model class non-type template parameters as their template parameter
+ // object declaration.
+ if (V.isStruct() || V.isUnion())
+ return Ctx.getTemplateParamObjectDecl(T, V);
+
+ // Pointers and references with an empty path use the special 'Declaration'
+ // representation.
+ if (V.isLValue() && V.hasLValuePath() &&
+ V.getLValuePath().empty() && !V.isLValueOnePastTheEnd())
+ return V.getLValueBase().dyn_cast<const ValueDecl *>();
+
+ // Everything else uses the 'uncommon' representation.
+ return nullptr;
+}
+
+TemplateArgument::TemplateArgument(const ASTContext &Ctx, QualType Type,
+ const APValue &V) {
+ if (Type->isIntegralOrEnumerationType() && V.isInt())
+ *this = TemplateArgument(Ctx, V.getInt(), Type);
+ else if ((V.isLValue() && V.isNullPointer()) ||
+ (V.isMemberPointer() && !V.getMemberPointerDecl()))
+ *this = TemplateArgument(Type, /*isNullPtr=*/true);
+ else if (const ValueDecl *VD = getAsSimpleValueDeclRef(Ctx, Type, V))
+ // FIXME: The Declaration form should expose a const ValueDecl*.
+ *this = TemplateArgument(const_cast<ValueDecl*>(VD), Type);
+ else {
+ Value.Kind = UncommonValue;
+ Value.Value = new (Ctx) APValue(V);
+ Value.Type = Type.getAsOpaquePtr();
+ }
+}
+
TemplateArgument
TemplateArgument::CreatePackCopy(ASTContext &Context,
ArrayRef<TemplateArgument> Args) {
@@ -134,6 +172,7 @@ TemplateArgumentDependence TemplateArgument::getDependence() const {
case NullPtr:
case Integral:
case Declaration:
+ case UncommonValue:
return TemplateArgumentDependence::None;
case Expression:
@@ -165,6 +204,7 @@ bool TemplateArgument::isPackExpansion() const {
case Null:
case Declaration:
case Integral:
+ case UncommonValue:
case Pack:
case Template:
case NullPtr:
@@ -215,6 +255,9 @@ QualType TemplateArgument::getNonTypeTemplateArgumentType() const {
case TemplateArgument::NullPtr:
return getNullPtrType();
+
+ case TemplateArgument::UncommonValue:
+ return getUncommonValueType();
}
llvm_unreachable("Invalid TemplateArgument Kind!");
@@ -259,8 +302,13 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
}
case Integral:
- getAsIntegral().Profile(ID);
getIntegralType().Profile(ID);
+ getAsIntegral().Profile(ID);
+ break;
+
+ case UncommonValue:
+ getUncommonValueType().Profile(ID);
+ getAsUncommonValue().Profile(ID);
break;
case Expression:
@@ -296,6 +344,16 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
return getIntegralType() == Other.getIntegralType() &&
getAsIntegral() == Other.getAsIntegral();
+ case UncommonValue: {
+ if (getUncommonValueType() != Other.getUncommonValueType())
+ return false;
+
+ llvm::FoldingSetNodeID A, B;
+ getAsUncommonValue().Profile(A);
+ Other.getAsUncommonValue().Profile(B);
+ return A == B;
+ }
+
case Pack:
if (Args.NumArgs != Other.Args.NumArgs) return false;
for (unsigned I = 0, E = Args.NumArgs; I != E; ++I)
@@ -322,6 +380,7 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
case Declaration:
case Integral:
+ case UncommonValue:
case Pack:
case Null:
case Template:
@@ -361,6 +420,10 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
break;
}
+ case UncommonValue:
+ getAsUncommonValue().printPretty(Out, Policy, getUncommonValueType());
+ break;
+
case NullPtr:
Out << "nullptr";
break;
@@ -443,6 +506,9 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
case TemplateArgument::Integral:
return getSourceIntegralExpression()->getSourceRange();
+ case TemplateArgument::UncommonValue:
+ return getSourceUncommonValueExpression()->getSourceRange();
+
case TemplateArgument::Pack:
case TemplateArgument::Null:
return SourceRange();
@@ -471,6 +537,18 @@ static const T &DiagTemplateArg(const T &DB, const TemplateArgument &Arg) {
case TemplateArgument::Integral:
return DB << Arg.getAsIntegral().toString(10);
+ case TemplateArgument::UncommonValue: {
+ // FIXME: We're guessing at LangOptions!
+ SmallString<32> Str;
+ llvm::raw_svector_ostream OS(Str);
+ LangOptions LangOpts;
+ LangOpts.CPlusPlus = true;
+ PrintingPolicy Policy(LangOpts);
+ Arg.getAsUncommonValue().printPretty(OS, Policy,
+ Arg.getUncommonValueType());
+ return DB << OS.str();
+ }
+
case TemplateArgument::Template:
return DB << Arg.getAsTemplate();
diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp
index 222b1abac510..438b6950890b 100644
--- a/clang/lib/AST/TypeLoc.cpp
+++ b/clang/lib/AST/TypeLoc.cpp
@@ -562,6 +562,7 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
case TemplateArgument::NullPtr:
+ case TemplateArgument::UncommonValue:
ArgInfos[i] = TemplateArgumentLocInfo();
break;
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 7b20d43b0f17..ae50f80e6fb5 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1953,6 +1953,14 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList,
TemplateParams.push_back(DBuilder.createTemplateValueParameter(
TheCU, Name, TTy, defaultParameter, V));
} break;
+ case TemplateArgument::UncommonValue: {
+ QualType T = TA.getUncommonValueType();
+ llvm::DIType *TTy = getOrCreateType(T, Unit);
+ llvm::Constant *V = ConstantEmitter(CGM).emitAbstract(
+ SourceLocation(), TA.getAsUncommonValue(), T);
+ TemplateParams.push_back(DBuilder.createTemplateValueParameter(
+ TheCU, Name, TTy, defaultParameter, V));
+ } break;
case TemplateArgument::Template:
TemplateParams.push_back(DBuilder.createTemplateTemplateParameter(
TheCU, Name, nullptr,
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index ca1d3a937fa8..840541a4af20 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1366,11 +1366,11 @@ llvm::Constant *ConstantEmitter::tryEmitConstantExpr(const ConstantExpr *CE) {
if (!CE->hasAPValueResult())
return nullptr;
const Expr *Inner = CE->getSubExpr()->IgnoreImplicit();
- QualType RetType;
- if (auto *Call = dyn_cast<CallExpr>(Inner))
- RetType = Call->getCallReturnType(CGF->getContext());
- else if (auto *Ctor = dyn_cast<CXXConstructExpr>(Inner))
- RetType = Ctor->getType();
+ QualType RetType = Inner->getType();
+ if (Inner->isLValue())
+ RetType = CGF->getContext().getLValueReferenceType(RetType);
+ else if (Inner->isXValue())
+ RetType = CGF->getContext().getRValueReferenceType(RetType);
llvm::Constant *Res =
emitAbstract(CE->getBeginLoc(), CE->getAPValueResult(), RetType);
return Res;
diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp
index abaeb1a4232f..9ada9ac8c209 100644
--- a/clang/lib/Index/USRGeneration.cpp
+++ b/clang/lib/Index/USRGeneration.cpp
@@ -983,6 +983,10 @@ void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
VisitType(Arg.getIntegralType());
Out << Arg.getAsIntegral();
break;
+
+ case TemplateArgument::UncommonValue:
+ // FIXME: Visit value.
+ break;
}
}
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 16dd8f510596..8885e4191987 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -2657,6 +2657,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
case TemplateArgument::Integral:
case TemplateArgument::Expression:
case TemplateArgument::NullPtr:
+ case TemplateArgument::UncommonValue:
// [Note: non-type template arguments do not contribute to the set of
// associated namespaces. ]
break;
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index ac52612ea3b0..5f4d5b9632e0 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -5774,7 +5774,9 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
if (Notes.empty()) {
// It's a constant expression.
- Expr *E = ConstantExpr::Create(S.Context, Result.get(), Value);
+ Expr *E = Result.get();
+ if (!isa<ConstantExpr>(E))
+ E = ConstantExpr::Create(S.Context, Result.get(), Value);
if (ReturnPreNarrowingValue)
Value = std::move(PreNarrowingValue);
return E;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 7ebd9be831ad..74a31c0a1b65 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4086,6 +4086,7 @@ static bool isTemplateArgumentTemplateParameter(
case TemplateArgument::NullPtr:
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
+ case TemplateArgument::UncommonValue:
case TemplateArgument::Pack:
case TemplateArgument::TemplateExpansion:
return false;
@@ -5419,6 +5420,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
+ case TemplateArgument::UncommonValue:
case TemplateArgument::NullPtr:
// We've already checked this template argument, so just copy
// it to the list of converted arguments.
@@ -5565,11 +5567,10 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
return true;
case TemplateArgument::Declaration:
- llvm_unreachable("Declaration argument with template template parameter");
case TemplateArgument::Integral:
- llvm_unreachable("Integral argument with template template parameter");
+ case TemplateArgument::UncommonValue:
case TemplateArgument::NullPtr:
- llvm_unreachable("Null pointer argument with template template parameter");
+ llvm_unreachable("non-type argument with template template parameter");
case TemplateArgument::Pack:
llvm_unreachable("Caller must expand template argument packs");
@@ -6936,37 +6937,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return ArgResult;
}
- // Convert the APValue to a TemplateArgument.
- switch (Value.getKind()) {
- case APValue::None:
- assert(ParamType->isNullPtrType());
- Converted = TemplateArgument(CanonParamType, /*isNullPtr*/true);
- break;
- case APValue::Indeterminate:
- llvm_unreachable("result of constant evaluation should be initialized");
- break;
- case APValue::Int:
- assert(ParamType->isIntegralOrEnumerationType());
- Converted = TemplateArgument(Context, Value.getInt(), CanonParamType);
- break;
- case APValue::MemberPointer: {
- assert(ParamType->isMemberPointerType());
-
- // FIXME: We need TemplateArgument representation and mangling for these.
- if (!Value.getMemberPointerPath().empty()) {
- Diag(Arg->getBeginLoc(),
- diag::err_template_arg_member_ptr_base_derived_not_supported)
- << Value.getMemberPointerDecl() << ParamType
- << Arg->getSourceRange();
- return ExprError();
- }
-
- auto *VD = const_cast<ValueDecl*>(Value.getMemberPointerDecl());
- Converted = VD ? TemplateArgument(VD, CanonParamType)
- : TemplateArgument(CanonParamType, /*isNullPtr*/true);
- break;
- }
- case APValue::LValue: {
+ // Prior to C++20, enforce restrictions on possible template argument
+ // values.
+ if (!getLangOpts().CPlusPlus20 && Value.isLValue()) {
// For a non-type template-parameter of pointer or reference type,
// the value of the constant expression shall not refer to
assert(ParamType->isPointerType() || ParamType->isReferenceType() ||
@@ -6982,8 +6955,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
<< Arg->getSourceRange();
return ExprError();
}
- // -- a subobject
- // FIXME: Until C++20
+ // -- a subobject [until C++20]
if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 &&
VD && VD->getType()->isArrayType() &&
Value.getLValuePath()[0].getAsArrayIndex() == 0 &&
@@ -7001,29 +6973,12 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
"null reference should not be a constant expression");
assert((!VD || !ParamType->isNullPtrType()) &&
"non-null value of type nullptr_t?");
- Converted = VD ? TemplateArgument(VD, CanonParamType)
- : TemplateArgument(CanonParamType, /*isNullPtr*/true);
- break;
}
- case APValue::Struct:
- case APValue::Union:
- // Get or create the corresponding template parameter object.
- Converted = TemplateArgument(
- Context.getTemplateParamObjectDecl(CanonParamType, Value),
- CanonParamType);
- break;
- case APValue::AddrLabelDiff:
+
+ if (Value.isAddrLabelDiff())
return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_
diff );
- case APValue::FixedPoint:
- case APValue::Float:
- case APValue::ComplexInt:
- case APValue::ComplexFloat:
- case APValue::Vector:
- case APValue::Array:
- return Diag(StartLoc, diag::err_non_type_template_arg_unsupported)
- << ParamType;
- }
+ Converted = TemplateArgument(Context, CanonParamType, Value);
return ArgResult.get();
}
@@ -7561,12 +7516,9 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
/// This routine takes care of the mapping from an integral template
/// argument (which may have any integral type) to the appropriate
/// literal value.
-ExprResult
-Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
- SourceLocation Loc) {
- assert(Arg.getKind() == TemplateArgument::Integral &&
- "Operation is only valid for integral template arguments");
- QualType OrigT = Arg.getIntegralType();
+static Expr *BuildExpressionFromIntegralTemplateArgumentValue(
+ Sema &S, QualType OrigT, const llvm::APSInt &Int, SourceLocation Loc) {
+ assert(OrigT->isIntegralOrEnumerationType());
// If this is an enum type that we're instantiating, we need to use an integer
// type the same size as the enumerator. We don't want to build an
@@ -7582,7 +7534,7 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
CharacterLiteral::CharacterKind Kind;
if (T->isWideCharType())
Kind = CharacterLiteral::Wide;
- else if (T->isChar8Type() && getLangOpts().Char8)
+ else if (T->isChar8Type() && S.getLangOpts().Char8)
Kind = CharacterLiteral::UTF8;
else if (T->isChar16Type())
Kind = CharacterLiteral::UTF16;
@@ -7591,29 +7543,131 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
else
Kind = CharacterLiteral::Ascii;
- E = new (Context) CharacterLiteral(Arg.getAsIntegral().getZExtValue(),
- Kind, T, Loc);
+ E = new (S.Context) CharacterLiteral(Int.getZExtValue(), Kind, T, Loc);
} else if (T->isBooleanType()) {
- E = new (Context) CXXBoolLiteralExpr(Arg.getAsIntegral().getBoolValue(),
- T, Loc);
- } else if (T->isNullPtrType()) {
- E = new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc);
+ E = new (S.Context) CXXBoolLiteralExpr(Int.getBoolValue(), T, Loc);
} else {
- E = IntegerLiteral::Create(Context, Arg.getAsIntegral(), T, Loc);
+ E = IntegerLiteral::Create(S.Context, Int, T, Loc);
}
if (OrigT->isEnumeralType()) {
// FIXME: This is a hack. We need a better way to handle substituted
// non-type template parameters.
- E = CStyleCastExpr::Create(Context, OrigT, VK_RValue, CK_IntegralCast, E,
- nullptr, CurFPFeatureOverrides(),
- Context.getTrivialTypeSourceInfo(OrigT, Loc),
+ E = CStyleCastExpr::Create(S.Context, OrigT, VK_RValue, CK_IntegralCast, E,
+ nullptr, S.CurFPFeatureOverrides(),
+ S.Context.getTrivialTypeSourceInfo(OrigT, Loc),
Loc, Loc);
}
return E;
}
+static Expr *BuildExpressionFromNonTypeTemplateArgumentValue(
+ Sema &S, QualType T, const APValue &Val, SourceLocation Loc) {
+ auto MakeInitList = [&] (ArrayRef<Expr*> Elts) -> Expr* {
+ auto *ILE = new (S.Context) InitListExpr(S.Context, Loc, Elts, Loc);
+ ILE->setType(T);
+ return ILE;
+ };
+
+ switch (Val.getKind()) {
+ case APValue::AddrLabelDiff:
+ // This cannot occur in a template argument at all.
+ case APValue::Array:
+ case APValue::Struct:
+ case APValue::Union:
+ // These can only occur within a template parameter object, which is
+ // represented as a TemplateArgument::Declaration.
+ llvm_unreachable("unexpected template argument value");
+
+ case APValue::Int:
+ return BuildExpressionFromIntegralTemplateArgumentValue(S, T, Val.getInt(),
+ Loc);
+
+ case APValue::Float:
+ return FloatingLiteral::Create(S.Context, Val.getFloat(), /*IsExact=*/true,
+ T, Loc);
+
+ case APValue::FixedPoint:
+ return FixedPointLiteral::CreateFromRawInt(
+ S.Context, Val.getFixedPoint().getValue(), T, Loc,
+ Val.getFixedPoint().getScale());
+
+ case APValue::ComplexInt: {
+ QualType ElemT = T->castAs<ComplexType>()->getElementType();
+ return MakeInitList({BuildExpressionFromIntegralTemplateArgumentValue(
+ S, ElemT, Val.getComplexIntReal(), Loc),
+ BuildExpressionFromIntegralTemplateArgumentValue(
+ S, ElemT, Val.getComplexIntImag(), Loc)});
+ }
+
+ case APValue::ComplexFloat: {
+ QualType ElemT = T->castAs<ComplexType>()->getElementType();
+ return MakeInitList(
+ {FloatingLiteral::Create(S.Context, Val.getComplexFloatReal(), true,
+ ElemT, Loc),
+ FloatingLiteral::Create(S.Context, Val.getComplexFloatImag(), true,
+ ElemT, Loc)});
+ }
+
+ case APValue::Vector: {
+ QualType ElemT = T->castAs<VectorType>()->getElementType();
+ llvm::SmallVector<Expr *, 8> Elts;
+ for (unsigned I = 0, N = Val.getVectorLength(); I != N; ++I)
+ Elts.push_back(BuildExpressionFromNonTypeTemplateArgumentValue(
+ S, ElemT, Val.getVectorElt(I), Loc));
+ return MakeInitList(Elts);
+ }
+
+ case APValue::None:
+ case APValue::Indeterminate:
+ // FIXME: Are these values possible?
+ case APValue::LValue:
+ case APValue::MemberPointer:
+ // There isn't necessarily a valid equivalent source-level syntax for
+ // these; in particular, a naive lowering might violate access control.
+ // So for now we lower to a ConstantExpr holding the value, wrapped around
+ // an OpaqueValueExpr.
+ // FIXME: We should have a better representation for this.
+ ExprValueKind VK = VK_RValue;
+ if (T->isReferenceType()) {
+ T = T->getPointeeType();
+ VK = VK_LValue;
+ }
+ auto *OVE = new (S.Context) OpaqueValueExpr(Loc, T, VK);
+ return ConstantExpr::Create(S.Context, OVE, Val);
+ }
+}
+
+ExprResult
+Sema::BuildExpressionFromNonTypeTemplateArgument(const TemplateArgument &Arg,
+ SourceLocation Loc) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ case TemplateArgument::Type:
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion:
+ case TemplateArgument::Pack:
+ llvm_unreachable("not a non-type template argument");
+
+ case TemplateArgument::Expression:
+ return Arg.getAsExpr();
+
+ case TemplateArgument::NullPtr:
+ case TemplateArgument::Declaration:
+ return BuildExpressionFromDeclTemplateArgument(
+ Arg, Arg.getNonTypeTemplateArgumentType(), Loc);
+
+ case TemplateArgument::Integral:
+ return BuildExpressionFromIntegralTemplateArgumentValue(
+ *this, Arg.getIntegralType(), Arg.getAsIntegral(), Loc);
+
+ case TemplateArgument::UncommonValue:
+ return BuildExpressionFromNonTypeTemplateArgumentValue(
+ *this, Arg.getUncommonValueType(), Arg.getAsUncommonValue(), Loc);
+ }
+}
+
/// Match two template parameters within template parameter lists.
static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old,
bool Complain,
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 4a3b64cf5425..23d4056ce254 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -276,6 +276,16 @@ checkDeducedTemplateArguments(ASTContext &Context,
// All other combinations are incompatible.
return DeducedTemplateArgument();
+ case TemplateArgument::UncommonValue:
+ // If we deduced a value and a dependent expression, keep the value.
+ if (Y.getKind() == TemplateArgument::Expression ||
+ (Y.getKind() == TemplateArgument::UncommonValue &&
+ X.structurallyEquals(Y)))
+ return X;
+
+ // All other combinations are incompatible.
+ return DeducedTemplateArgument();
+
case TemplateArgument::Template:
if (Y.getKind() == TemplateArgument::Template &&
Context.hasSameTemplateName(X.getAsTemplate(), Y.getAsTemplate()))
@@ -2361,20 +2371,18 @@ DeduceTemplateArguments(Sema &S,
return Sema::TDK_NonDeducedMismatch;
case TemplateArgument::Integral:
- if (Arg.getKind() == TemplateArgument::Integral) {
- if (hasSameExtendedValue(Param.getAsIntegral(), Arg.getAsIntegral()))
- return Sema::TDK_Success;
+ if (Arg.getKind() == TemplateArgument::Integral &&
+ hasSameExtendedValue(Param.getAsIntegral(), Arg.getAsIntegral()))
+ return Sema::TDK_Success;
- Info.FirstArg = Param;
- Info.SecondArg = Arg;
- return Sema::TDK_NonDeducedMismatch;
- }
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
- if (Arg.getKind() == TemplateArgument::Expression) {
- Info.FirstArg = Param;
- Info.SecondArg = Arg;
- return Sema::TDK_NonDeducedMismatch;
- }
+ case TemplateArgument::UncommonValue:
+ if (Arg.getKind() == TemplateArgument::UncommonValue &&
+ Arg.structurallyEquals(Param))
+ return Sema::TDK_Success;
Info.FirstArg = Param;
Info.SecondArg = Arg;
@@ -2383,28 +2391,34 @@ DeduceTemplateArguments(Sema &S,
case TemplateArgument::Expression:
if (const NonTypeTemplateParmDecl *NTTP =
getDeducedParameterFromExpr(Info, Param.getAsExpr())) {
- if (Arg.getKind() == TemplateArgument::Integral)
- return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
- Arg.getAsIntegral(),
- Arg.getIntegralType(),
- /*ArrayBound=*/false,
- Info, Deduced);
- if (Arg.getKind() == TemplateArgument::NullPtr)
- return DeduceNullPtrTemplateArgument(S, TemplateParams, NTTP,
- Arg.getNullPtrType(),
- Info, Deduced);
- if (Arg.getKind() == TemplateArgument::Expression)
- return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
- Arg.getAsExpr(), Info, Deduced);
- if (Arg.getKind() == TemplateArgument::Declaration)
- return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP,
- Arg.getAsDecl(),
- Arg.getParamTypeForDecl(),
- Info, Deduced);
+ switch (Arg.getKind()) {
+ case TemplateArgument::Integral:
+ case TemplateArgument::Expression:
+ case TemplateArgument::UncommonValue:
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, DeducedTemplateArgument(Arg),
+ Arg.getNonTypeTemplateArgumentType(), Info, Deduced);
- Info.FirstArg = Param;
- Info.SecondArg = Arg;
- return Sema::TDK_NonDeducedMismatch;
+ case TemplateArgument::NullPtr:
+ return DeduceNullPtrTemplateArgument(
+ S, TemplateParams, NTTP, Arg.getNullPtrType(), Info, Deduced);
+
+
+ case TemplateArgument::Declaration:
+ return DeduceNonTypeTemplateArgument(
+ S, TemplateParams, NTTP, Arg.getAsDecl(), Arg.getParamTypeForDecl(),
+ Info, Deduced);
+
+ case TemplateArgument::Null:
+ case TemplateArgument::Type:
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion:
+ case TemplateArgument::Pack:
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
+ }
+ llvm_unreachable("Unknown template argument kind");
}
// Can't deduce anything, but that's okay.
@@ -2592,6 +2606,9 @@ static bool isSameTemplateArg(ASTContext &Context,
case TemplateArgument::Integral:
return hasSameExtendedValue(X.getAsIntegral(), Y.getAsIntegral());
+ case TemplateArgument::UncommonValue:
+ return X.structurallyEquals(Y);
+
case TemplateArgument::Expression: {
llvm::FoldingSetNodeID XID, YID;
X.getAsExpr()->Profile(XID, Context, true);
@@ -2657,9 +2674,9 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
E);
}
- case TemplateArgument::Integral: {
- Expr *E =
- BuildExpressionFromIntegralTemplateArgument(Arg, Loc).getAs<Expr>();
+ case TemplateArgument::Integral:
+ case TemplateArgument::UncommonValue: {
+ Expr *E = BuildExpressionFromNonTypeTemplateArgument(Arg, Loc).get();
return TemplateArgumentLoc(TemplateArgument(E), E);
}
@@ -6103,11 +6120,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
- break;
-
case TemplateArgument::NullPtr:
- MarkUsedTemplateParameters(Ctx, TemplateArg.getNullPtrType(), OnlyDeduced,
- Depth, Used);
+ case TemplateArgument::UncommonValue:
break;
case TemplateArgument::Type:
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index cbf4fb1de465..d04ae36360a6 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1556,16 +1556,18 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
VD = nullptr;
}
- QualType paramType = VD ? arg.getParamTypeForDecl() : arg.getNullPtrType();
+ QualType paramType = arg.getNonTypeTemplateArgumentType();
assert(!paramType.isNull() && "type substitution failed for param type");
assert(!paramType->isDependentType() && "param type still dependent");
result = SemaRef.BuildExpressionFromDeclTemplateArgument(arg, paramType, loc);
refParam = paramType->isReferenceType();
} else {
- result = SemaRef.BuildExpressionFromIntegralTemplateArgument(arg, loc);
+ QualType paramType = arg.getNonTypeTemplateArgumentType();
+ result = SemaRef.BuildExpressionFromNonTypeTemplateArgument(arg, loc);
+ refParam = paramType->isReferenceType();
assert(result.isInvalid() ||
SemaRef.Context.hasSameType(result.get()->getType(),
- arg.getIntegralType()));
+ paramType.getNonReferenceType()));
}
if (result.isInvalid())
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 1951aec3d17d..3c6365a075f4 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -1103,6 +1103,7 @@ Sema::getTemplateArgumentPackExpansionPattern(
case TemplateArgument::NullPtr:
case TemplateArgument::Template:
case TemplateArgument::Integral:
+ case TemplateArgument::UncommonValue:
case TemplateArgument::Pack:
case TemplateArgument::Null:
return TemplateArgumentLoc();
@@ -1153,6 +1154,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
case TemplateArgument::NullPtr:
case TemplateArgument::TemplateExpansion:
case TemplateArgument::Integral:
+ case TemplateArgument::UncommonValue:
case TemplateArgument::Pack:
case TemplateArgument::Null:
return None;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 2cc8b9c8324f..1695e26c7d5f 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -3557,6 +3557,7 @@ class TreeTransform {
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
+ case TemplateArgument::UncommonValue:
case TemplateArgument::Pack:
case TemplateArgument::TemplateExpansion:
case TemplateArgument::NullPtr:
@@ -4229,7 +4230,8 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
case TemplateArgument::Integral:
case TemplateArgument::NullPtr:
- case TemplateArgument::Declaration: {
+ case TemplateArgument::Declaration:
+ case TemplateArgument::UncommonValue: {
// Transform a resolved template argument straight to a resolved template
// argument. We get here when substituting into an already-substituted
// template type argument during concept satisfaction checking.
@@ -4256,9 +4258,15 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
else if (Arg.getKind() == TemplateArgument::NullPtr)
Output = TemplateArgumentLoc(TemplateArgument(NewT, /*IsNullPtr=*/true),
TemplateArgumentLocInfo());
- else
+ else if (Arg.getKind() == TemplateArgument::Declaration)
Output = TemplateArgumentLoc(TemplateArgument(NewD, NewT),
TemplateArgumentLocInfo());
+ else if (Arg.getKind() == TemplateArgument::UncommonValue)
+ Output = TemplateArgumentLoc(
+ TemplateArgument(getSema().Context, NewT, Arg.getAsUncommonValue()),
+ TemplateArgumentLocInfo());
+ else
+ llvm_unreachable("unexpected template argument kind");
return false;
}
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index b48b23ce4a51..22533527fc61 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -7100,6 +7100,7 @@ ASTRecordReader::readTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind) {
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
case TemplateArgument::NullPtr:
+ case TemplateArgument::UncommonValue:
case TemplateArgument::Pack:
// FIXME: Is this right?
return TemplateArgumentLocInfo();
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 3a281e492fde..87160b26d421 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -5350,6 +5350,7 @@ void ASTRecordWriter::AddTemplateArgumentLocInfo(
case TemplateArgument::Integral:
case TemplateArgument::Declaration:
case TemplateArgument::NullPtr:
+ case TemplateArgument::UncommonValue:
case TemplateArgument::Pack:
// FIXME: Is this right?
break;
diff --git a/clang/test/CodeGenCXX/mangle-ms-templates.cpp b/clang/test/CodeGenCXX/mangle-ms-templates.cpp
index 7402d367ae3e..c9149a473b6f 100644
--- a/clang/test/CodeGenCXX/mangle-ms-templates.cpp
+++ b/clang/test/CodeGenCXX/mangle-ms-templates.cpp
@@ -2,6 +2,7 @@
// RUN: %clang_cc1 -std=c++11 -fms-compatibility-version=19 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-win32 | FileCheck -check-prefix X64 %s
// RUN: %clang_cc1 -std=c++17 -fms-compatibility-version=19 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=i386-pc-win32 | FileCheck %s
// RUN: %clang_cc1 -std=c++17 -fms-compatibility-version=19 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-win32 | FileCheck -check-prefix X64 %s
+// RUN: %clang_cc1 -std=c++20 -fms-compatibility-version=19 -emit-llvm %s -o - -fms-extensions -fdelayed-template-parsing -triple=x86_64-pc-win32 | FileCheck -check-prefix CXX20-X64 %s
template<typename T>
class Class {
@@ -327,3 +328,12 @@ void fun_uint128(UInt128<(unsigned __int128)-1>) {}
// X64: define {{.*}} @"?fun_uint128@@YAXU?$UInt128@$0DPPPPPPPPPPPPPPPAAAAAAAAAAAAAAAB@@@@Z"(
void fun_uint128(UInt128<(unsigned __int128)9223372036854775807 * (unsigned __int128)9223372036854775807>) {}
#endif
+
+#if __cplusplus >= 202002L
+template<float> struct Float {};
+// CXX20-X64: define {{.*}} @"?f@@YAXU?$Float@$ADPIAAAAA@@@@Z"(
+void f(Float<1.0f>) {}
+template<auto> struct Auto {};
+// CXX20-X64: define {{.*}} @"?f@@YAXU?$Auto@$MMADPIAAAAA@@@@Z"(
+void f(Auto<1.0f>) {}
+#endif
diff --git a/clang/test/CodeGenCXX/mangle-template.cpp b/clang/test/CodeGenCXX/mangle-template.cpp
index 40688de7e12e..8326bf658f06 100644
--- a/clang/test/CodeGenCXX/mangle-template.cpp
+++ b/clang/test/CodeGenCXX/mangle-template.cpp
@@ -226,6 +226,16 @@ namespace test16 {
namespace cxx20 {
template<auto> struct A {};
template<typename T, T V> struct B {};
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AILf3f800000EEE(
+ void f(A<1.0f>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AILd3ff0000000000000EEE(
+ void f(A<1.0>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AILe3fff8000000000000000EEE(
+ void f(A<1.0l>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXtlCiLi0ELi1EEEEE(
+ void f(A<1i>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXtlCdLd0000000000000000ELd3ff0000000000000EEEEE(
+ void f(A<1.0i>) {}
int x;
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadL_ZNS_1xEEEEE(
@@ -245,7 +255,24 @@ namespace cxx20 {
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPKvXadL_ZNS_1xEEEEE(
void f(B<const void*, (const void*)&x>) {}
- struct Q { int x; };
+ struct Q { int x; } q;
+
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadsoiL_ZNS_1qEEEEEE(
+ void f(A<&q.x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPiXadsoiL_ZNS_1qEEEEEE(
+ void f(B<int*, &q.x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadsoKiL_ZNS_1qEEEEEE(
+ void f(A<(const int*)&q.x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPKiXadsoS1_L_ZNS_1qEEEEEE
+ void f(B<const int*, (const int*)&q.x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPvadsoiL_ZNS_1qEEEEEE(
+ void f(A<(void*)&q.x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPvXadsoiL_ZNS_1qEEEEEE(
+ void f(B<void*, (void*)&q.x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXcvPKvadsoiL_ZNS_1qEEEEEE(
+ void f(A<(const void*)&q.x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIPKvXadsoiL_ZNS_1qEEEEEE(
+ void f(B<const void*, (const void*)&q.x>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXadL_ZNS_1Q1xEEEEE(
void f(A<&Q::x>) {}
@@ -255,6 +282,17 @@ namespace cxx20 {
void f(A<(const int Q::*)&Q::x>) {}
// CXX20: define {{.*}} @_ZN5cxx201fENS_1BIMNS_1QEKiXadL_ZNS1_1xEEEEE(
void f(B<const int Q::*, (const int Q::*)&Q::x>) {}
+
+ struct R : Q {};
+
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXmcMNS_1REiadL_ZNS_1Q1xEEEEEE(
+ void f(A<(int R::*)&Q::x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIMNS_1REiXmcS2_adL_ZNS_1Q1xEEEEEE(
+ void f(B<int R::*, (int R::*)&Q::x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1AIXmcMNS_1REKiadL_ZNS_1Q1xEEEEEE(
+ void f(A<(const int R::*)&Q::x>) {}
+ // CXX20: define {{.*}} @_ZN5cxx201fENS_1BIMNS_1REKiXmcS3_adL_ZNS_1Q1xEEEEEE(
+ void f(B<const int R::*, (const int R::*)&Q::x>) {}
}
#endif
diff --git a/clang/test/CodeGenCXX/template-arguments.cpp b/clang/test/CodeGenCXX/template-arguments.cpp
new file mode 100644
index 000000000000..fd6f469e88fc
--- /dev/null
+++ b/clang/test/CodeGenCXX/template-arguments.cpp
@@ -0,0 +1,81 @@
+// RUN: %clang_cc1 -std=c++20 %s -emit-llvm -o - -triple x86_64-linux -DCONSTEXPR= | FileCheck %s
+// RUN: %clang_cc1 -std=c++20 %s -emit-llvm -o - -triple x86_64-linux -DCONSTEXPR=constexpr | FileCheck %s --check-prefix=CONST
+
+template<typename T> CONSTEXPR T id(T v) { return v; }
+template<auto V> auto value = id(V);
+
+// CHECK: call {{.*}} @_Z2idIiET_S0_(i32 1)
+// CONST: @_Z5valueILi1EE = weak_odr {{.*}} i32 1,
+template int value<1>;
+
+// CHECK: call {{.*}} @_Z2idIyET_S0_(i64 -1)
+// CONST: @_Z5valueILy18446744073709551615EE = weak_odr {{.*}} i64 -1,
+template unsigned long long value<-1ULL>;
+
+// CHECK: call {{.*}} @_Z2idIfET_S0_(float 1.000000e+00)
+// CONST: @_Z5valueILf3f800000EE = weak_odr {{.*}} float 1.000000e+00,
+template float value<1.0f>;
+// CHECK: call {{.*}} @_Z2idIdET_S0_(double 1.000000e+00)
+// CONST: @_Z5valueILd3ff0000000000000EE = weak_odr {{.*}} double 1.000000e+00,
+template double value<1.0>;
+
+int n;
+// CHECK: call {{.*}} @_Z2idIPiET_S1_(i32* @n)
+// CONST: @_Z5valueIXadL_Z1nEEE = weak_odr {{.*}} i32* @n,
+template int *value<&n>;
+
+struct A { int a[3]; } a;
+// CHECK: call {{.*}} @_Z2idIPiET_S1_(i32* getelementptr inbounds (%struct.A, %struct.A* @a, i32 0, i32 0, i32 0))
+// CONST: @_Z5valueIXadsoiL_Z1aEEEE = weak_odr {{.*}} i32* getelementptr inbounds (%struct.A, %struct.A* @a, i32 0, i32 0, i32 0),
+template int *value<&a.a[0]>;
+// CHECK: call {{.*}} @_Z2idIPiET_S1_(i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.A* @a to i8*), i64 4) to i32*))
+// CONST: @_Z5valueIXadsoiL_Z1aE4EEE = weak_odr {{.*}} i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.A* @a to i8*), i64 4) to i32*),
+template int *value<&a.a[1]>;
+// CHECK: call {{.*}} @_Z2idIPiET_S1_(i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.A* @a to i8*), i64 8) to i32*))
+// CONST: @_Z5valueIXadsoiL_Z1aE8EEE = weak_odr {{.*}} i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.A* @a to i8*), i64 8) to i32*),
+template int *value<&a.a[2]>;
+// CHECK: call {{.*}} @_Z2idIPiET_S1_(i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.A* @a to i8*), i64 12) to i32*))
+// CONST: @_Z5valueIXadsoiL_Z1aE12pEEE = weak_odr {{.*}} i32* bitcast (i8* getelementptr (i8, i8* bitcast (%struct.A* @a to i8*), i64 12) to i32*),
+template int *value<&a.a[3]>;
+
+struct B { int x, y; };
+// CHECK: call {{.*}} @_Z2idIM1BiET_S2_(i64 0)
+// CONST: @_Z5valueIXadL_ZN1B1xEEEE = weak_odr {{.*}} i64 0,
+template int B::*value<&B::x>;
+// CHECK: call {{.*}} @_Z2idIM1BiET_S2_(i64 4)
+// CONST: @_Z5valueIXadL_ZN1B1yEEEE = weak_odr {{.*}} i64 4,
+template int B::*value<&B::y>;
+
+struct C : A, B { int z; };
+// CHECK: call {{.*}} @_Z2idIM1CiET_S2_(i64 12)
+// CONST: @_Z5valueIXmcM1CiadL_ZN1B1xEE12EEE = weak_odr {{.*}} i64 12,
+template int C::*value<(int C::*)&B::x>;
+// CHECK: call {{.*}} @_Z2idIM1BiET_S2_(i64 8)
+// CONST: @_Z5valueIXmcM1BiadL_ZN1C1zEEn12EEE = weak_odr {{.*}} i64 8,
+template int B::*value<(int B::*)&C::z>;
+
+// CHECK: store i32 1, i32*
+// CHECK: store i32 2, i32*
+// CHECK: bitcast { i32, i32 }* %{{.*}} to i64*
+// CHECK: load i64,
+// CHECK: call {{.*}} @_Z2idICiET_S1_(i64 %
+// CONST: @_Z5valueIXtlCiLi1ELi2EEEE = weak_odr {{.*}} { i32, i32 } { i32 1, i32 2 },
+template _Complex int value<1 + 2j>;
+
+// CHECK: store float 1.000000e+00, float*
+// CHECK: store float 2.000000e+00, float*
+// CHECK: bitcast { float, float }* %{{.*}} to <2 x float>*
+// CHECK: load <2 x float>,
+// CHECK: call {{.*}} @_Z2idICfET_S1_(<2 x float> %
+// CONST: @_Z5valueIXtlCfLf3f800000ELf40000000EEEE = weak_odr {{.*}} { float, float } { float 1.000000e+00, float 2.000000e+00 },
+template _Complex float value<1.0f + 2.0fj>;
+
+using V3i __attribute__((ext_vector_type(3))) = int;
+// CHECK: call {{.*}} @_Z2idIDv3_iET_S1_(<3 x i32> <i32 1, i32 2, i32 3>)
+// CONST: @_Z5valueIXtlDv3_iLi1ELi2ELi3EEEE = weak_odr {{.*}} <3 x i32> <i32 1, i32 2, i32 3>
+template V3i value<V3i{1, 2, 3}>;
+
+using V3f [[gnu::vector_size(12)]] = float;
+// CHECK: call {{.*}} @_Z2idIDv3_fET_S1_(<3 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00>)
+// CONST: @_Z5valueIXtlDv3_fLf3f800000ELf40000000ELf40400000EEEE = weak_odr {{.*}} <3 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00>
+template V3f value<V3f{1, 2, 3}>;
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx17.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx17.cpp
index 52cf51719f05..bc8a22e89041 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx17.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx17.cpp
@@ -2,7 +2,7 @@
template<typename T, T val> struct A {};
-template<typename T, typename U> constexpr bool is_same = false; // expected-note +{{here}}
+template<typename T, typename U> constexpr bool is_same = false;
template<typename T> constexpr bool is_same<T, T> = true;
namespace String {
@@ -84,34 +84,32 @@ namespace PtrMem {
constexpr int B::*b = &B::b;
constexpr int C::*cb = b;
constexpr int D::*db = b;
- constexpr int E::*ecb = cb; // expected-note +{{here}}
- constexpr int E::*edb = db; // expected-note +{{here}}
+ constexpr int E::*ecb = cb;
+ constexpr int E::*edb = db;
constexpr int E::*e = &E::e;
constexpr int D::*de = (int D::*)e;
constexpr int C::*ce = (int C::*)e;
- constexpr int B::*bde = (int B::*)de; // expected-note +{{here}}
- constexpr int B::*bce = (int B::*)ce; // expected-note +{{here}}
+ constexpr int B::*bde = (int B::*)de;
+ constexpr int B::*bce = (int B::*)ce;
- // FIXME: This should all be accepted, but we don't yet have a representation
- // nor mangling for this form of template argument.
using Ab = A<int B::*, b>;
using Ab = A<int B::*, &B::b>;
- using Abce = A<int B::*, bce>; // expected-error {{not supported}}
- using Abde = A<int B::*, bde>; // expected-error {{not supported}}
- static_assert(!is_same<Ab, Abce>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
- static_assert(!is_same<Ab, Abde>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
- static_assert(!is_same<Abce, Abde>, ""); // expected-error 2{{undeclared}} expected-error {{must be a type}}
- static_assert(is_same<Abce, A<int B::*, (int B::*)(int C::*)&E::e>>, ""); // expected-error {{undeclared}} expected-error {{not supported}}
+ using Abce = A<int B::*, bce>;
+ using Abde = A<int B::*, bde>;
+ static_assert(!is_same<Ab, Abce>, "");
+ static_assert(!is_same<Ab, Abde>, "");
+ static_assert(!is_same<Abce, Abde>, "");
+ static_assert(is_same<Abce, A<int B::*, (int B::*)(int C::*)&E::e>>, "");
using Ae = A<int E::*, e>;
using Ae = A<int E::*, &E::e>;
- using Aecb = A<int E::*, ecb>; // expected-error {{not supported}}
- using Aedb = A<int E::*, edb>; // expected-error {{not supported}}
- static_assert(!is_same<Ae, Aecb>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
- static_assert(!is_same<Ae, Aedb>, ""); // expected-error {{undeclared}} expected-error {{must be a type}}
- static_assert(!is_same<Aecb, Aedb>, ""); // expected-error 2{{undeclared}} expected-error {{must be a type}}
- static_assert(is_same<Aecb, A<int E::*, (int E::*)(int C::*)&B::b>>, ""); // expected-error {{undeclared}} expected-error {{not supported}}
+ using Aecb = A<int E::*, ecb>;
+ using Aedb = A<int E::*, edb>;
+ static_assert(!is_same<Ae, Aecb>, "");
+ static_assert(!is_same<Ae, Aedb>, "");
+ static_assert(!is_same<Aecb, Aedb>, "");
+ static_assert(is_same<Aecb, A<int E::*, (int E::*)(int C::*)&B::b>>, "");
using An = A<int E::*, nullptr>;
using A0 = A<int E::*, (int E::*)0>;
@@ -205,9 +203,9 @@ namespace Auto {
struct Y : X {};
void type_affects_identity(B<&X::n>) {}
- void type_affects_identity(B<(int Y::*)&X::n>) {} // FIXME: expected-error {{sorry}}
+ void type_affects_identity(B<(int Y::*)&X::n>) {}
void type_affects_identity(B<(const int X::*)&X::n>) {}
- void type_affects_identity(B<(const int Y::*)&X::n>) {} // FIXME: expected-error {{sorry}}
+ void type_affects_identity(B<(const int Y::*)&X::n>) {}
// A case where we need to do auto-deduction, and check whether the
// resulting dependent types match during partial ordering. These
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
index d514465f7d67..48101cccfce0 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
@@ -8,8 +8,8 @@ namespace std {
// floating-point arguments
template<float> struct Float {};
-using F1 = Float<1.0f>; // FIXME expected-error {{sorry}}
-using F1 = Float<2.0f / 2>; // FIXME expected-error {{sorry}}
+using F1 = Float<1.0f>;
+using F1 = Float<2.0f / 2>;
struct S { int n[3]; } s; // expected-note 1+{{here}}
union U { int a, b; } u;
@@ -17,24 +17,24 @@ int n; // expected-note 1+{{here}}
// pointers to subobjects
template<int *> struct IntPtr {};
-using IPn = IntPtr<&n + 1>; // FIXME expected-error {{refers to subobject}}
-using IPn = IntPtr<&n + 1>; // FIXME expected-error {{refers to subobject}}
+using IPn = IntPtr<&n + 1>;
+using IPn = IntPtr<&n + 1>;
-using IP2 = IntPtr<&s.n[2]>; // FIXME expected-error {{refers to subobject}}
-using IP2 = IntPtr<s.n + 2>; // FIXME expected-error {{refers to subobject}}
+using IP2 = IntPtr<&s.n[2]>;
+using IP2 = IntPtr<s.n + 2>;
-using IP3 = IntPtr<&s.n[3]>; // FIXME expected-error {{refers to subobject}}
-using IP3 = IntPtr<s.n + 3>; // FIXME expected-error {{refers to subobject}}
+using IP3 = IntPtr<&s.n[3]>;
+using IP3 = IntPtr<s.n + 3>;
template<int &> struct IntRef {};
-using IPn = IntRef<*(&n + 1)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of 'n'}}
-using IPn = IntRef<*(&n + 1)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of 'n'}}
+using IRn = IntRef<*(&n + 1)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of 'n'}}
+using IRn = IntRef<*(&n + 1)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of 'n'}}
-using IP2 = IntRef<s.n[2]>; // FIXME expected-error {{refers to subobject}}
-using IP2 = IntRef<*(s.n + 2)>; // FIXME expected-error {{refers to subobject}}
+using IR2 = IntRef<s.n[2]>;
+using IR2 = IntRef<*(s.n + 2)>;
-using IP3 = IntRef<s.n[3]>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of subobject of 's'}}
-using IP3 = IntRef<*(s.n + 3)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of subobject of 's'}}
+using IR3 = IntRef<s.n[3]>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of subobject of 's'}}
+using IR3 = IntRef<*(s.n + 3)>; // expected-error {{not a constant expression}} expected-note {{dereferenced pointer past the end of subobject of 's'}}
// classes
template<S> struct Struct {};
@@ -48,12 +48,12 @@ using U1 = Union<U{.b = 1}>; // expected-error {{
diff erent types}}
// miscellaneous scalar types
template<_Complex int> struct ComplexInt {};
-using CI = ComplexInt<1 + 3i>; // FIXME: expected-error {{sorry}}
-using CI = ComplexInt<1 + 3i>; // FIXME: expected-error {{sorry}}
+using CI = ComplexInt<1 + 3i>;
+using CI = ComplexInt<3i + 1>;
template<_Complex float> struct ComplexFloat {};
-using CF = ComplexFloat<1.0f + 3.0fi>; // FIXME: expected-error {{sorry}}
-using CF = ComplexFloat<1.0f + 3.0fi>; // FIXME: expected-error {{sorry}}
+using CF = ComplexFloat<1.0f + 3.0fi>;
+using CF = ComplexFloat<3.0fi + 1.0f>;
namespace ClassNTTP {
struct A { // expected-note 2{{candidate}}
@@ -307,11 +307,11 @@ namespace dependent {
if constexpr (N < 10)
return R<n>();
else if constexpr (N < 20)
- return R<vn.v>(); // FIXME: expected-error 2{{refers to subobject}}
+ return R<vn.v>();
else if constexpr (N < 30)
return S<&n>();
else if constexpr (N < 40)
- return S<&vn.v>(); // FIXME: expected-error 2{{refers to subobject}}
+ return S<&vn.v>();
else if constexpr (N < 50)
return T<V<int&>{n}>();
else if constexpr (N < 60)
@@ -322,15 +322,15 @@ namespace dependent {
return T<V<int*>{&vn.v}>();
}
template<int Base> void check() {
- auto v = f<Base + 0>(); // FIXME: expected-note 2{{instantiation of}}
- auto w = f<Base + 1>(); // FIXME: expected-note 2{{instantiation of}}
+ auto v = f<Base + 0>();
+ auto w = f<Base + 1>();
static_assert(!__is_same(decltype(v), decltype(w)));
static_assert(v != w);
}
template void check<0>();
- template void check<10>(); // FIXME: expected-note 2{{instantiation of}}
+ template void check<10>();
template void check<20>();
- template void check<30>(); // FIXME: expected-note 2{{instantiation of}}
+ template void check<30>();
template void check<40>();
template void check<50>();
template void check<60>();
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index f1008319ddc7..8a4d3cbcf939 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -1493,6 +1493,11 @@ bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) {
return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
return false;
+ case TemplateArgument::UncommonValue:
+ if (Expr *E = TAL.getSourceUncommonValueExpression())
+ return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
+ return false;
+
case TemplateArgument::NullPtr:
if (Expr *E = TAL.getSourceNullPtrExpression())
return Visit(MakeCXCursor(E, StmtParent, TU, RegionOfInterest));
diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index 180cf1858d04..851b418b6d7b 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -1375,6 +1375,9 @@ enum CXTemplateArgumentKind clang_Cursor_getTemplateArgumentKind(CXCursor C,
return CXTemplateArgumentKind_NullPtr;
case TemplateArgument::Integral:
return CXTemplateArgumentKind_Integral;
+ case TemplateArgument::UncommonValue:
+ // FIXME: Expose these values.
+ return CXTemplateArgumentKind_Invalid;
case TemplateArgument::Template:
return CXTemplateArgumentKind_Template;
case TemplateArgument::TemplateExpansion:
More information about the llvm-branch-commits
mailing list