[cfe-dev] Modify (and reparse) AST

Reid Kleckner rnk at google.com
Thu Feb 13 17:45:18 PST 2014


Here's my poor, not for commit, attempt to do this.  It lets Clang accept
sizeof without typename, but it crashes 72 existing tests.


On Thu, Feb 13, 2014 at 2:46 PM, Reid Kleckner <rnk at google.com> wrote:

> Considering that MSVC rejects typename in places where it is required by
> the standard, I don't think issuing fixits is appropriate if we assume that
> users still want to build with MSVC.
>
> It's way too late to go back and reparse with a new typename token by the
> time we reach instantiation.  We've already done the first parse of the
> template, and now we're transforming AST nodes.
>
> I think we can probably add a hack for sizeof if we observe during
> instantiation that the sizeof expr is really operating on a DeclRefExpr
> that names a type and not a decl.  Then we have to turn that DeclRefExpr
> into TypeSourceInfo, and I think we can rebuild a sizeof() expr that thinks
> it got a type.  I'm not sure how to take apart a DeclRefExpr and go looking
> for types with that name.
>
>
>
> On Thu, Feb 13, 2014 at 12:49 PM, JB Feldman <jb.feldman at kyrus-tech.com>wrote:
>
>> Is there a way to "modify the source" and reparse the text during the AST
>> TreeTransform process?
>>
>> I am trying to make a local change that would fix the bug:
>> http://llvm.org/bugs/show_bug.cgi?id=18443
>>
>> The idea would be to replace the nodes that are rendered as:
>> UnaryExprOrTypeTraitExpr 0x10c4f18 <col:41, col:55> 'unsigned int' sizeof
>> `-ParenExpr 0x10c4f00 <col:47, col:55> '<dependent type>' lvalue
>>   `-DependentScopeDeclRefExpr 0x10c4ed8 <col:48, col:51> '<dependent
>> type>' lvalue
>> with
>> UnaryExprOrTypeTraitExpr 0xf64f28 <col:41, col:64> 'unsigned int' sizeof
>> 'typename T::type'
>>
>> simply by adding "typename" before the symbol, and then the parser would
>> handle it correctly. and generate the correct UnaryExprOrTypeTraitExpr
>>
>> Solutions I would accept include:
>> 1) Change the source and reprocess the file (a la "Fixit"), but this has
>> a high overhead for large files/projects
>> 2) Ask the parser for the single Expr that would be generated from the
>> new text
>> 3) A way to look up what the existing typename would be manually and
>> create the expr manually.
>> 4) Other thing I'm too new to know about.
>>
>> Thanks,
>> JB
>>
>> FYI: I'm trying to do this from the context of
>> TransformUnaryExprOrTypeTraitExpr
>>
>> _______________________________________________
>> cfe-dev mailing list
>> cfe-dev at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20140213/2785e405/attachment.html>
-------------- next part --------------
commit 7820aa682556ee493e9953622cc534ba9abdd5c2
Author: Reid Kleckner <rnk at google.com>
Date:   Thu Feb 13 17:42:41 2014 -0800

    WIP

diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index efd53cf..1c8255c 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -907,6 +907,8 @@ namespace {
     QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
                                            TemplateTypeParmTypeLoc TL);
 
+    ExprResult TransformUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
+
     /// \brief Transforms an already-substituted template type parameter pack
     /// into either itself (if we aren't substituting into its pack expansion)
     /// or the appropriate substituted argument.
@@ -963,6 +965,10 @@ namespace {
     ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
                                                SourceLocation loc,
                                                TemplateArgument arg);
+
+    /// \brief When MSVC compatibility is enabled and processing sizeof(T::x),
+    /// check if T::x names a type, and try to build TypeSourceInfo for it.
+    ExprResult TransformMSUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
   };
 }
 
@@ -1513,6 +1519,65 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
   return Result;
 }
 
+ExprResult TemplateInstantiator::TransformMSUnaryExprOrTypeTraitExpr(
+    UnaryExprOrTypeTraitExpr *E) {
+  Expr *SE = E->getArgumentExpr()->IgnoreParens();
+  DependentScopeDeclRefExpr *DRE = dyn_cast<DependentScopeDeclRefExpr>(SE);
+
+  // Suppress this hack in the presence of a template keyword.
+  if (!DRE || DRE->hasTemplateKeyword())
+    return ExprError();
+
+  // Transform the NNS.  The final identifier shouldn't be dependent.  (Right?)
+  NestedNameSpecifierLoc OldNNS = DRE->getQualifierLoc();
+  NestedNameSpecifierLoc NewNNS = TransformNestedNameSpecifierLoc(OldNNS);
+  if (!NewNNS)
+    return ExprError();
+
+  // Lookup the name and see if it's a type.  Yes, we do name lookup twice.
+  CXXScopeSpec SS;
+  SS.Adopt(NewNNS);
+  DeclContext *DC = SemaRef.computeDeclContext(SS, false);
+  if (!DC)
+    return ExprError();
+  if (SemaRef.RequireCompleteDeclContext(SS, DC))
+    return ExprError();
+
+  const DeclarationNameInfo &NameInfo = DRE->getNameInfo();
+  LookupResult R(SemaRef, NameInfo, Sema::LookupOrdinaryName);
+  if (!SemaRef.LookupQualifiedName(R, DC))
+    return ExprError();
+
+  // If there was any ambiguity, give up.
+  if (R.getResultKind() != LookupResult::Found)
+    return ExprError();
+
+  // If the decl doesn't declare a type, don't do anything special.
+  TypeDecl *D = dyn_cast<TypeDecl>(R.getRepresentativeDecl());
+  if (!D)
+    return ExprError();
+
+  // Otherwise, we're doing sizeof on a type now, not an expression.
+  QualType T = SemaRef.Context.getTypeDeclType(D);
+  TypeSourceInfo *NewT =
+      SemaRef.Context.getTrivialTypeSourceInfo(T, NameInfo.getLoc());
+  llvm::errs() << "TemplateInstantiator::TransformMSUnaryExprOrTypeTraitExpr\n";
+  return RebuildUnaryExprOrTypeTrait(NewT, E->getOperatorLoc(), E->getKind(),
+                                     E->getSourceRange());
+}
+
+ExprResult TemplateInstantiator::TransformUnaryExprOrTypeTraitExpr(
+    UnaryExprOrTypeTraitExpr *E) {
+  // In non-MSVC compatibility modes or when we know we have a type, do normal
+  // instantiation.
+  ExprResult Result;
+  if (SemaRef.getLangOpts().MSVCCompat && !E->isArgumentType())
+    Result = TransformMSUnaryExprOrTypeTraitExpr(E);
+  if (!Result.isInvalid())
+    return Result;
+  return TreeTransform<TemplateInstantiator>::TransformUnaryExprOrTypeTraitExpr(E);
+}
+
 QualType 
 TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
                                                             TypeLocBuilder &TLB,
diff --git a/test/SemaTemplate/ms-sizeof-missing-typename.cpp b/test/SemaTemplate/ms-sizeof-missing-typename.cpp
new file mode 100644
index 0000000..c4f4277
--- /dev/null
+++ b/test/SemaTemplate/ms-sizeof-missing-typename.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fms-compatibility -fsyntax-only -verify %s
+
+// expected-no-diagnostics
+
+template <typename T> int type_f() { return sizeof T::type; }
+template <typename T> int type_g() { return sizeof(T::type); }
+template <typename T> int type_h() { return sizeof((T::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>() +
+      type_g<X>() +
+      type_h<X>() +
+      value_f<X>() +
+      value_f<X>() +
+      value_f<X>();
+}


More information about the cfe-dev mailing list