From dcee98048d5147502da2b224f01d08f24aec2293 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 8 Feb 2010 23:41:45 +0000 Subject: [PATCH] When substituting a declaration non-type template argument for a non-type template parameter that has reference type, augment the qualifiers of the non-type template argument with those of the referenced type. Fixes PR6250. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95607 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaTemplateInstantiate.cpp | 22 ++++++++++++------- .../CXX/temp/temp.arg/temp.arg.nontype/p5.cpp | 16 ++++++++++++++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index c8cc9dc98f..99c1de6198 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -701,7 +701,7 @@ TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { Sema::OwningExprResult TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, - NonTypeTemplateParmDecl *NTTP) { + NonTypeTemplateParmDecl *NTTP) { // If the corresponding template argument is NULL or non-existent, it's // because we are performing instantiation from explicitly-specified // template arguments in a function template, but there were some @@ -731,7 +731,8 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, // Derive the type we want the substituted decl to have. This had // better be non-dependent, or these checks will have serious problems. QualType TargetType = SemaRef.SubstType(NTTP->getType(), TemplateArgs, - E->getLocation(), DeclarationName()); + E->getLocation(), + DeclarationName()); assert(!TargetType.isNull() && "type substitution failed for param type"); assert(!TargetType->isDependentType() && "param type still dependent"); @@ -769,6 +770,8 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, } } + QualType T = VD->getType().getNonReferenceType(); + if (TargetType->isPointerType()) { // C++03 [temp.arg.nontype]p5: // - For a non-type template-parameter of type pointer to @@ -779,8 +782,7 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, // applied. OwningExprResult RefExpr - = SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), - E->getLocation()); + = SemaRef.BuildDeclRefExpr(VD, T, E->getLocation()); if (RefExpr.isInvalid()) return SemaRef.ExprError(); @@ -799,10 +801,14 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, return SemaRef.Owned(RefE); } - // FIXME: template parameters can add qualifiers to a reference. - - return SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), - E->getLocation()); + // If the non-type template parameter has reference type, qualify the + // resulting declaration reference with the extra qualifiers on the + // type that the reference refers to. + if (const ReferenceType *TargetRef = TargetType->getAs()) + T = SemaRef.Context.getQualifiedType(T, + TargetRef->getPointeeType().getQualifiers()); + + return SemaRef.BuildDeclRefExpr(VD, T, E->getLocation()); } assert(Arg.getKind() == TemplateArgument::Integral); diff --git a/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp b/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp index f74e78f746..458aff2f02 100644 --- a/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp +++ b/test/CXX/temp/temp.arg/temp.arg.nontype/p5.cpp @@ -89,6 +89,22 @@ namespace reference_parameters { S3 s3v; S3 s3cv; } + + namespace PR6250 { + template void inc() { + ref++; // expected-error{{read-only variable is not assignable}} + } + + template void bind() { + T &ref2 = ref; // expected-error{{drops qualifiers}} + } + + int counter; + void test() { + inc(); // expected-note{{instantiation of}} + bind(); // expected-note{{instantiation of}} + } + } } // -- For a non-type template-parameter of type pointer to function, the -- 2.40.0