diff options
| author | George Karpenkov <ekarpenkov@apple.com> | 2018-03-29 00:56:24 +0000 |
|---|---|---|
| committer | George Karpenkov <ekarpenkov@apple.com> | 2018-03-29 00:56:24 +0000 |
| commit | ec38cf7aed74a354d6cbcd4fa99f4490406b467b (patch) | |
| tree | 3e685fff7255276c58869f051c7c9e8b624823d5 | |
| parent | 3588fd4865695be266f8b53c6903393ee2f4d417 (diff) | |
| download | bcm5719-llvm-ec38cf7aed74a354d6cbcd4fa99f4490406b467b.tar.gz bcm5719-llvm-ec38cf7aed74a354d6cbcd4fa99f4490406b467b.zip | |
[ast] Do not auto-initialize Objective-C for-loop variables in Objective-C++ in templatized code under ARC
The AST for the fragment
```
@interface I
@end
template <typename>
void decode(I *p) {
for (I *k in p) {}
}
void decode(I *p) {
decode<int>(p);
}
```
differs heavily when templatized and non-templatized:
```
|-FunctionTemplateDecl 0x7fbfe0863940 <line:4:1, line:7:1> line:5:6 decode
| |-TemplateTypeParmDecl 0x7fbfe0863690 <line:4:11> col:11 typename depth 0 index 0
| |-FunctionDecl 0x7fbfe08638a0 <line:5:1, line:7:1> line:5:6 decode 'void (I *__strong)'
| | |-ParmVarDecl 0x7fbfe08637a0 <col:13, col:16> col:16 referenced p 'I *__strong'
| | `-CompoundStmt 0x7fbfe0863b88 <col:19, line:7:1>
| | `-ObjCForCollectionStmt 0x7fbfe0863b50 <line:6:3, col:20>
| | |-DeclStmt 0x7fbfe0863a50 <col:8, col:13>
| | | `-VarDecl 0x7fbfe08639f0 <col:8, col:11> col:11 k 'I *const __strong'
| | |-ImplicitCastExpr 0x7fbfe0863a90 <col:16> 'I *' <LValueToRValue>
| | | `-DeclRefExpr 0x7fbfe0863a68 <col:16> 'I *__strong' lvalue ParmVar 0x7fbfe08637a0 'p' 'I *__strong'
| | `-CompoundStmt 0x7fbfe0863b78 <col:19, col:20>
| `-FunctionDecl 0x7fbfe0863f80 <line:5:1, line:7:1> line:5:6 used decode 'void (I *__strong)'
| |-TemplateArgument type 'int'
| |-ParmVarDecl 0x7fbfe0863ef8 <col:13, col:16> col:16 used p 'I *__strong'
| `-CompoundStmt 0x7fbfe0890cf0 <col:19, line:7:1>
| `-ObjCForCollectionStmt 0x7fbfe0890cc8 <line:6:3, col:20>
| |-DeclStmt 0x7fbfe0890c70 <col:8, col:13>
| | `-VarDecl 0x7fbfe0890c00 <col:8, col:11> col:11 k 'I *__strong' callinit
| | `-ImplicitValueInitExpr 0x7fbfe0890c60 <<invalid sloc>> 'I *__strong'
| |-ImplicitCastExpr 0x7fbfe0890cb0 <col:16> 'I *' <LValueToRValue>
| | `-DeclRefExpr 0x7fbfe0890c88 <col:16> 'I *__strong' lvalue ParmVar 0x7fbfe0863ef8 'p' 'I *__strong'
| `-CompoundStmt 0x7fbfe0863b78 <col:19, col:20>
```
Note how in the instantiated version ImplicitValueInitExpr unexpectedly appears.
While objects are auto-initialized under ARC, it does not make sense to
have an initializer for a for-loop variable, and it makes even less
sense to have such a different AST for instantiated and non-instantiated
version.
Digging deeper, I have found that there are two separate Sema* files for
dealing with templates and for dealing with non-templatized code.
In a non-templatized version, an initialization was performed only for
variables which are not loop variables for an Objective-C loop and not
variables for a C++ for-in loop:
```
if (FRI && (Tok.is(tok::colon) || isTokIdentifier_in())) {
bool IsForRangeLoop = false;
if (TryConsumeToken(tok::colon, FRI->ColonLoc)) {
IsForRangeLoop = true;
if (Tok.is(tok::l_brace))
FRI->RangeExpr = ParseBraceInitializer();
else
FRI->RangeExpr = ParseExpression();
}
Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D);
if (IsForRangeLoop)
Actions.ActOnCXXForRangeDecl(ThisDecl);
Actions.FinalizeDeclaration(ThisDecl);
D.complete(ThisDecl);
return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, ThisDecl);
}
SmallVector<Decl *, 8> DeclsInGroup;
Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(
D, ParsedTemplateInfo(), FRI);
```
However the code in SemaTemplateInstantiateDecl was inconsistent,
guarding only against C++ for-in loops.
rdar://38391075
Differential Revision: https://reviews.llvm.org/D44989
llvm-svn: 328749
| -rw-r--r-- | clang/include/clang/AST/Decl.h | 13 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 7 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTWriterDecl.cpp | 2 | ||||
| -rw-r--r-- | clang/test/SemaObjC/foreachtemplatized.mm | 15 |
6 files changed, 39 insertions, 2 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 44d2030b4f6..da164c66a61 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -937,6 +937,9 @@ protected: /// for-range statement. unsigned CXXForRangeDecl : 1; + /// Whether this variable is the for-in loop declaration in Objective-C. + unsigned ObjCForDecl : 1; + /// Whether this variable is an ARC pseudo-__strong /// variable; see isARCPseudoStrong() for details. unsigned ARCPseudoStrong : 1; @@ -1334,6 +1337,16 @@ public: NonParmVarDeclBits.CXXForRangeDecl = FRD; } + /// \brief Determine whether this variable is a for-loop declaration for a + /// for-in statement in Objective-C. + bool isObjCForDecl() const { + return NonParmVarDeclBits.ObjCForDecl; + } + + void setObjCForDecl(bool FRD) { + NonParmVarDeclBits.ObjCForDecl = FRD; + } + /// \brief Determine whether this variable is an ARC pseudo-__strong /// variable. A pseudo-__strong variable has a __strong-qualified /// type but does not actually retain the object written into it. diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index f19bcaadf01..0e02acd8595 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2027,8 +2027,13 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); - if (IsForRangeLoop) + if (IsForRangeLoop) { Actions.ActOnCXXForRangeDecl(ThisDecl); + } else { + // Obj-C for loop + if (auto *VD = dyn_cast_or_null<VarDecl>(ThisDecl)) + VD->setObjCForDecl(true); + } Actions.FinalizeDeclaration(ThisDecl); D.complete(ThisDecl); return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, ThisDecl); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 9e09a6aa356..a7883c67b80 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4083,6 +4083,7 @@ void Sema::BuildVariableInstantiation( NewVar->setTSCSpec(OldVar->getTSCSpec()); NewVar->setInitStyle(OldVar->getInitStyle()); NewVar->setCXXForRangeDecl(OldVar->isCXXForRangeDecl()); + NewVar->setObjCForDecl(OldVar->isObjCForDecl()); NewVar->setConstexpr(OldVar->isConstexpr()); NewVar->setInitCapture(OldVar->isInitCapture()); NewVar->setPreviousDeclInSameBlockScope( @@ -4215,7 +4216,7 @@ void Sema::InstantiateVariableInitializer( } // We'll add an initializer to a for-range declaration later. - if (Var->isCXXForRangeDecl()) + if (Var->isCXXForRangeDecl() || Var->isObjCForDecl()) return; ActOnUninitializedDecl(Var); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 0c9151cf80a..fa0db51e7f3 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1279,6 +1279,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) { VD->NonParmVarDeclBits.ExceptionVar = Record.readInt(); VD->NonParmVarDeclBits.NRVOVariable = Record.readInt(); VD->NonParmVarDeclBits.CXXForRangeDecl = Record.readInt(); + VD->NonParmVarDeclBits.ObjCForDecl = Record.readInt(); VD->NonParmVarDeclBits.ARCPseudoStrong = Record.readInt(); VD->NonParmVarDeclBits.IsInline = Record.readInt(); VD->NonParmVarDeclBits.IsInlineSpecified = Record.readInt(); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 254b5175d7b..06ea8e7f2bc 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -920,6 +920,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { Record.push_back(D->isExceptionVariable()); Record.push_back(D->isNRVOVariable()); Record.push_back(D->isCXXForRangeDecl()); + Record.push_back(D->isObjCForDecl()); Record.push_back(D->isARCPseudoStrong()); Record.push_back(D->isInline()); Record.push_back(D->isInlineSpecified()); @@ -2031,6 +2032,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isObjCForDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong Abv->Add(BitCodeAbbrevOp(0)); // isInline Abv->Add(BitCodeAbbrevOp(0)); // isInlineSpecified diff --git a/clang/test/SemaObjC/foreachtemplatized.mm b/clang/test/SemaObjC/foreachtemplatized.mm new file mode 100644 index 00000000000..ab2770a7cef --- /dev/null +++ b/clang/test/SemaObjC/foreachtemplatized.mm @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -Wno-objc-root-class -std=c++11 -ast-dump %s | FileCheck %s + +// CHECK-NOT: ImplicitValueInitExpr + +@interface I +@end + +template <typename T> +void decode(I *p) { + for (I *k in p) {} +} + +void decode(I *p) { + decode<int>(p); +} |

