Author: rnk Date: Thu Jun 12 18:03:48 2014 New Revision: 210855 URL: http://llvm.org/viewvc/llvm-project?rev=210855&view=rev Log: Recover from missing 'typename' in sizeof(T::InnerType)
Summary: 'sizeof' is a UnaryExprOrTypeTrait, and it can contain either a type or an expression. This change threads a RecoveryTSI parameter through the layers between TransformUnaryExprOrTypeTrait the point at which we look up the type. If lookup finds a single type result after instantiation, we now build TypeSourceInfo for it just like a normal transformation would. This fixes the last error in the hello world ATL app that I've been working with, and it now links and runs with clang. Please try it and file bugs! Reviewers: rsmith Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D4108 Added: cfe/trunk/test/SemaTemplate/ms-sizeof-missing-typename.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/TreeTransform.h Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=210855&r1=210854&r2=210855&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jun 12 18:03:48 2014 @@ -3550,7 +3550,7 @@ def note_typename_refers_here : Note< "referenced member %0 is declared here">; def err_typename_missing : Error< "missing 'typename' prior to dependent type name '%0%1'">; -def warn_typename_missing : ExtWarn< +def ext_typename_missing : ExtWarn< "missing 'typename' prior to dependent type name '%0%1'">, InGroup<DiagGroup<"typename-missing">>; def ext_typename_outside_of_template : ExtWarn< Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=210855&r1=210854&r2=210855&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Thu Jun 12 18:03:48 2014 @@ -3403,9 +3403,10 @@ public: const LookupResult &R, bool HasTrailingLParen); - ExprResult BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, - const DeclarationNameInfo &NameInfo, - bool IsAddressOfOperand); + ExprResult BuildQualifiedDeclarationNameExpr( + CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, + bool IsAddressOfOperand, TypeSourceInfo **RecoveryTSI = nullptr); + ExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=210855&r1=210854&r2=210855&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jun 12 18:03:48 2014 @@ -517,7 +517,7 @@ bool Sema::DiagnoseUnknownTypeName(Ident else if (isDependentScopeSpecifier(*SS)) { unsigned DiagID = diag::err_typename_missing; if (getLangOpts().MSVCCompat && isMicrosoftMissingTypename(SS, S)) - DiagID = diag::warn_typename_missing; + DiagID = diag::ext_typename_missing; Diag(SS->getRange().getBegin(), DiagID) << SS->getScopeRep() << II->getName() Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=210855&r1=210854&r2=210855&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Jun 12 18:03:48 2014 @@ -2185,7 +2185,8 @@ ExprResult Sema::ActOnIdExpression(Scope ExprResult Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, - bool IsAddressOfOperand) { + bool IsAddressOfOperand, + TypeSourceInfo **RecoveryTSI) { DeclContext *DC = computeDeclContext(SS, false); if (!DC) return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(), @@ -2210,15 +2211,39 @@ Sema::BuildQualifiedDeclarationNameExpr( return ExprError(); } - if (R.isSingleResult() && R.getAsSingle<TypeDecl>()) { - // Diagnose a missing typename if this resolved unambiguously to a type in a - // dependent context. - // FIXME: Issue a fixit and recover as though the user had written - // 'typename'. - Diag(SS.getBeginLoc(), diag::err_typename_missing) - << SS.getScopeRep() << NameInfo.getName().getAsString() - << SourceRange(SS.getBeginLoc(), NameInfo.getEndLoc()); - return ExprError(); + if (const TypeDecl *TD = R.getAsSingle<TypeDecl>()) { + // Diagnose a missing typename if this resolved unambiguously to a type in + // a dependent context. If we can recover with a type, downgrade this to + // a warning in Microsoft compatibility mode. + unsigned DiagID = diag::err_typename_missing; + if (RecoveryTSI && getLangOpts().MSVCCompat) + DiagID = diag::ext_typename_missing; + SourceLocation Loc = SS.getBeginLoc(); + auto D = Diag(Loc, DiagID); + D << SS.getScopeRep() << NameInfo.getName().getAsString() + << SourceRange(Loc, NameInfo.getEndLoc()); + + // Don't recover if the caller isn't expecting us to or if we're in a SFINAE + // context. + if (!RecoveryTSI) + return ExprError(); + + // Only issue the fixit if we're prepared to recover. + D << FixItHint::CreateInsertion(Loc, "typename "); + + // Recover by pretending this was an elaborated type. + QualType Ty = Context.getTypeDeclType(TD); + TypeLocBuilder TLB; + TLB.pushTypeSpec(Ty).setNameLoc(NameInfo.getLoc()); + + QualType ET = getElaboratedType(ETK_None, SS, Ty); + ElaboratedTypeLoc QTL = TLB.push<ElaboratedTypeLoc>(ET); + QTL.setElaboratedKeywordLoc(SourceLocation()); + QTL.setQualifierLoc(SS.getWithLocInContext(Context)); + + *RecoveryTSI = TLB.getTypeSourceInfo(Context, ET); + + return ExprEmpty(); } // Defend against this resolving to an implicit member access. We usually Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=210855&r1=210854&r2=210855&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Jun 12 18:03:48 2014 @@ -2897,7 +2897,7 @@ Sema::BuildQualifiedTemplateIdExpr(CXXSc if (ClassTemplateDecl *Temp = R.getAsSingle<ClassTemplateDecl>()) { Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_class_template) << SS.getScopeRep() - << NameInfo.getName() << SS.getRange(); + << NameInfo.getName().getAsString() << SS.getRange(); Diag(Temp->getLocation(), diag::note_referenced_class_template); return ExprError(); } Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=210855&r1=210854&r2=210855&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Thu Jun 12 18:03:48 2014 @@ -604,8 +604,15 @@ public: } ExprResult TransformAddressOfOperand(Expr *E); + ExprResult TransformDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E, - bool IsAddressOfOperand); + bool IsAddressOfOperand, + TypeSourceInfo **RecoveryTSI); + + ExprResult TransformParenDependentScopeDeclRefExpr( + ParenExpr *PE, DependentScopeDeclRefExpr *DRE, bool IsAddressOfOperand, + TypeSourceInfo **RecoveryTSI); + StmtResult TransformOMPExecutableDirective(OMPExecutableDirective *S); // FIXME: We use LLVM_ATTRIBUTE_NOINLINE because inlining causes a ridiculous @@ -2288,16 +2295,17 @@ public: SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, - bool IsAddressOfOperand) { + bool IsAddressOfOperand, + TypeSourceInfo **RecoveryTSI) { CXXScopeSpec SS; SS.Adopt(QualifierLoc); if (TemplateArgs || TemplateKWLoc.isValid()) - return getSema().BuildQualifiedTemplateIdExpr(SS, TemplateKWLoc, - NameInfo, TemplateArgs); + return getSema().BuildQualifiedTemplateIdExpr(SS, TemplateKWLoc, NameInfo, + TemplateArgs); - return getSema().BuildQualifiedDeclarationNameExpr(SS, NameInfo, - IsAddressOfOperand); + return getSema().BuildQualifiedDeclarationNameExpr( + SS, NameInfo, IsAddressOfOperand, RecoveryTSI); } /// \brief Build a new template-id expression. @@ -6708,7 +6716,7 @@ template<typename Derived> ExprResult TreeTransform<Derived>::TransformAddressOfOperand(Expr *E) { if (DependentScopeDeclRefExpr *DRE = dyn_cast<DependentScopeDeclRefExpr>(E)) - return getDerived().TransformDependentScopeDeclRefExpr(DRE, true); + return getDerived().TransformDependentScopeDeclRefExpr(DRE, true, nullptr); else return getDerived().TransformExpr(E); } @@ -6853,8 +6861,22 @@ TreeTransform<Derived>::TransformUnaryEx EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated, Sema::ReuseLambdaContextDecl); - ExprResult SubExpr = getDerived().TransformExpr(E->getArgumentExpr()); - if (SubExpr.isInvalid()) + // Try to recover if we have something like sizeof(T::X) where X is a type. + // Notably, there must be *exactly* one set of parens if X is a type. + TypeSourceInfo *RecoveryTSI = nullptr; + ExprResult SubExpr; + auto *PE = dyn_cast<ParenExpr>(E->getArgumentExpr()); + if (auto *DRE = + PE ? dyn_cast<DependentScopeDeclRefExpr>(PE->getSubExpr()) : nullptr) + SubExpr = getDerived().TransformParenDependentScopeDeclRefExpr( + PE, DRE, false, &RecoveryTSI); + else + SubExpr = getDerived().TransformExpr(E->getArgumentExpr()); + + if (RecoveryTSI) { + return getDerived().RebuildUnaryExprOrTypeTrait( + RecoveryTSI, E->getOperatorLoc(), E->getKind(), E->getSourceRange()); + } else if (SubExpr.isInvalid()) return ExprError(); if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getArgumentExpr()) @@ -8234,18 +8256,37 @@ TreeTransform<Derived>::TransformExpress E->getTrait(), E->getLocStart(), SubExpr.get(), E->getLocEnd()); } -template<typename Derived> -ExprResult -TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( - DependentScopeDeclRefExpr *E) { - return TransformDependentScopeDeclRefExpr(E, /*IsAddressOfOperand*/false); +template <typename Derived> +ExprResult TreeTransform<Derived>::TransformParenDependentScopeDeclRefExpr( + ParenExpr *PE, DependentScopeDeclRefExpr *DRE, bool AddrTaken, + TypeSourceInfo **RecoveryTSI) { + ExprResult NewDRE = getDerived().TransformDependentScopeDeclRefExpr( + DRE, AddrTaken, RecoveryTSI); + + // Propagate both errors and recovered types, which return ExprEmpty. + if (!NewDRE.isUsable()) + return NewDRE; + + // We got an expr, wrap it up in parens. + if (!getDerived().AlwaysRebuild() && NewDRE.get() == DRE) + return PE; + return getDerived().RebuildParenExpr(NewDRE.get(), PE->getLParen(), + PE->getRParen()); +} + +template <typename Derived> +ExprResult TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( + DependentScopeDeclRefExpr *E) { + return TransformDependentScopeDeclRefExpr(E, /*IsAddressOfOperand=*/false, + nullptr); } template<typename Derived> ExprResult TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *E, - bool IsAddressOfOperand) { + bool IsAddressOfOperand, + TypeSourceInfo **RecoveryTSI) { assert(E->getQualifierLoc()); NestedNameSpecifierLoc QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc()); @@ -8270,11 +8311,9 @@ TreeTransform<Derived>::TransformDepende NameInfo.getName() == E->getDeclName()) return E; - return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc, - TemplateKWLoc, - NameInfo, - /*TemplateArgs*/nullptr, - IsAddressOfOperand); + return getDerived().RebuildDependentScopeDeclRefExpr( + QualifierLoc, TemplateKWLoc, NameInfo, /*TemplateArgs=*/nullptr, + IsAddressOfOperand, RecoveryTSI); } TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc()); @@ -8283,11 +8322,9 @@ TreeTransform<Derived>::TransformDepende TransArgs)) return ExprError(); - return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc, - TemplateKWLoc, - NameInfo, - &TransArgs, - IsAddressOfOperand); + return getDerived().RebuildDependentScopeDeclRefExpr( + QualifierLoc, TemplateKWLoc, NameInfo, &TransArgs, IsAddressOfOperand, + RecoveryTSI); } template<typename Derived> Added: cfe/trunk/test/SemaTemplate/ms-sizeof-missing-typename.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/ms-sizeof-missing-typename.cpp?rev=210855&view=auto ============================================================================== --- cfe/trunk/test/SemaTemplate/ms-sizeof-missing-typename.cpp (added) +++ cfe/trunk/test/SemaTemplate/ms-sizeof-missing-typename.cpp Thu Jun 12 18:03:48 2014 @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only -verify %s + +// If we were even more clever, we'd tell the user to use one set of parens to +// get the size of this type, so they don't get errors after inserting typename. + +namespace basic { +template <typename T> int type_f() { return sizeof T::type; } // expected-error {{missing 'typename' prior to dependent type name 'X::type'}} +template <typename T> int type_g() { return sizeof(T::type); } // expected-warning {{missing 'typename' prior to dependent type name 'X::type'}} +template <typename T> int type_h() { return sizeof((T::type)); } // expected-error {{missing 'typename' prior to dependent type name 'X::type'}} +template <typename T> int value_f() { return sizeof T::not_a_type; } +template <typename T> int value_g() { return sizeof(T::not_a_type); } +template <typename T> int value_h() { return sizeof((T::not_a_type)); } +struct X { + typedef int type; + static const int not_a_type; +}; +int bar() { + return + type_f<X>() + // expected-note-re {{in instantiation {{.*}} requested here}} + type_g<X>() + // expected-note-re {{in instantiation {{.*}} requested here}} + type_h<X>() + // expected-note-re {{in instantiation {{.*}} requested here}} + value_f<X>() + + value_f<X>() + + value_f<X>(); +} +} + +namespace nested_sizeof { +template <typename T> +struct Foo { + enum { + // expected-warning@+2 {{use 'template' keyword to treat 'InnerTemplate' as a dependent template name}} + // expected-warning@+1 {{missing 'typename' prior to dependent type name 'Bar::InnerType'}} + x1 = sizeof(typename T::/*template*/ InnerTemplate<sizeof(/*typename*/ T::InnerType)>), + // expected-warning@+1 {{missing 'typename' prior to dependent type name 'Bar::InnerType'}} + x2 = sizeof(typename T::template InnerTemplate<sizeof(/*typename*/ T::InnerType)>), + // expected-warning@+1 {{use 'template' keyword to treat 'InnerTemplate' as a dependent template name}} + y1 = sizeof(typename T::/*template*/ InnerTemplate<sizeof(T::InnerVar)>), + y2 = sizeof(typename T::template InnerTemplate<sizeof(T::InnerVar)>), + z = sizeof(T::template InnerTemplate<sizeof(T::InnerVar)>::x), + }; +}; +struct Bar { + template <int N> + struct InnerTemplate { int x[N]; }; + typedef double InnerType; + static const int InnerVar = 42; +}; +template struct Foo<Bar>; // expected-note-re {{in instantiation {{.*}} requested here}} +} + +namespace ambiguous_missing_parens { +// expected-error@+1 {{'Q::U' instantiated to a class template, not a function template}} +template <typename T> void f() { int a = sizeof T::template U<0> + 4; } +struct Q { + // expected-error@+1 {{class template declared here}} + template <int> struct U {}; +}; +// expected-note-re@+1 {{in instantiation {{.*}} requested here}} +template void f<Q>(); +} _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
