From: Richard Smith Date: Thu, 14 Dec 2017 15:40:16 +0000 (+0000) Subject: When attempting to complete an incomplete array bound type in an expression, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b007293d31c4fbcd73592302a948fb3bac5d36a7;p=clang When attempting to complete an incomplete array bound type in an expression, update the type from the definition even if we didn't instantiate a definition. We may have instantiated the definition in an earlier stage of semantic analysis, after creating the DeclRefExpr but before we reach a point where a complete expression type is required. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@320709 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 2d8094b991..2fffe8e179 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -7268,27 +7268,29 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, void Sema::completeExprArrayBound(Expr *E) { if (DeclRefExpr *DRE = dyn_cast(E->IgnoreParens())) { if (VarDecl *Var = dyn_cast(DRE->getDecl())) { - if (isTemplateInstantiation(Var->getTemplateSpecializationKind()) && - !Var->getDefinition()) { - SourceLocation PointOfInstantiation = E->getExprLoc(); - InstantiateVariableDefinition(PointOfInstantiation, Var); + if (isTemplateInstantiation(Var->getTemplateSpecializationKind())) { auto *Def = Var->getDefinition(); - - // If we don't already have a point of instantiation, and we managed to - // instantiate a definition, this is the point of instantiation. - // Otherwise, we don't request an end-of-TU instantiation, so this is - // not a point of instantiation. - // FIXME: Is this really the right behavior? - if (Var->getPointOfInstantiation().isInvalid() && Def) { - assert(Var->getTemplateSpecializationKind() == - TSK_ImplicitInstantiation && - "explicit instantiation with no point of instantiation"); - Var->setTemplateSpecializationKind( - Var->getTemplateSpecializationKind(), PointOfInstantiation); + if (!Def) { + SourceLocation PointOfInstantiation = E->getExprLoc(); + InstantiateVariableDefinition(PointOfInstantiation, Var); + Def = Var->getDefinition(); + + // If we don't already have a point of instantiation, and we managed + // to instantiate a definition, this is the point of instantiation. + // Otherwise, we don't request an end-of-TU instantiation, so this is + // not a point of instantiation. + // FIXME: Is this really the right behavior? + if (Var->getPointOfInstantiation().isInvalid() && Def) { + assert(Var->getTemplateSpecializationKind() == + TSK_ImplicitInstantiation && + "explicit instantiation with no point of instantiation"); + Var->setTemplateSpecializationKind( + Var->getTemplateSpecializationKind(), PointOfInstantiation); + } } - // Update the type to the newly instantiated definition's type both - // here and within the expression. + // Update the type to the definition's type both here and within the + // expression. if (Def) { DRE->setDecl(Def); QualType T = Def->getType(); diff --git a/test/SemaTemplate/cxx17-inline-variables.cpp b/test/SemaTemplate/cxx17-inline-variables.cpp index c0180506be..9e6761ee57 100644 --- a/test/SemaTemplate/cxx17-inline-variables.cpp +++ b/test/SemaTemplate/cxx17-inline-variables.cpp @@ -5,3 +5,14 @@ template struct DominatorTreeBase { }; extern template class DominatorTreeBase; constexpr bool k = DominatorTreeBase::IsPostDominator; + +namespace CompleteType { + template constexpr int f(const bool (&)[N]) { return 0; } + + template struct X { + static constexpr bool arr[] = {V...}; + static constexpr int value = f(arr); + }; + + constexpr int n = X::value; +}