aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2011-02-20 03:19:35 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2011-02-20 03:19:35 +0000
commit34b41d939a1328f484511c6002ba2456db879a29 (patch)
tree9631c2ce7dde0b9c680fe463d5718d0cb8f92e45 /lib
parent9ed9a250180f19b2c44df83a196fc3a2ac82f817 (diff)
Implement the C++0x deduced 'auto' feature.
This fixes PR 8738, 9060 and 9132. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126069 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/ASTContext.cpp19
-rw-r--r--lib/AST/ASTDiagnostic.cpp22
-rw-r--r--lib/AST/ASTImporter.cpp25
-rw-r--r--lib/AST/ItaniumMangle.cpp9
-rw-r--r--lib/AST/MicrosoftMangle.cpp7
-rw-r--r--lib/AST/Type.cpp56
-rw-r--r--lib/AST/TypeLoc.cpp4
-rw-r--r--lib/AST/TypePrinter.cpp14
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp1
-rw-r--r--lib/CodeGen/CGRTTI.cpp1
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp1
-rw-r--r--lib/Parse/ParseDecl.cpp15
-rw-r--r--lib/Parse/ParseExprCXX.cpp3
-rw-r--r--lib/Sema/SemaCodeComplete.cpp1
-rw-r--r--lib/Sema/SemaDecl.cpp178
-rw-r--r--lib/Sema/SemaDeclCXX.cpp37
-rw-r--r--lib/Sema/SemaExpr.cpp46
-rw-r--r--lib/Sema/SemaExprCXX.cpp40
-rw-r--r--lib/Sema/SemaTemplate.cpp4
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp106
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp8
-rw-r--r--lib/Sema/SemaType.cpp80
-rw-r--r--lib/Sema/TreeTransform.h32
-rw-r--r--lib/Serialization/ASTCommon.cpp3
-rw-r--r--lib/Serialization/ASTReader.cpp6
-rw-r--r--lib/Serialization/ASTWriter.cpp8
26 files changed, 567 insertions, 159 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 50c295f241..945dfb87f2 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -380,10 +380,6 @@ void ASTContext::InitBuiltinTypes() {
// Placeholder type for functions.
InitBuiltinType(OverloadTy, BuiltinType::Overload);
- // Placeholder type for C++0x auto declarations whose real type has
- // not yet been deduced.
- InitBuiltinType(UndeducedAutoTy, BuiltinType::UndeducedAuto);
-
// C99 6.2.5p11.
FloatComplexTy = getComplexType(FloatTy);
DoubleComplexTy = getComplexType(DoubleTy);
@@ -875,6 +871,12 @@ ASTContext::getTypeInfo(const Type *T) const {
return getTypeInfo(cast<SubstTemplateTypeParmType>(T)->
getReplacementType().getTypePtr());
+ case Type::Auto: {
+ const AutoType *A = cast<AutoType>(T);
+ assert(A->isDeduced() && "Cannot request the size of a dependent type");
+ return getTypeInfo(cast<AutoType>(T)->getDeducedType().getTypePtr());
+ }
+
case Type::Paren:
return getTypeInfo(cast<ParenType>(T)->getInnerType().getTypePtr());
@@ -1532,6 +1534,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
case Type::DependentTemplateSpecialization:
case Type::TemplateTypeParm:
case Type::SubstTemplateTypeParmPack:
+ case Type::Auto:
case Type::PackExpansion:
llvm_unreachable("type should never be variably-modified");
@@ -2680,6 +2683,14 @@ QualType ASTContext::getDecltypeType(Expr *e) const {
return QualType(dt, 0);
}
+/// getAutoType - Unlike many "get<Type>" functions, we don't unique
+/// AutoType AST's.
+QualType ASTContext::getAutoType(QualType DeducedType) const {
+ AutoType *at = new (*this, TypeAlignment) AutoType(DeducedType);
+ Types.push_back(at);
+ return QualType(at, 0);
+}
+
/// getTagDeclType - Return the unique reference to the type for the
/// specified TagDecl (struct/union/class/enum) decl.
QualType ASTContext::getTagDeclType(const TagDecl *Decl) const {
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 9870b515c6..5bf8a38199 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -28,18 +28,26 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
const Type *Ty = QC.strip(QT);
// Don't aka just because we saw an elaborated type...
- if (isa<ElaboratedType>(Ty)) {
- QT = cast<ElaboratedType>(Ty)->desugar();
+ if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Ty)) {
+ QT = ET->desugar();
continue;
}
// ... or a paren type ...
- if (isa<ParenType>(Ty)) {
- QT = cast<ParenType>(Ty)->desugar();
+ if (const ParenType *PT = dyn_cast<ParenType>(Ty)) {
+ QT = PT->desugar();
continue;
}
- // ...or a substituted template type parameter.
- if (isa<SubstTemplateTypeParmType>(Ty)) {
- QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();
+ // ...or a substituted template type parameter ...
+ if (const SubstTemplateTypeParmType *ST =
+ dyn_cast<SubstTemplateTypeParmType>(Ty)) {
+ QT = ST->desugar();
+ continue;
+ }
+ // ... or an auto type.
+ if (const AutoType *AT = dyn_cast<AutoType>(Ty)) {
+ if (!AT->isSugared())
+ break;
+ QT = AT->desugar();
continue;
}
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index a1e0070422..65c0a3bb61 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -64,6 +64,7 @@ namespace {
// FIXME: DependentTypeOfExprType
QualType VisitTypeOfType(const TypeOfType *T);
QualType VisitDecltypeType(const DecltypeType *T);
+ QualType VisitAutoType(const AutoType *T);
// FIXME: DependentDecltypeType
QualType VisitRecordType(const RecordType *T);
QualType VisitEnumType(const EnumType *T);
@@ -604,6 +605,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
+ case Type::Auto:
+ if (!IsStructurallyEquivalent(Context,
+ cast<AutoType>(T1)->getDeducedType(),
+ cast<AutoType>(T2)->getDeducedType()))
+ return false;
+ break;
+
case Type::Record:
case Type::Enum:
if (!IsStructurallyEquivalent(Context,
@@ -1347,9 +1355,6 @@ QualType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) {
case BuiltinType::Overload: return Importer.getToContext().OverloadTy;
case BuiltinType::Dependent: return Importer.getToContext().DependentTy;
- case BuiltinType::UndeducedAuto:
- // FIXME: Make sure that the "to" context supports C++0x!
- return Importer.getToContext().UndeducedAutoTy;
case BuiltinType::ObjCId:
// FIXME: Make sure that the "to" context supports Objective-C!
@@ -1550,6 +1555,7 @@ QualType ASTNodeImporter::VisitTypeOfType(const TypeOfType *T) {
}
QualType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) {
+ // FIXME: Make sure that the "to" context supports C++0x!
Expr *ToExpr = Importer.Import(T->getUnderlyingExpr());
if (!ToExpr)
return QualType();
@@ -1557,6 +1563,19 @@ QualType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) {
return Importer.getToContext().getDecltypeType(ToExpr);
}
+QualType ASTNodeImporter::VisitAutoType(const AutoType *T) {
+ // FIXME: Make sure that the "to" context supports C++0x!
+ QualType FromDeduced = T->getDeducedType();
+ QualType ToDeduced;
+ if (!FromDeduced.isNull()) {
+ ToDeduced = Importer.Import(FromDeduced);
+ if (ToDeduced.isNull())
+ return QualType();
+ }
+
+ return Importer.getToContext().getAutoType(ToDeduced);
+}
+
QualType ASTNodeImporter::VisitRecordType(const RecordType *T) {
RecordDecl *ToDecl
= dyn_cast_or_null<RecordDecl>(Importer.Import(T->getDecl()));
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 2819a7e4b9..d66c374cbe 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -1313,9 +1313,6 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
assert(false &&
"Overloaded and dependent types shouldn't get to name mangling");
break;
- case BuiltinType::UndeducedAuto:
- assert(0 && "Should not see undeduced auto here");
- break;
case BuiltinType::ObjCId: Out << "11objc_object"; break;
case BuiltinType::ObjCClass: Out << "10objc_class"; break;
case BuiltinType::ObjCSel: Out << "13objc_selector"; break;
@@ -1648,6 +1645,12 @@ void CXXNameMangler::mangleType(const DecltypeType *T) {
Out << 'E';
}
+void CXXNameMangler::mangleType(const AutoType *T) {
+ QualType D = T->getDeducedType();
+ assert(!D.isNull() && "can't mangle undeduced auto type");
+ mangleType(D);
+}
+
void CXXNameMangler::mangleIntegerLiteral(QualType T,
const llvm::APSInt &Value) {
// <expr-primary> ::= L <type> <value number> E # integer literal
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 7aafac0ad0..4bf7f23a0a 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -720,9 +720,6 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) {
assert(false &&
"Overloaded and dependent types shouldn't get to name mangling");
break;
- case BuiltinType::UndeducedAuto:
- assert(0 && "Should not see undeduced auto here");
- break;
case BuiltinType::ObjCId: Out << "PAUobjc_object@@"; break;
case BuiltinType::ObjCClass: Out << "PAUobjc_class@@"; break;
case BuiltinType::ObjCSel: Out << "PAUobjc_selector@@"; break;
@@ -1119,6 +1116,10 @@ void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T) {
assert(false && "Don't know how to mangle DecltypeTypes yet!");
}
+void MicrosoftCXXNameMangler::mangleType(const AutoType *T) {
+ assert(false && "Don't know how to mangle AutoTypes yet!");
+}
+
void MicrosoftMangleContext::mangleName(const NamedDecl *D,
llvm::raw_ostream &Out) {
assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 0130b13b94..b03314e11d 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -432,6 +432,61 @@ CXXRecordDecl *Type::getAsCXXRecordDecl() const {
return 0;
}
+namespace {
+ class GetContainedAutoVisitor :
+ public TypeVisitor<GetContainedAutoVisitor, AutoType*> {
+ public:
+ using TypeVisitor<GetContainedAutoVisitor, AutoType*>::Visit;
+ AutoType *Visit(QualType T) {
+ if (T.isNull())
+ return 0;
+ return Visit(T.getTypePtr());
+ }
+
+ // The 'auto' type itself.
+ AutoType *VisitAutoType(const AutoType *AT) {
+ return const_cast<AutoType*>(AT);
+ }
+
+ // Only these types can contain the desired 'auto' type.
+ AutoType *VisitPointerType(const PointerType *T) {
+ return Visit(T->getPointeeType());
+ }
+ AutoType *VisitBlockPointerType(const BlockPointerType *T) {
+ return Visit(T->getPointeeType());
+ }
+ AutoType *VisitReferenceType(const ReferenceType *T) {
+ return Visit(T->getPointeeTypeAsWritten());
+ }
+ AutoType *VisitMemberPointerType(const MemberPointerType *T) {
+ return Visit(T->getPointeeType());
+ }
+ AutoType *VisitArrayType(const ArrayType *T) {
+ return Visit(T->getElementType());
+ }
+ AutoType *VisitDependentSizedExtVectorType(
+ const DependentSizedExtVectorType *T) {
+ return Visit(T->getElementType());
+ }
+ AutoType *VisitVectorType(const VectorType *T) {
+ return Visit(T->getElementType());
+ }
+ AutoType *VisitFunctionType(const FunctionType *T) {
+ return Visit(T->getResultType());
+ }
+ AutoType *VisitParenType(const ParenType *T) {
+ return Visit(T->getInnerType());
+ }
+ AutoType *VisitAttributedType(const AttributedType *T) {
+ return Visit(T->getModifiedType());
+ }
+ };
+}
+
+AutoType *Type::getContainedAutoType() const {
+ return GetContainedAutoVisitor().Visit(this);
+}
+
bool Type::isIntegerType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
@@ -1066,7 +1121,6 @@ const char *BuiltinType::getName(const LangOptions &LO) const {
case NullPtr: return "nullptr_t";
case Overload: return "<overloaded function type>";
case Dependent: return "<dependent type>";
- case UndeducedAuto: return "auto";
case ObjCId: return "id";
case ObjCClass: return "Class";
case ObjCSel: return "SEL";
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 0680acb1c5..14db7f83c2 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -191,9 +191,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::WChar_S:
case BuiltinType::WChar_U:
return TST_wchar;
- case BuiltinType::UndeducedAuto:
- return TST_auto;
-
+
case BuiltinType::UChar:
case BuiltinType::UShort:
case BuiltinType::UInt:
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 5e6046acdc..139073987a 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -80,6 +80,8 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
bool CanPrefixQualifiers = false;
Type::TypeClass TC = T->getTypeClass();
+ if (const AutoType *AT = dyn_cast<AutoType>(T))
+ TC = AT->desugar()->getTypeClass();
if (const SubstTemplateTypeParmType *Subst
= dyn_cast<SubstTemplateTypeParmType>(T))
TC = Subst->getReplacementType()->getTypeClass();
@@ -129,6 +131,7 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
case Type::Attributed:
case Type::PackExpansion:
case Type::SubstTemplateTypeParm:
+ case Type::Auto:
CanPrefixQualifiers = false;
break;
}
@@ -493,6 +496,17 @@ void TypePrinter::printDecltype(const DecltypeType *T, std::string &S) {
S = "decltype(" + s.str() + ")" + S;
}
+void TypePrinter::printAuto(const AutoType *T, std::string &S) {
+ // If the type has been deduced, do not print 'auto'.
+ if (T->isDeduced()) {
+ print(T->getDeducedType(), S);
+ } else {
+ if (!S.empty()) // Prefix the basic type, e.g. 'auto X'.
+ S = ' ' + S;
+ S = "auto" + S;
+ }
+}
+
/// Appends the given scope to the end of a string.
void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) {
if (DC->isTranslationUnit()) return;
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 01a4154a87..469b4605d7 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -1465,6 +1465,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Decltype:
+ case Type::Auto:
llvm_unreachable("type should have been unwrapped!");
return llvm::DIType();
}
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index de403b6559..7ec0ee4b5c 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -195,7 +195,6 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
case BuiltinType::Overload:
case BuiltinType::Dependent:
- case BuiltinType::UndeducedAuto:
assert(false && "Should not see this type here!");
case BuiltinType::ObjCId:
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 0a1f76d297..5254922f13 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -253,7 +253,6 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
case BuiltinType::Overload:
case BuiltinType::Dependent:
- case BuiltinType::UndeducedAuto:
assert(0 && "Unexpected builtin type!");
break;
}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index bff4e184c2..5a7fc7e72d 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -392,7 +392,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts,
ParsingDeclSpec DS(*this);
DS.takeAttributesFrom(attrs);
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
- getDeclSpecContextFromDeclaratorContext(Context));
+ getDeclSpecContextFromDeclaratorContext(Context));
StmtResult R = Actions.ActOnVlaStmt(DS);
if (R.isUsable())
Stmts.push_back(R.release());
@@ -587,6 +587,9 @@ Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D,
}
}
+ bool TypeContainsAuto =
+ D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
+
// Parse declarator '=' initializer.
if (isTokenEqualOrMistypedEqualEqual(
diag::err_invalid_equalequal_after_declarator)) {
@@ -622,7 +625,8 @@ Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D,
SkipUntil(tok::comma, true, true);
Actions.ActOnInitializerError(ThisDecl);
} else
- Actions.AddInitializerToDecl(ThisDecl, Init.take());
+ Actions.AddInitializerToDecl(ThisDecl, Init.take(),
+ /*DirectInit=*/false, TypeContainsAuto);
}
} else if (Tok.is(tok::l_paren)) {
// Parse C++ direct initializer: '(' expression-list ')'
@@ -656,12 +660,11 @@ Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D,
Actions.AddCXXDirectInitializerToDecl(ThisDecl, LParenLoc,
move_arg(Exprs),
- RParenLoc);
+ RParenLoc,
+ TypeContainsAuto);
}
} else {
- bool TypeContainsUndeducedAuto =
- D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
- Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsUndeducedAuto);
+ Actions.ActOnUninitializedDecl(ThisDecl, TypeContainsAuto);
}
return ThisDecl;
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index e769ecac50..e73578f23e 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -827,7 +827,8 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
ConsumeToken();
ExprResult AssignExpr(ParseAssignmentExpression());
if (!AssignExpr.isInvalid())
- Actions.AddInitializerToDecl(DeclOut, AssignExpr.take());
+ Actions.AddInitializerToDecl(DeclOut, AssignExpr.take(), false,
+ DS.getTypeSpecType() == DeclSpec::TST_auto);
} else {
// FIXME: C++0x allows a braced-init-list
Diag(Tok, diag::err_expected_equal_after_declarator);
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index aef5cab98a..bab665a38d 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -586,7 +586,6 @@ SimplifiedTypeClass clang::getSimplifiedTypeClass(CanQualType T) {
case BuiltinType::Overload:
case BuiltinType::Dependent:
- case BuiltinType::UndeducedAuto:
return STC_Other;
case BuiltinType::ObjCId:
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 679b430a3c..dd30c1261e 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1471,48 +1471,26 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) {
return false;
}
-/// MergeVarDecl - We just parsed a variable 'New' which has the same name
-/// and scope as a previous declaration 'Old'. Figure out how to resolve this
-/// situation, merging decls or emitting diagnostics as appropriate.
+/// MergeVarDecl - We parsed a variable 'New' which has the same name and scope
+/// as a previous declaration 'Old'. Figure out how to merge their types,
+/// emitting diagnostics as appropriate.
///
-/// Tentative definition rules (C99 6.9.2p2) are checked by
-/// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative
-/// definitions here, since the initializer hasn't been attached.
+/// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back
+/// to here in AddInitializerToDecl and AddCXXDirectInitializerToDecl. We can't
+/// check them before the initializer is attached.
///
-void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
- // If the new decl is already invalid, don't do any other checking.
- if (New->isInvalidDecl())
+void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
+ if (New->isInvalidDecl() || Old->isInvalidDecl())
return;
- // Verify the old decl was also a variable.
- VarDecl *Old = 0;
- if (!Previous.isSingleResult() ||
- !(Old = dyn_cast<VarDecl>(Previous.getFoundDecl()))) {
- Diag(New->getLocation(), diag::err_redefinition_different_kind)
- << New->getDeclName();
- Diag(Previous.getRepresentativeDecl()->getLocation(),
- diag::note_previous_definition);
- return New->setInvalidDecl();
- }
-
- // C++ [class.mem]p1:
- // A member shall not be declared twice in the member-specification [...]
- //
- // Here, we need only consider static data members.
- if (Old->isStaticDataMember() && !New->isOutOfLine()) {
- Diag(New->getLocation(), diag::err_duplicate_member)
- << New->getIdentifier();
- Diag(Old->getLocation(), diag::note_previous_declaration);
- New->setInvalidDecl();
- }
-
- MergeDeclAttributes(New, Old, Context);
-
- // Merge the types
QualType MergedT;
if (getLangOptions().CPlusPlus) {
- if (Context.hasSameType(New->getType(), Old->getType()))
- MergedT = New->getType();
+ AutoType *AT = New->getType()->getContainedAutoType();
+ if (AT && !AT->isDeduced()) {
+ // We don't know what the new type is until the initializer is attached.
+ return;
+ } else if (Context.hasSameType(New->getType(), Old->getType()))
+ return;
// C++ [basic.link]p10:
// [...] the types specified by all declarations referring to a given
// object or function shall be identical, except that declarations for an
@@ -1536,7 +1514,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
MergedT = Old->getType();
} else if (New->getType()->isObjCObjectPointerType()
&& Old->getType()->isObjCObjectPointerType()) {
- MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType());
+ MergedT = Context.mergeObjCGCQualifiers(New->getType(),
+ Old->getType());
}
} else {
MergedT = Context.mergeTypes(New->getType(), Old->getType());
@@ -1548,6 +1527,49 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
return New->setInvalidDecl();
}
New->setType(MergedT);
+}
+
+/// MergeVarDecl - We just parsed a variable 'New' which has the same name
+/// and scope as a previous declaration 'Old'. Figure out how to resolve this
+/// situation, merging decls or emitting diagnostics as appropriate.
+///
+/// Tentative definition rules (C99 6.9.2p2) are checked by
+/// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative
+/// definitions here, since the initializer hasn't been attached.
+///
+void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
+ // If the new decl is already invalid, don't do any other checking.
+ if (New->isInvalidDecl())
+ return;
+
+ // Verify the old decl was also a variable.
+ VarDecl *Old = 0;
+ if (!Previous.isSingleResult() ||
+ !(Old = dyn_cast<VarDecl>(Previous.getFoundDecl()))) {
+ Diag(New->getLocation(), diag::err_redefinition_different_kind)
+ << New->getDeclName();
+ Diag(Previous.getRepresentativeDecl()->getLocation(),
+ diag::note_previous_definition);
+ return New->setInvalidDecl();
+ }
+
+ // C++ [class.mem]p1:
+ // A member shall not be declared twice in the member-specification [...]
+ //
+ // Here, we need only consider static data members.
+ if (Old->isStaticDataMember() && !New->isOutOfLine()) {
+ Diag(New->getLocation(), diag::err_duplicate_member)
+ << New->getIdentifier();
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ New->setInvalidDecl();
+ }
+
+ MergeDeclAttributes(New, Old, Context);
+
+ // Merge the types.
+ MergeVarDeclTypes(New, Old);
+ if (New->isInvalidDecl())
+ return;
// C99 6.2.2p4: Check if we have a static decl followed by a non-static.
if (New->getStorageClass() == SC_Static &&
@@ -3004,6 +3026,12 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
II, R, TInfo, SC, SCAsWritten);
+ // If this decl has an auto type in need of deduction, mark the VarDecl so
+ // we can diagnose uses of it in its own initializer.
+ if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto) {
+ NewVD->setParsingAutoInit(R->getContainedAutoType());
+ }
+
if (D.isInvalidType() || Invalid)
NewVD->setInvalidDecl();
@@ -4466,17 +4494,14 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
return true;
}
-void Sema::AddInitializerToDecl(Decl *dcl, Expr *init) {
- AddInitializerToDecl(dcl, init, /*DirectInit=*/false);
-}
-
/// AddInitializerToDecl - Adds the initializer Init to the
/// declaration dcl. If DirectInit is true, this is C++ direct
/// initialization rather than copy initialization.
-void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
+void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
+ bool DirectInit, bool TypeMayContainAuto) {
// If there is no declaration, there was an error parsing it. Just ignore
// the initializer.
- if (RealDecl == 0)
+ if (RealDecl == 0 || RealDecl->isInvalidDecl())
return;
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) {
@@ -4507,6 +4532,25 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
return;
}
+ // C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
+ if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) {
+ VDecl->setParsingAutoInit(false);
+
+ QualType DeducedType;
+ if (!DeduceAutoType(VDecl->getType(), Init, DeducedType)) {
+ Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure)
+ << VDecl->getDeclName() << VDecl->getType() << Init->getType()
+ << Init->getSourceRange();
+ RealDecl->setInvalidDecl();
+ return;
+ }
+ VDecl->setType(DeducedType);
+
+ // If this is a redeclaration, check that the type we just deduced matches
+ // the previously declared type.
+ if (VarDecl *Old = VDecl->getPreviousDeclaration())
+ MergeVarDeclTypes(VDecl, Old);
+ }
// A definition must end up with a complete type, which means it must be
@@ -4755,6 +4799,13 @@ void Sema::ActOnInitializerError(Decl *D) {
VarDecl *VD = dyn_cast<VarDecl>(D);
if (!VD) return;
+ // Auto types are meaningless if we can't make sense of the initializer.
+ if (VD->isParsingAutoInit()) {
+ VD->setParsingAutoInit(false);
+ VD->setInvalidDecl();
+ return;
+ }
+
QualType Ty = VD->getType();
if (Ty->isDependentType()) return;
@@ -4779,7 +4830,7 @@ void Sema::ActOnInitializerError(Decl *D) {
}
void Sema::ActOnUninitializedDecl(Decl *RealDecl,
- bool TypeContainsUndeducedAuto) {
+ bool TypeMayContainAuto) {
// If there is no declaration, there was an error parsing it. Just ignore it.
if (RealDecl == 0)
return;
@@ -4788,7 +4839,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
QualType Type = Var->getType();
// C++0x [dcl.spec.auto]p3
- if (TypeContainsUndeducedAuto) {
+ if (TypeMayContainAuto && Type->getContainedAutoType()) {
+ Var->setParsingAutoInit(false);
+
Diag(Var->getLocation(), diag::err_auto_var_requires_init)
<< Var->getDeclName() << Type;
Var->setInvalidDecl();
@@ -4999,6 +5052,41 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
if (DS.isTypeSpecOwned())
Decls.push_back(DS.getRepAsDecl());
+ // C++0x [dcl.spec.auto]p7:
+ // If the type deduced for the template parameter U is not the same in each
+ // deduction, the program is ill-formed.
+ // FIXME: When initializer-list support is added, a distinction is needed
+ // between the deduced type U and the deduced type which 'auto' stands for.
+ // auto a = 0, b = { 1, 2, 3 };
+ // is legal because the deduced type U is 'int' in both cases.
+ bool TypeContainsAuto = DS.getTypeSpecType() == DeclSpec::TST_auto;
+ if (TypeContainsAuto && NumDecls > 1) {
+ QualType Deduced;
+ CanQualType DeducedCanon;
+ VarDecl *DeducedDecl = 0;
+ for (unsigned i = 0; i != NumDecls; ++i) {
+ if (VarDecl *D = dyn_cast<VarDecl>(Group[i])) {
+ AutoType *AT = D->getType()->getContainedAutoType();
+ if (AT && AT->isDeduced()) {
+ QualType U = AT->getDeducedType();
+ CanQualType UCanon = Context.getCanonicalType(U);
+ if (Deduced.isNull()) {
+ Deduced = U;
+ DeducedCanon = UCanon;
+ DeducedDecl = D;
+ } else if (DeducedCanon != UCanon) {
+ Diag(DS.getTypeSpecTypeLoc(), diag::err_auto_different_deductions)
+ << Deduced << DeducedDecl->getDeclName()
+ << U << D->getDeclName()
+ << DeducedDecl->getInit()->getSourceRange()
+ << D->getInit()->getSourceRange();
+ break;
+ }
+ }
+ }
+ }
+ }
+
for (unsigned i = 0; i != NumDecls; ++i)
if (Decl *D = Group[i])
Decls.push_back(D);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 2e6c4c8ace..e8abab8476 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/