if (!D)
return Deps;
for (const auto *I : D->specific_attrs<AlignedAttr>()) {
+ if (I->isAlignmentErrorDependent())
+ Deps |= ExprDependence::Error;
if (I->isAlignmentDependent())
- return Deps | ExprDependence::ValueInstantiation;
+ Deps |= ExprDependence::ValueInstantiation;
}
return Deps;
}
const AttrVec &V = getAttrs();
ASTContext &Ctx = getASTContext();
specific_attr_iterator<AlignedAttr> I(V.begin()), E(V.end());
- for (; I != E; ++I)
- Align = std::max(Align, I->getAlignment(Ctx));
+ for (; I != E; ++I) {
+ if (!I->isAlignmentErrorDependent())
+ Align = std::max(Align, I->getAlignment(Ctx));
+ }
return Align;
}
void test(int x) {
foo.abc;
foo->func(x);
-}
\ No newline at end of file
+}
+
+// CHECK: |-AlignedAttr {{.*}} alignas
+// CHECK-NEXT:| `-RecoveryExpr {{.*}} contains-errors
+// CHECK-NEXT:| `-UnresolvedLookupExpr {{.*}} 'invalid'
+struct alignas(invalid()) Aligned {};
--- /dev/null
+// RUN: %clang_cc1 -frecovery-ast -verify %s
+// RUN: %clang_cc1 -verify %s
+
+struct alignas(invalid()) Foo {}; // expected-error {{use of undeclared identifier}}
+
+constexpr int k = alignof(Foo);
void writeAccessors(raw_ostream &OS) const override {
OS << " bool is" << getUpperName() << "Dependent() const;\n";
+ OS << " bool is" << getUpperName() << "ErrorDependent() const;\n";
OS << " unsigned get" << getUpperName() << "(ASTContext &Ctx) const;\n";
<< "Type->getType()->isDependentType();\n";
OS << "}\n";
+ OS << "bool " << getAttrName() << "Attr::is" << getUpperName()
+ << "ErrorDependent() const {\n";
+ OS << " if (is" << getLowerName() << "Expr)\n";
+ OS << " return " << getLowerName() << "Expr && " << getLowerName()
+ << "Expr->containsErrors();\n";
+ OS << " return " << getLowerName()
+ << "Type->getType()->containsErrors();\n";
+ OS << "}\n";
+
// FIXME: Do not do the calculation here
// FIXME: Handle types correctly
// A null pointer means maximum alignment